用Riggrep进行快速搜索

为什么要学习riggrep? Riggrep快 天下武功,唯快不破 Riggrep聪明 默认会排除 .gitignore/.ignore/.rgignore 文件下的配置和隐藏文件、二进制文件 安装 brew install ripgrep 使用说明 样例所有操作使用 study-sample 仓库,里面是常用语言的入门学习资源,操作文档结构如下: tree ~/github/study-sample /Users/tomyli/github/study-sample |-- LearnBash.sh |-- LearnJava.java |-- README.md |-- commonlisp.lisp |-- learn-emacs-lisp.el |-- learn.nix |-- learnc.c |-- learnclojure.clj |-- learngo.go |-- learnlua.lua |-- learnpython.py |-- learnrust.rs `-- markdown.md 0 directories, 13 files 基本使用 遍历查询 ~/github/study-sample/ 下所有包含 TODO say hello 字符串的结果 rg 'TODO say hello' ~/github/study-sample/ /Users/tomyli/github/study-sample/learnc.c:/* TODO say hello */ /Users/tomyli/github/study-sample/commonlisp.lisp:;; TODO say hello /Users/tomyli/github/study-sample/learnclojure.clj:;; TODO say hello /Users/tomyli/github/study-sample/learn-emacs-lisp.el:;; TODO say hello /Users/tomyli/github/study-sample/LearnBash.sh:# TODO say hello /Users/tomyli/github/study-sample/LearnJava.java: // TODO say hello /Users/tomyli/github/study-sample/learnrust.rs:// TODO say hello 查询到的结果以 文件 维度进行展示,使用 分号 进行分割,分号前为文件路径,分号后为查询匹配到的内容 ...

2022-08-30 ·  (🌟Updated: 2022-10-09) · 3 min · 552 words · tomyli

Spring的RedisTemplate如何与Lettuce进行交互的

问题 SpringWebFlux项目,使用的Redis客户端是Lettuce(基于异步),在Spring中封装了两种操作Redis的模板 RedisTemplate 与 ReactiveRedisTemplate ,正常情况下,异步编程要使用 ReactiveRedisTemplate ,那么可以在项目中使用 RedisTemplate 进行redis的操作吗?为什么? 答案 可以使用 RedisTemplate 在异步代码中进行操作 @Autowried private StringRedisTemplate redisTemplate; String value = redisTemplate.opsForValue().get(key); 追根溯源 先来明确一下应用与Redis的交互流程 Redis交互流程 获取连接 执行命令 返回结果 源码追踪 String value = redisTemplate.opsForValue().get(key); 以下以redis的get命令为例进行解析,get方法是通过 RedisTemplate 的 ValueOperations 属性进行处理的,因为 ValueOperations 是一个接口,要从其实现类 DefaultValueOperations 的get方法进行解析,直接上图 Figure 1: 整体流程图 关键点解析 第1-5步只是为了获取Redis连接 getConnection是为了获取具体的底层redis命令,项目使用Lettuce且为String操作,此处获取的连接为 LettuceStringCommands 第6步是命令执行触发点 它调用了执行DefaultValueOperations.execute(ValueDeserializingRedisCallback)方法调用时方法参数ValueDeserializingRedisCallback的实现方法inRedis,由此转入到真正的命令执行阶段 第9步获取API LettuceConnection获取的是通过调用StatefulConnection.async()方法获取的异步API 第12步进行返回处理 LettuceConnection的doInvoke方法进行了LettuceInvoker的返回处理,在里面看到的是调用了feture.get()方法使用等待的方式来实现了异步转同步的调用 获取连接阶段与执行命令阶段图示 更近一步,可以把 获取连接阶段 与 执行命令阶段 分开来,看图更加清晰 ...

2022-06-01 ·  (🌟Updated: 2022-06-06) · 1 min · 70 words · tomyli

Springwebflux源码学习-服务启动流程

学习目标 理解WebFlux核心组件HttpHandler、WebHandler的创建过程 理解DispatcherHandler如何映射请求url及参数的过程 理解Netty服务的主要启动节点 此次学习的Spring boot版本为2.6.6,对应的Spring webflux版本为5.3.18 入口 Springboot工程入口方法为 SpringApplication.run() ,从此方法开始进行分析。 public static void main(String[] args) { SpringApplication.run(Main.class, args); } 决定启动的web应用类型 整个服务的web应用类型是在构造 SpringApplication 类时进行确定的,具体代码如下: this.webApplicationType = WebApplicationType.deduceFromClasspath(); 判断应用类型的逻辑 org.springframework.web.reactive.DispatcherHandler存在 org.springframework.web.servlet.DispatcherServlet不存在 org.glassfish.jersey.servlet.ServletContainer不存在 即确认webApplicationType为 Reactive if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } 创建具体的ApplicationContext 根据webApplicationType(Reactive)确定创建的ApplicationContext为AnnotationConfigReactiveWebServerApplicationContext,此Context支持 @Component 和 JSR-330规范中 @Inject 形式的依赖注解 SpringAplication.createApplicationContext() switch (webApplicationType) { case SERVLET: return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext(); default: return new AnnotationConfigApplicationContext(); } 最主要的ApplicationContext.refresh()方法 refresh的Refresh阶段 刷新操作是在 AbstractApplicationContext 类的refresh方法中进行,在调用invokeBeanFactoryPostProcessors方法时会有对controller注解的扫描与处理 ...

2022-05-24 ·  (🌟Updated: 2022-05-30) · 2 min · 351 words · tomyli

开发中会遇到的Maven问题解惑

多模块系统版本控制问题 在开发想保持项目下的所有子模块版本一致,可以使用${rversion}变量 配置父pom <groupId>cn.imcompany</groupId> <artifactId>big-parent</artifactId> <version>${revision}</version> <packaging>pom</packaging> <modules> <module>big-web</module> </modules> <properties> <revision>1.0.0</revision> </properties> 子模块配置 <parent> <groupId>cn.imcompany</groupId> <artifactId>big-parent</artifactId> <version>${revision}</version> </parent> <artifactId>big-web</artifactId> 修改版本方式 直接修改revision变量的值 使用 mvn clean package -Drevision=1.1.0 进行配置 使用revision后Deploy操作不显示正确版本问题 需要配合 Flatten Maven Plugin 即可解决,父pom中需要增加以下配置: <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>flatten-maven-plugin</artifactId> <version>1.2.2</version> <configuration> <updatePomFile>true</updatePomFile> </configuration> <executions> <execution> <id>flatten</id> <phase>process-resources</phase> <goals> <goal>flatten</goal> </goals> </execution> <execution> <id>flatten.clean</id> <phase>clean</phase> <goals> <goal>clean</goal> </goals> </execution> </executions> </plugin> </plugins> </build> 配置指定项目不发布到远程仓库 在新版本的deploy插件已经支持配置,配置skip变量即可 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> <version>3.0.0-M2</version> <configuration> <skip>true</skip> </configuration> </plugin> Reference Maven: POM files without a version in it? - SoftwareEntwicklung Beratung Schulung

2022-04-07 ·  (🌟Updated: 2022-04-08) · 1 min · 85 words · tomyli

Linux代码结构学习

Linux代码结构 准备学习Linux,看源码是少不了的,先对Linux源码有个大体认识(基于linux4.13) 代码主要文件解析 Makefile 这是整个源码的Makefile,里面定义了一系列的变量和规则,比如默认的gcc编译flag。 Documentation/ 项目文档,里面包含了很多关于配置内核、与ramdisk运行等有用的信息。这里面没有不同配置项的帮助信息,这些信息可以在相关子目录的 Kconfig 文件中查看。 arch/ 体系结构相关代码都在这里,还有一部分在include/arch-generic中。每个体系结构在这个目录下都有一个子目录。比如基于x86体系的代码都在 arch/x86 下。另外,这个目录下还包含低级别的内存管理,中断处理,早期初始化,汇编例程等信息。 crypto/ 内核使用的加密API代码。 drivers/ 所有设备相关的信息都在这个目录下。包括视频设备,网卡设备,低级别的SCSI设备。比如网络设备一般是在 drivers/net 目录下。 fs/ 通用的文件系统与其它类型的文件系统代码都在这里。现在的操作系统的根文件系统一般为ext4格式,它的代码在 fs/ext4 下 include/ 所有.c文件中包含的头文件都定义在这个目录下。 init/ 这个目录包含了内核启动的入口文件 main.c ,版本信息文件 version.c 和早期用户空间相关的代码,早期空间代码提供内核出现时的功能,它不需要在内核中进行运行。 ipc/ 进程间通信相关代码,包含共享内存,信号量等信息。 kernel/ 内核级别代码,上层的系统调用代码在这里,还有关于 printk() 代码,调度,信号量处理的代码。 lib/ 内核所有使用的库都在这里。常见的字符串运算,调试库,命令行解析代码等。 mm/ 高级别的内存管理代码。虚拟内存是通过这些库与低级别的体系结构代码(在 arch//mm )一同实现的。这里完成了早期引导内存管理,涉及文件的内存映射,页缓存的管理,内存分配和RAM中页面的交换。 net/ 高级别的网络代码。与低级别的网络进行发包与收包交互。*net/core* 中包含其它网络协议使用的核心代码。net子目录就是特定的网络协议实现。 scripts/ 这里面包含构建内核的脚本文件。 security/ 不同Linux的安全模型代码。 sound/ 声卡及相关代码在这里。 usr/ 该目录包含构建根文件系统映射的cpio格式的文档代码,该文档用于早期的用户空间。

2022-04-06 ·  (🌟Updated: 2022-04-06) · 1 min · 54 words · tomyli

记一次SpringWebflux框架下堆外OOM排查经历

症状 生产环境业务页面打不开,看错误日志是 OutOfDirectMemoryError (OOM)了,详情报错信息如下: 2022-03-21 06:00:00.541 [,] [tafprx-asyrecv_9] ERROR r.c.p.Operators - [error,314] - Operator called default onErrorDropped java.lang.OutOfMemoryError: Direct buffer memory at java.base/java.nio.Bits.reserveMemory(Bits.java:175) at java.base/java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:118) at java.base/java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:317) at io.netty.buffer.PoolArena$DirectArena.allocateDirect(PoolArena.java:632) at io.netty.buffer.PoolArena$DirectArena.newChunk(PoolArena.java:607) at io.netty.buffer.PoolArena.allocateNormal(PoolArena.java:202) at io.netty.buffer.PoolArena.tcacheAllocateSmall(PoolArena.java:172) at io.netty.buffer.PoolArena.allocate(PoolArena.java:134) at io.netty.buffer.PoolArena.allocate(PoolArena.java:126) at io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:395) at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187) at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:178) at io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:115) at org.springframework.core.io.buffer.NettyDataBufferFactory.allocateBuffer(NettyDataBufferFactory.java:71) at org.springframework.core.io.buffer.NettyDataBufferFactory.allocateBuffer(NettyDataBufferFactory.java:39) at org.springframework.http.codec.json.AbstractJackson2Encoder.encodeValue(AbstractJackson2Encoder.java:236) at org.springframework.http.codec.json.AbstractJackson2Encoder.lambda$encode$0(AbstractJackson2Encoder.java:150) at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:113) at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815) at reactor.core.publisher.MonoCompletionStage.lambda$subscribe$0(MonoCompletionStage.java:82) at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859) at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:883) at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2251) at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:143) at reactor.core.publisher.MonoCompletionStage.subscribe(MonoCompletionStage.java:57) at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64) at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157) at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815) at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249) at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:199) at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:199) at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.complete(MonoIgnoreThen.java:284) at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onNext(MonoIgnoreThen.java:187) at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1815) at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:151) 根据报错的堆栈,找到 AbstractJackson2Encoder:236 行,调试发现框架使用的buffer在最后都进行了释放,看着没问题。 ...

2022-03-31 ·  (🌟Updated: 2022-04-13) · 3 min · 615 words · tomyli

那些提高效率MAC软件(全程免费)

NTFS 支持MAC电脑读取NTFS格式文件 eul 监控MAC运行状态的工具 uPic 文件与图片云端上传工具 Sequel-Ace MAC上数据库管理工具,支持Mysql与MariaDB CopyQ MAC上免费的剪切板工具 Bob MAC上翻译软件 LuLu MAC上强大的防火墙 hidden MAC菜单栏图标隐藏工具 Brooklyn MAC上炫酷的屏保程序 Gifski 把Video转换成Gif BackgroundMusic 音频工具,可以为每个app设定音量值 pixel-picker MAC取色软件 Itsycal MAC日历软件 SwitchHosts 快速切换机器Host,开发必备 hammerspoon 使用Lua脚本来控制电脑 squirrel 鼠鬚管,无敌的输入法 iTerm2 MAC上的终端模拟器 keycastr MAC上按键显示工具 TODO pot-app/pot-desktop: 🌈一个跨平台的划词翻译和OCR软件 | A cross-platform software for text translation and recognition. TODO jordanbaird/Ice: Powerful menu bar manager for macOS TODO qarmin/czkawka: Multi functional app to find duplicates, empty folders, similar images etc. TODO FelixKratz/SketchyBar: A highly customizable macOS status bar replacement TODO nikitabobko/AeroSpace: AeroSpace is an i3-like tiling window manager for macOS TODO Alex313031/thorium: Chromium fork named after radioactive element No. 90. Windows and MacOS/Raspi/Android/Special builds are in different repositories, links are towards the top of the README.md. TODO odlp/bluesnooze: Sleeping Mac = Bluetooth off TODO nonwill/GoldenDict-OCR: GoldenDict++:内置大量的官方版本问题的修正;先期添加了一个简单的插件机制,并基于该机制接入了多个 OCR 划词 和 音频播放 引擎;后期在增强易用性的基础上为提高查询效率、减少运行时 CPU 及 内存 占用、降低代码维护难度,完全重构了所有的实现;将来的目标是将功能扩展和词典格式处理抽象为完整的插件实现,以进一步增强应用的扩展性和可维护性。 TODO Homebrew/homebrew-bundle: 📦 Bundler for non-Ruby dependencies from Homebrew, Homebrew Cask and the Mac App Store. ungoogled-software/ungoogled-chromium: Google Chromium, sans integration with Google 生活中去google化 ...

2021-10-25 ·  (🌟Updated: 2024-04-28) · 1 min · 180 words · tomyli

让好代码生生不息-更好的使用String

开发中常用的String操作 开发中经常用到的操作有: 格式化/日志格式化 字符串判断 字符串处理,常见的如处理字符串的第一个/最后一个字符 String.format String.format()是一个格式化的方法,使用%为前缀来表示要格式化的内容占位,一般的使用方法为: String.format("test result is %s", "success"); 但是当要格式化的占位符与参数个数不同时会发生什么呢? 占位符个数与参数个数相同 如上代码,可以正常进行输出: test result is success 占位符个数少于参数个数 String.format("test result is %s", "success", "other"); 可以正常打印,输出结果为: test result is success 占位符个数多于参数个数 String.format("test result is %s %s %s", "success", "other"); 抛出了异常java.util.MissingFormatArgumentException: Format specifier ‘%s’ 问题总结 为什么占位符数少于参数个数可以正常执行,而多于参数个数却报了异常?看JAVADOC发现,如果占位符个数少于参数个数,则多余的参数被忽略,如果多于参数个数,则在进行解析时会判断待处理占位符位置与参数个数,主要代码逻辑如下: if (args != null && lasto > args.length - 1) throw new MissingFormatArgumentException(fs.toString()); 所以在使用String.format方法 切记 要参数个数多于待解析占位符的个数,这种问题常因为Copy操作后,处理了部分参数而忘记对应处理占位符 替换方案 目前看到很多的老代码打印日志时大都使用String.format(),可以改成slf4j的{} 还可以使用Apache common utils中的StringUtils.joinWith()或者Google guava的Joiner连接器 Apache commons utils-StringUtils 在StringUtils中有一个isNumeric方法,用来判断字符串是不是数字,那下面的代码会返回什么呢? ...

2021-08-23 ·  (🌟Updated: 2021-09-06) · 2 min · 221 words · tomyli

让好代码生生不息-更好的对待NULL

什么样的代码是好代码 易读的代码,行云流水的代码 JAVA中的NULL处理 众所周知,在Java代码中总是少不了一堆的判null逻辑,在代码bug中,NullPointerException出镜率也是非常高的,尤其是现在的主流分布式架构,一个web接口要调用后端的N个RPC服务来实现功能,基于防御编程的思想,判null就更重要了 在处理NULL时怎么做更好 IDE 既然无法避免null,IDE就给程序员增加了可以快速判断空的功能,比如在IDEA中,可以使用Postfix功能,在对象上o使用.nn来快速输入if(o != null) {} JAVA基础类库 近期的JDK版本也针对null判断增加了一些实用的方法 Objects类 JAVA8在Objects工具提供了isNull()和nonNull()方法,JAVA9又增加了requireNonNullElse()和requireNonNullElseGet()来给待处理对象增加设置默认值的方法 知名三方库 Apache common utils中提供了非常多的判空工具类,如针对String操作的StringUtils类和针对集合操作的CollectionUtils、MapUtils、ListUtils、SetUtils,这几个类都有一些典型的方法来进行判空处理,通用的方法如下: StringUtils isEmpty()/isNotEmpty() 判断String是否为空/不空 isBlank()/isNoneBlank() 判断String是否为空/不空,这类方法还会判断实际值是否为空串 defaultString() 此方法允许在String为null时为返回空串 defaultIfBlank()/defaultIfEmpty() 此方法允许在String为空串或null时设置一个默认值 集合类Utils isEmpty()/isNotEmpty() 判断集合是否为空/不空 emptyIfNull() 这是一个很有用的方法,当传入对象为空时则返回设置的默认对象,可以很好的根治if处理null的问题,下面两段代码演示一下 正常情况下有if判断 List<Object> values = rpcClient.getFromRpcList(); if(CollectionUtils.isNotEmpty(values)) { return values .forEach(System.out::println); } 使用emptyIfNull方法 return CollectionUtils.emptyIfNull(rpcClient.getFromRpcList()) .forEach(System.out::println); 这样保证了代码编写的连贯性,爽! 此方法在ListUtis、MapUtils、SetUtils中也有提供 defaultIfNull() 此方法允许在集合为null时设置一个默认值,也是可以链式操作 优秀的Coder 在编写通用方法时,对于有null返回的情况可以使用返回默认值来代替null 不返回空,以空对象来代替 比如返回一个new Object() ...

2021-07-17 ·  (🌟Updated: 2021-07-23) · 1 min · 60 words · tomyli

JAVA中获取调用栈帧的最优方式

前言 近期在做日志优化,需要记录业务日志,日志内容包括业务的请求、响应信息。当然还应该有具体的调用方法位置、日志的所在的方法等通用信息。 解决方案 一般情况下,在程序有异常信息时可以打印出整个调用堆栈信息,但是现在需要的是正常调用下来获取到当前方法的调用帧。 JAVA9之前 Thread.dumpStack() 这个可以打印出当前的堆栈错误信息,本质上是new一个Exception,调用了printStackTrace()方法,但是这个方法只建议用于调试。 public class StackTraceExample1 { public static void main(String[] args) { one(); } public static void one() { two(); } private static void two() { three(); } private static void three() { Thread.dumpStack(); } } 执行后输出如下: java.lang.Exception: Stack trace at java.base/java.lang.Thread.dumpStack(Thread.java:1379) at cn.imcompany.stack.StackTraceExample1.three(StackTraceExample1.java:25) at cn.imcompany.stack.StackTraceExample1.two(StackTraceExample1.java:21) at cn.imcompany.stack.StackTraceExample1.one(StackTraceExample1.java:17) at cn.imcompany.stack.StackTraceExample1.main(StackTraceExample1.java:13) 直接以异常的方式显示出来了。 ...

2021-04-20 ·  (🌟Updated: 2021-04-21) · 1 min · 154 words · tomyli