✍前言
你好,我是YourBatman。
北京时间2020-10-27,Spring Framework 5.3.0版本正式发布。说明:Spring Framework 5.2.0.RELEASE的发布时间是2019-09哈。
注意:5.3.0版本号没有.RELEASE后缀哟,至于原因我前面写的这篇文章给了你完整解释哈:Spring改变版本号命名规则:此举对非英语国家很友好
在Spring Boot大行其道的今天,似乎Spring Framework的版本升级受到的关注越来越少了,殊不知对Spring Boot有多了解始于对Spring Framework的了解程度,因此保持对后者的一定关注会是很有意义的。
✍正文
Spring Framework 5.3.x是5.x版本的最后一个功能分支,此系列最低要求JDK8,且支持到了JDK15,以及还会扩展支持到明年的JDK17。
另外,对于刚刚发布的Spring Boot 2.4.0以及明年即将发布的Spring Boot 2.5.0均会基于此功能分支构建。官方建议:现在处在5.x / 4.x的用户均升级到Spring Framework 5.3.x版本上来,因为它将是一个面向未来的分支,并且提供长期维护(持续到2024年,持续时间可谓是最长的)。它是寿命同样长的4.3.x分支系列产品的后继产品,但此系列的寿命将在2020-12结束不再维护(毕竟真的很老了嘛)。
说明:Spring团队对于一般的功能分支,提供2-3年的维护,而对于4.3/5.3均提供了长达4年多的维护时间,这得益于它们是主版本号的最后一个功能分支
新特性/功能升级
诚如各位所知,Spring Framework是很多模块技术的总和,因此在新特性/功能增强方面我们分模块进行表述。
通用升级
1、ASM升级到9.0
ASM 9.0版本可是非常新的版本,如下图:
<dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>9.0</version> </dependency>
Spring使用了最新版的ASM包,可谓紧跟潮流啊。
需要清楚的是Spring它并没有引入这个jar哦,而是fork了一份源代码放在spring-core里(报名改了,但内容基本没没变),这样做更加高效:
至于ASM 9.0的新功能增强,有兴趣可进入其官网阅读即可,直达电梯:https://asm.ow2.io
2、支持RxJava 3.0,过期对RxJava 1.0支持
这些都是通过适配器ReactiveAdapterRegistry实现的,它支持了:Reactor、RxJava 2/3、CompletableFuture、Java 9+的Flow.Publisher等等,并且以把对RxJava 1.0的支持标记为过期,预计下个功能分支会移除。
<dependency> <groupId>io.reactivex.rxjava3</groupId> <artifactId>rxjava</artifactId> <version>3.0.7</version> </dependency>
可以看到RxJava 3.X也是非常非常新的,这点Spring做得不可为不好。
RxJava 3.X旨在用来替代RxJava 2,因此存在少量的二进制不兼容(简单说:不向下兼容,但改动也没那么的大),另外就是提供了基于Java 8 lambda友好的API,更加的普适了。
通过spring.spel.ignore属性可禁用SpEL模块
如果你的应用程序没使用/不依赖于SpEL,那么可以通过属性spring.spel.ignore来忽略掉它。SpEL是spring-expression是这个模块提供支持的,其实很多时候我们并不需要使用到SpEL表达式(特别是在现在的注解驱动使用中),那么我们就可以通过设置此属性值来禁用掉此模块功能,为系统减负(降低启动时间,节约内存)。
SpEL模块主要在两个地方被使用,均可通过此属性配置来关闭:
// 上下文了支持SpEL表达式,比如@Value里 AbstractApplicationContext: private static final boolean shouldIgnoreSpel = SpringProperties.getFlag("spring.spel.ignore"); protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { ... if (!shouldIgnoreSpel) { beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); } ... } // 支持@EventListener(condition = 'SpEL') EventListenerMethodProcessor: public EventListenerMethodProcessor() { if (shouldIgnoreSpel) { this.evaluator = null; } else { this.evaluator = new EventExpressionEvaluator(); } }
只需要在类路径下的spring.properties文件添加属性spring.spel.ignore = true即可禁用掉SpEL模块的加载。
小贴士:类路径下的spring.properties文件是Spring Framework启动自动就会加载的,详可参见org.springframework.core.SpringProperties学习。
spring-expression模块的初始化动作不轻,Spring提供此属性我认为是在为云原生做不懈努力。但是,但是,但是,请你务必在确定没有使用SpEL的情况下才去关闭此开关,否则弄出线上bug背个锅就划不来了。当然喽,最好是能有个熟悉Spring的人hold住才去改它~
核心容器
此模块最大的升级就是对Cron表达式进行了提升。
对@Scheduled升级:CronExpression
在Spring场景下,Cron表达式只能通过@Scheduled注解去实现,而在5.3.0版本引入了一个新的API:CronExpression用于解析Cron表达式(编程式)。
CronExpression完全替代了CronSequenceGenerator(@Scheduled基于它实现)这个老的API,是因为后者基于java.util.Calendar实现的从而存在已知的一些问题,并且还没法修复(毕竟是JDK的锅嘛,Spirng团队也无能为力),因此新的CronExpression就使用了java.time解决了问题并且还提供了新的好用功能。
CronExpression的使用
在之前我们想要一个Cron表达式都是借助@Scheduled来完成,现在可以使用CronExpression轻松编程式来做喽:
public static void main(String[] args) { CronExpression expression = CronExpression.parse("10 * * * * *"); LocalDateTime start = LocalDateTime.now(); for (int i = 0; i < 3; i++) { start = expression.next(start); System.out.println(start); } }
运行程序,控制台输出:
2020-11-15T11:28:10 2020-11-15T11:29:10 2020-11-15T11:30:10
该Cron表达式表示:每分钟的第10秒钟触发,因此结果是符合预期的。该parse方法入参是Cron表达式的字符串,该字符串带有六个以空格分隔的时间和日期字段,各部分表示为:
当然啦,还有些 * ?这样的通配符可以使用,具体的这里就不做过多介绍了。