认识SpEL表达式
前言
最近项目接入苞米豆的
lock4j用于分布式的锁控制,良好的控制在多台服务器下请求分流导致的数据重复问题,使用上也比较简单,在需要分布式锁的方法上添加一个@Lock4j注解并添加相应的参数即可,在使用中发现其中有一个属性keys = {"#userId", "#user.sex"},并且支持自定义重写分布式锁键的生成策略。在好奇心的驱使下,查看了默认实现的分布式锁键生成策略是通过SpEL的方式解析参数信息。
最近项目接入苞米豆的
lock4j用于分布式的锁控制,良好的控制在多台服务器下请求分流导致的数据重复问题,使用上也比较简单,在需要分布式锁的方法上添加一个@Lock4j注解并添加相应的参数即可,在使用中发现其中有一个属性keys = {"#userId", "#user.sex"},并且支持自定义重写分布式锁键的生成策略。在好奇心的驱使下,查看了默认实现的分布式锁键生成策略是通过SpEL的方式解析参数信息。
今天在使用mybatis-plus作者苞米豆的另一个项目lock4j用于项目中的分布式锁,解决多实例情况下对接口进行上锁,使得业务上的共享资源在一个时间节点里只会被一个线程执行。
lock4j和mybatis-plus差不多,秉承着人性化使用的初衷,lock4j使用上还是非常简单的,只需要在需要上锁的接口方法上使用@Lock4j进行标记并设置一些简单的超时参数即可。
使用中发现有一个需要上锁的接口是一个私有方法(原本单机情况下,采用ReentrantLock),所以改造时仅仅只是对改接口上添加@Lock4j注解。
今天收到预生产环境测试人员的消息说项目启动失败,看了一下错误是rabbitmq的队列监听抛出找不到该队列,没有道理,逻辑上已经经过了测试环境的测试没有理由犯这么低级的错误。吓得我赶紧看去看了一下预生产环境的apollo配置信息(我们使用的mq厂商随环境的不同可能不同),配置信息也是对的;赶紧再次核对一下错误日志,发启动时创建交换机还有另外的报错:
1 | 2021-04-14 16:58:23.014 [AMQP Connection 192.168.2.16:5672] ERROR o.s.a.r.c.CachingConnectionFactory-Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'type' for exchange 'xxxxx' in vhost '/': received 'topic' but current is 'fanout', class-id=40, method-id=10) |
大概的意思是已经存在该名称为fanout类型交换机不允许改变为topic类型交换机。
使用过SprongBoot打过jar包的都应该知道,目标文件一般都会生成两个文件,一个是以.jar的包,一个是.jar.original文件。那么使用SpringBoot会打出两个包,而.jar.original的作用是什么呢?还有就是java -jar是如何将一个SpringBoot项目启动,之间都进行了那些的操作?
其实.jar.original是maven在SpringBoot重新打包之前的原始jar包,内部只包含了项目的用户类,不包含其他的依赖jar包,生成之后,SpringBoot重新打包之后,最后生成.jar包,内部包含了原始jar包以及其他的引用依赖。以下提及的jar包都是SpringBoot二次加工打的包。
[TOC]
在java的异常体系中Exception异常有两个分支,一个是运行时异常RuntimeException,一个是编译时异常,在Exception下的所有非RuntimeException异常,比如IOException、SQLException等;所有的运行时异常不捕获,编译时异常是一定要捕获,否则编译会报错。@SneakyThrows就是利用了这一机制,将当前方法抛出的异常,包装成RuntimeException,骗过编译器,使得调用点可以不用显示处理异常信息。
[TOC]
泛型实现了参数化类型的概念,使代码可以应用于多种类型,设计的初衷应该是希望类或者方法能够具备最广泛的表达能力。在引入泛型之前,一般都是依赖于Object顶层对象实现类似泛型的功能,但是使用Object有一个缺陷是如果类型转换异常,编译器在编译期无法检测这种异常,只有在字节码的运行时期才会抛出类型转换异常。而JDK 1.5之后引入的泛型,在编译期就会对类型进行检查,使得问题可以及早发现。
[TOC]
过滤器
Filter是通过实现java.servlet.filter接口实现过滤器功能,作用是用于对传入的request和响应的response进行一些处理,比如对请求参数进行校验,或者设置、检验头部信息,再或者对一些非法行为进行校验。由实现的接口可知,过滤器是依赖于servlet容器。所以由于过滤器不依赖于spring容器,它也就无法获取到容器中的对象。
[TOC]
在mybatis中从sql的解析到最后结果集的返回,经过了一系列的内部组件,比如参数处理器parameterHandler,语句处理器StatementHandler,结果集处理器ResultSetHandler等。若开发者需要对SQL执行的某一环节进行一些特定的处理,比如参数类型的转换,数据分页功能,打印执行的SQL语句等都可以通过mybatis的插件机制实现。
[TOC]
因为需要,研究了可以通过InheritableThreadLocal进行父子线程中如何传递本地线程变量,通过阿里开源项目TransmitableThreadLocal进行进行线程池传递本地线程变量(详解可查看以往博客)。在查找资料的过程中无意发现了Dobbo的InternalThreadLocal,其实Dobbo的InternalThreadLocal和netty的FastThreadLocal有异曲同工之妙。之前学netty的时候有了解一点,为了加深一下ThreadLocal种群的了解,使用本博客记录一下。
[TOC]
在Thread中除了有属性threadLocals引用ThreadLocal.ThreadLocalMap,其实还有一个属性,也就是inheritableThreadLocals,threadLocals的作用是保存本地线程变量,而inneritableThreadLocals的作用是传递当前线程本地变量InheritableThreadLocal到子线程的本地变量InheritableThreadLocal中。