记录发现redissonBug并提交修复的历程
背景redis cluster集群模式下3主3从,用redisson,scan命令会漏扫非cluster集群下没有问题,lettuce也没有问题,只有redisson+cluster+scan才有会有问题
发现的历程搞库存重构,存放在redis的库存数据要更改名称,肯定不能用keys命令,keys会阻塞,时间复杂度是O(n)所以用scan,但发现scan总是漏扫数据,用Lettuce就没有问题,所以断定是redisson源码出现问题
找问题的历程分析源码,从scan开始,源码如下
建议debug阅读源码,不然容易混乱本地没有环境建议远程debug,在jvm启动脚本加上-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=16770 用idea连接即可远程debug
分析源码scan原理调用scan会返回一个迭代器,通过迭代器scan会从头扫到尾,直至cursorId=0源码如下
12345678910111213141516171819202122232425262728293031323334353 ...
es踩坑之deleteByQuery
背景由于es增删改操作有延迟,所以在某些业务场景如:先删除,在新增这种db下的场景就不适用于es了(es删除后在新增),毕竟db会有事务保证,所以在es层面只适合用deleteByQuery
代码场景通过canal订阅mysql的数据变动,投递到mq中,mq消费同步至es中,es做deleteByQuery的代码如下
1234567DeleteByQueryRequest request = new DeleteByQueryRequest("你的index");request.types("_doc");BoolQueryBuilder builder = QueryBuilders.boolQuery();builder.filter(QueryBuilders.termQuery("promotionId", promotionId)); // 条件一builder.filter(QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery("sh ...
java实例化的几种方式
直接new调用了构造
通过反射调用了构造
clone没有调用构造,但必须实现Cloneable接口,java通过native方法实现
反序列化没有调用构造,通过调用MethodAccessorGenerator#generateSerializationConstructor生成一个新的构造对象,该构造对象不会调用构造方法
通过Unsafe类的allocateInstance()方法没有调用构造,只分配内存空间
通用枚举
使用场景我们一般用枚举来代表数字或者字符串,避免魔法值的产生。
有时需要根据数字或字符串获取到对应的枚举。
虽然可以在枚举里面写静态方法根据int获取对应的枚举也可以做到,但是你需要在一个枚举写一个方法,如果有N多个枚举则会非常的冗余类似于这段代码
123456789101112131415161718192021222324@Getterpublic enum Condition { ONCE(0, "满"), EACH_TIMES(1, "每满"), LADDERED(2, "阶梯满"); private final int code; private final String name; Condition(int code, String name) { this.code = code; this.name = name; } // 类似于这段代码 public static Condition getTypeByCode(int code) { ...
javaUtil动态代理
动态代理有很多使用的场景,比如
springAOP切入
spring事务、缓存
自定义业务场景等
本文就是一个动态代理util。为了使用起来更加的方便。之后的文章也有可能用得到。
后续用新文章来分析动态代理的原理
本文的使用场景(点我)
代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110import org.springframework.beans.BeanUtils;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;i ...
环境变量
main方法参数使用:java 类名 【参数1】 【参数2】 【参数3】 .。。。
123public static void main(String[] args) { System.out.println(args);}
System.getenv获取系统环境变量同 linux 下 export
System.getProperty获取java程序变量通过 java -Dk=v配置
dubbo-spi
javaSpi
java有spi机制为什么dubbo还要自创一套?
javaSpi没有key value机制,没有顺序之分
javaSpi 如果有多个实现类,只能依次加载,不能精准加载
...等
dubboSPI的特性
可根据指定的key获取SPI实现
可根据@Activate注解进行分类,获取指定的SPI实现
多个实现可排序实现排序接口org.apache.dubbo.common.lang.Prioritized
可包装(静态代理)对原有的spi实现直接编码进行静态的代理,spi的实现类只留一个有参构造,参数为SPI接口的类型即可变为wrapper
可注入对spi的实现类中如果有set方法,且没有DisableInject注解,那么以此方法的第一个参数的类型+名称,再次从dubboSPI容器中寻找对应的实例。并set
spi无实现者的情况下,可自适应实现(一般开发者用不到)方法:getAdaptiveExtension()如果spi配置文件中的配置实现类上有Adaptive注解,则直接用此类。如果没有实现类,但是spi接口中个别方法上有Adaptive注解,并且参数 ...
java-spi
javaSPI机制service provider interface
12345// 通过遍历即可获取到对应的class,那么原理是什么呢?Iterator<ABC> iterator = ServiceLoader.load(ABC.class).iterator();while (iterator.hasNext()) { ABC next = iterator.next();}
原理java规定spi的配置文件都在这个目录META-INF/services/该目录下可以有多个文件,文件的名称必须以class全类名命名。通过ServiceLoader类,读取名字为spi类的全名称的文件内容为多行,一行为一个class的全类名。该class为spi的实现类。
ServiceLoader入口12345678910111213141516171819202122232425262728293031323334353637383940414243public final class ServiceLoader<S> implements ...