先看整体效果,“忽悠”简单的东西,是软件开发的目标之一。请看下图:
左边在application.yml中配置了三个生成器,右边可以直接注入代码中使用。注意,你不需要写任何代码。这个又酸又爽。请看下面的效果:
以上是三个生成器生成的第一个序列号。哦,还不错。学会慢慢分析序列号。大家都很熟悉了。它只不过是一个初始值,一个步长,有时是一个最大值。这只是最基本的信息,其他可以根据需要添加。抽象一个接口很容易,
以下代码:
根据实际情况使用*/String getName();/* *容器中注册的bean名称*/String get bean name();/* *初始值*/long getInitNum();/* *步长*/long get step();/* *获取下一个序列号*/long next num();/* *最大值*/long get maxnum();}剩下的是以下三个问题:
有了接口,自然是基于Redis实现的,这是遇到的第一个问题。您还需要根据配置将bean定义动态注册到容器中,这是第二个问题。自然,下一步就要从配置文件中读取这些配置信息,这是第三个问题。
然后学习主要使用Redis的INCRBY命令实现接口,这是一个原子命令。即使你有多个节点,每个节点同时有多个线程要调用,也是可以的。而当该键不存在时,第一次调用时该键会被设置为0。
这样做的好处是程序不需要考虑键是否存在,直接调用self-increment就可以了。唯一不愉快的是key只会被设置为0。如果初始值不从0开始,真的很难受。最简单的方法是在程序中叠加初始值作为偏移量。
当然还有一种方法,就是主动设置key的初始值。由于并发性,使用SETNX命令是很自然的。这是完全可以的,但是有些人还是觉得心理不安全。然后在应用启动阶段执行命令,这个时候肯定不会有调用。
请看下面的源代码:
/** * 基于雷迪斯的实现* @作者李心洁* @自2019-04-04 */公共类再生器实现sn生成器{ @ Autowired private stringdistemplate stringdistemplate;私有字符串名称;私有字符串beanNameprivate long initNum私长步;私有long maxNum public redinsn generator(String name,String beanName,long initNum,long step,long maxNum){ this。name=名称;这个。bean name=bean name这个。初始化数量=初始化数量;this . step=step this . maxNum=maxNum } @ post构造public void init(){ if(!stringdistemplate。has key(getName()){ string distemplate。价值得运营().setIfAbsent(getName(),string。(getInitNum()))的值;} } @覆盖公共字符串getName(){ return name;} public String get bean name(){ return bean name;} @ Override public long getInitNum(){ return initNum;} @ Override公共long get step(){ return step;} @ Override public long nextNum(){ return string distemplate。值得操作().increment(getName()、get step());} @ Override public long get maxNum(){ return maxNum;}}要动态注册豆定义,
公共接口bean定义注册后处理器扩展了bean factorypostprocessor {/* * * * @ param注册表应用程序上下文使用的豆定义注册表* @ throws org。spring框架。豆子。beans异常出现错误时*/void postprocessbean定义注册表(bean definition registry registry)引发bean异常;}它是一个豆工厂后处理器,
The public interface EnvironmentAware extends Aware {/** * to set the {@code Environment} running this component. */void setEnvironment; } It is a known interface,
private SnGeneInfo[]parseSnGeneInfos(){ String prefix=' sn generator 'string[]生成器=环境。getproperty(前缀。生成器,字符串[]。类);SnGeneInfo[]infos=新SnGeneInfo[生成器。长度];for(int I=0;一。发电机长度;i ) { infos[i]=buildSnGeneInfo(前缀,生成器[I]);}返回信息;}私有SnGeneInfo buildSnGeneInfo(字符串前缀,字符串生成器){返回新的SnGeneInfo(前缀):' generator,environment.getProperty(前缀)。'"发电机"。bean-name ')、environment.getProperty(前缀。"发电机"。init-num 'long.class),environment.getProperty(前缀''"发电机"。step 'long.class)、environment.getProperty(前缀。"发电机"。最大数量,长型。类));}下面是注册豆定义的:
@ Override public void postprocessbean definition registry(bean definition registry registry)抛出beans exception { SnGeneInfo[]gene infos=parseSnGeneInfos();system . out . println(log info(gene infos));for(SnGeneInfo gene info:gene infos){ bean definition builder BDB=bean definition builder . genericbean definition(redisn generator . class);BDB . addconstructorargvalue(gene info . getkeyname());BDB . addconstructorargvalue(gene info . get beanname());BDB . addconstructorargvalue(gene info . getinitnum());BDB . addconstructorargvalue(gene info . get step());BDB . addconstructorargvalue(gene info . get maxnum());registry . registerbean definition(gene info . get beanname()、BDB . getbean definition());于你觉得怎样?当你有机会的时候,
请看下面的效果:
每组中的key,也就是上面的f1/f2/f3,不需要配置,需要时可以直接传入程序。这时候获取下一个序列号的方法需要带一个参数,用来传递这个键。它是基于Redis散列实现的。
根据实际情况使用*/String getName();/* *容器中注册的bean名称*/String get bean name();/* *初始值*/long getInitNum();/* *步长*/long get step();/* *获取下一个序列号*/long nextNum(字符串标识符);/* *最大值*/long get maxnum();}这个时候你也会遇到为hashkey设置初始值的问题。
集团免费提供Java架构学习资料(包括高可用性、高并发、高性能和分布、Jvm性能调优、Spring源代码、MyBatis、
Netty、Redis、Kafka、MySQL、Zookeeper、Tomcat、Docker、Dubbo、Nginx等知识点)合理利用每一分每一秒学习提升自己。
不要用“没时间”来掩饰思想上的懒惰!趁着年轻好好奋斗,以后给自己一个交代!
标题:开箱即用(out-of-box)的Redis序列号生成器,你值得拥有
链接:https://www.52hkw.com/news/rj/62892.html
版权:文章转载自网络,如有侵权,请联系删除!