Spring4.1新特性——Spring核心部分及其他

目录

Spring4.1新特性——综述

Spring4.1新特性——Spring核心部分及其他

Spring4.1新特性——Spring缓存框架增强

Spring4.1新特性——异步调用和事件机制的异常处理

Spring4.1新特性——数据库集成测试脚本初始化

Spring4.1新特性——Spring MVC增强

Spring4.1新特性——页面自动化测试框架Spring MVC Test HtmlUnit简介

Spring4.1新特性——静态资源处理增强

 

Spring 4.1对核心部分没有很亮点的增强,主要还是一些改进和增强;本文将一一道来。

 

1、DirectFieldAccessor

Spring内部大量使用BeanWrapper进行属性取值赋值(setter/getter),不过到目前为止没有简单的办法去获取对象字段 值;之前都是通过ReflectionUtils获取Field然后进行操作;Spring 4.1提供了DirectFieldAccessor来完成此功能:

Java代码   收藏代码
  1. //嵌套设置/访问对象字段数据  
  2. DirectFieldAccessor accessor = new DirectFieldAccessor(bean);  
  3. //如果嵌套对象为null,字段创建  
  4. accessor.setAutoGrowNestedPaths(true);  
  5. //设置字段值  
  6. accessor.setPropertyValue("bean2.name""zhangsan");  
  7. //读取字段值  
  8. System.out.println(accessor.getPropertyValue("bean2.name"));  

在Spring MVC中也可以通过如下方式给对象字段绑定数据:

Java代码   收藏代码
  1. @RequestMapping("/directField")  
  2. public String directFieldInject(MyUser user) {  
  3.     System.out.println(user);  
  4.     return user.toString();  
  5. }  
  6.   
  7. @InitBinder  
  8. public void initBinder(DataBinder dataBinder) {  
  9.     dataBinder.initDirectFieldAccess();//直接字段访问 必须加这句才可以  
  10. }  

 

2、Yaml支持

YAML类似于JSON,做配置文件还是不错的,需要添加org.yaml.snakeyaml依赖。目前支持把YAML文本转换成Map和Properties:

yaml.txt

Java代码   收藏代码
  1. env:  
  2.     one:  
  3.         name: zhangsan  
  4.   
  5.     two:  
  6.         -   a: 1  
  7.             b: 2  
  8.         -   c: "3"  
  9.             d: 4  
  10.     three:  

yaml-override.txt

Java代码   收藏代码
  1. env:  
  2.     three: 11  

 

配置文件

Java代码   收藏代码
  1. <bean id="yamlMap" class="org.springframework.beans.factory.config.YamlMapFactoryBean">  
  2.     <property name="resources">  
  3.         <list>  
  4.             <value>classpath:yaml.txt</value>  
  5.             <value>classpath:yaml-override.txt</value>  
  6.         </list>  
  7.     </property>  
  8.     <property name="resolutionMethod" value="FIRST_FOUND"/>  
  9. </bean>  
  10.   
  11. <bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">  
  12.     <property name="resources">  
  13.         <list>  
  14.             <value>classpath:yaml.txt</value>  
  15.             <value>classpath:yaml-override.txt</value>  
  16.         </list>  
  17.     </property>  
  18.     <property name="resolutionMethod" value="FIRST_FOUND"/>  
  19. </bean>  

 

在应用中使用:

Java代码   收藏代码
  1. @Autowired  
  2. private ApplicationContext ctx;  
  3.   
  4. @Autowired  
  5. @Qualifier("yamlProperties")  
  6. private Properties yamlProperties;  
  7. @Test  
  8. public void testYmlMap() {  
  9.     //Map(不能直接注入@Autowired Map)  
  10.     //请参考 Map依赖注入(http://jinnianshilongnian.iteye.com/blog/1989379)  
  11.     System.out.println(this.yamlMap);  
  12.     Map<String, Object> yamlMap = ctx.getBean("yamlMap", Map.class);  
  13.     //需要snakeyaml 该功能是从spring-boot引入的  
  14.     Map<String, Object> env = (Map<String, Object>) yamlMap.get("env");  
  15.     Map<String, Object> one = (Map<String, Object>) env.get("one");  
  16.     Assert.assertEquals("zhangsan", one.get("name"));  
  17.   
  18.     List<Map<String, Object>> two = (List) env.get("two");  
  19.     Assert.assertEquals(1, two.get(0).get("a"));  
  20.     Assert.assertEquals("3", two.get(1).get("c"));  
  21.   
  22.     Assert.assertEquals(null, env.get("three"));  
  23.   
  24.   
  25.     //Properties  
  26.     Assert.assertEquals("zhangsan", yamlProperties.getProperty("env.one.name"));  
  27.     //getProperty如果返回的数据时非String的则返回null  
  28.     Assert.assertEquals(1, yamlProperties.get("env.two[0].a"));  
  29.     Assert.assertEquals("3", yamlProperties.getProperty("env.two[1].c"));  
  30.     Assert.assertEquals("", yamlProperties.getProperty("env.three"));  
  31.   
  32.   
  33.     //spring.profiles  
  34.     //http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config-yaml  
  35. }  

 

该特性是从Spring Boot引入,可以直接参考其文档

 

此处需要注意不能:

Java代码   收藏代码
  1. @Autowired  
  2. @Qualifier("yamlMap")  
  3. private Map<String, Object> yamlMap;  

原因请参考 Map依赖注入(http://jinnianshilongnian.iteye.com/blog/1989379)。

 

3、SmartInitializingSingleton

所有非lazy单例Bean实例化完成后的回调方法:

Java代码   收藏代码
  1. public class MySmartInitializingSingleton implements SmartInitializingSingleton {  
  2.     //所有非lazy单例Bean实例化完成后,会调用该方法  
  3.     @Override  
  4.     public void afterSingletonsInstantiated() {  
  5.         System.out.println("单例Bean实例化完成了");  
  6.     }  
  7. }  

  

4、Base64Utils

其会自动根据反射来决定是使用Java 8 的 java.util.Base64还是Apache Commons Codec的org.apache.commons.codec.binary.Base64。

Java代码   收藏代码
  1. @Test  
  2. public void test() {  
  3.     //需要Java 8  或 Apache Commons Codec  
  4.     String str = "123";  
  5.     String str2 = new String(Base64Utils.decodeFromString(Base64Utils.encodeToString(str.getBytes())));  
  6.     Assert.assertEquals(str, str2);  
  7. }  

 

5、SpEL编译模式

SpEL支持把解释型的SpEL转换为字节码进行编译模式下执行:

Java代码   收藏代码
  1. @Test  
  2. public void test() {  
  3.     SpelParserConfiguration configuration =  
  4.             new SpelParserConfiguration(SpelCompilerMode.MIXED, getClass().getClassLoader());  
  5.     SpelExpressionParser parser = new SpelExpressionParser(configuration);  
  6.   
  7.     SpelExpression expression = parser.parseRaw("new String('haha')");  
  8.     Assert.assertEquals("haha", expression.getValue());  
  9.   
  10.     //人工编译  
  11.     //或者使用expression.compileExpression();  
  12.     SpelCompiler spelCompiler = SpelCompiler.getCompiler(getClass().getClassLoader());  
  13.     CompiledExpression compiledExpression = spelCompiler.compile((SpelNodeImpl) expression.getAST());  
  14.     Assert.assertEquals("haha", compiledExpression.getValue(nullnull));  
  15. }  

 

SpelCompilerMode.MIXED指定了是混合模式,其在解释型和编译型之间转换, 其编译规则是这样的:

Java代码   收藏代码
  1. private void checkCompile(ExpressionState expressionState) {  
  2.     this.interpretedCount++;  
  3.     SpelCompilerMode compilerMode = expressionState.getConfiguration().getCompilerMode();  
  4.     if (compilerMode != SpelCompilerMode.OFF) {  
  5.         if (compilerMode == SpelCompilerMode.IMMEDIATE) {//如果立即编译,则直接编译  
  6.             if (this.interpretedCount > 1) {//只有当解释的次数大于1时才编译  
  7.                 compileExpression();  
  8.             }  
  9.         }  
  10.         else {  
  11.             // compilerMode = SpelCompilerMode.MIXED  
  12.             if (this.interpretedCount > INTERPRETED_COUNT_THRESHOLD) {//混合模式下,需要解释次数达到阀值(默认100)才会编译  
  13.                 compileExpression();  
  14.             }  
  15.         }  
  16.     }  
  17. }  

 

默认情况下,编译模式是禁用的,想要全局开启可以通过配置classpath:spring.properties配置文件,然后 SpelParserConfiguration会在类加载时读取spring.expression.compiler.mode属性来配置:

Java代码   收藏代码
  1. private static final SpelCompilerMode defaultCompilerMode;  
  2.   
  3. static {  
  4.     String compilerMode = SpringProperties.getProperty("spring.expression.compiler.mode");  
  5.     defaultCompilerMode = (compilerMode != null ?  
  6.             SpelCompilerMode.valueOf(compilerMode.toUpperCase()) : SpelCompilerMode.OFF);  
  7. }  

 

5、BackOff退避算法实现

在如连接网络的应用中,网络是不稳定的有时候会连接断开,因此为了保证断开重连接;还有如系统之间互联,相互之间发生消息,如果某个服务器因为不确定因此连接不上,也需要断开重连;则需要一定的规则;常见的规则有:

1、按照固定时间间隔重试,比如100毫秒;这种方式在网络不稳定时重连可能造成某一时间点流量同时发送,阻塞网络;或者造成发送一些无意义的请求;

2、按照指数时间间隔重试,比如刚开始100毫秒,下一次200毫秒等;比如支付宝和第三方集成时就是类似方式。

 

固定时间间隔重试:

Java代码   收藏代码
  1. @Test  
  2. public void testFixedBackOff() {  
  3.     long interval = 100;  
  4.     long maxAttempts = 10;  
  5.     BackOff backOff = new FixedBackOff(interval, maxAttempts);  
  6.     BackOffExecution execution = backOff.start();  
  7.   
  8.     for(int i = 1; i <= 10; i++) {  
  9.         //每次重试时间是100毫秒  
  10.         System.out.println(execution.nextBackOff());  
  11.     }  
  12.     Assert.assertEquals(BackOffExecution.STOP, execution.nextBackOff());  
  13. }  

interval是重试间隔,maxAttempts是最大重试次数,如果重试到了maxAttempts,则execution.nextBackOff()=BackOffExecution.STOP。

 

指数时间间隔重试:

Java代码   收藏代码
  1. @Test  
  2. public void testExponentialBackOff() {  
  3.     long initialInterval = 100;//初始间隔  
  4.     long maxInterval = 5 * 1000L;//最大间隔  
  5.     long maxElapsedTime = 50 * 1000L;//最大时间间隔  
  6.     double multiplier = 1.5;//递增倍数(即下次间隔是上次的多少倍)  
  7.     ExponentialBackOff backOff = new ExponentialBackOff(initialInterval, multiplier);  
  8.     backOff.setMaxInterval(maxInterval);  
  9.     //currentElapsedTime = interval1 + interval2 + ... + intervalN;  
  10.     backOff.setMaxElapsedTime(maxElapsedTime);  
  11.   
  12.     BackOffExecution execution = backOff.start();  
  13.   
  14.     for(int i = 1; i <= 18; i++) {  
  15.         System.out.println(execution.nextBackOff());  
  16.     }  
  17.     Assert.assertEquals(BackOffExecution.STOP, execution.nextBackOff());  
  18. }  

initialInterval是初始重试间隔,maxInterval是最大的重试间隔, multiplier是递增倍数,maxElapsedTime是重试的最大时长。

 

Spring4新特性

Spring4新特性——泛型限定式依赖注入

Spring4新特性——核心容器的其他改进

Spring4新特性——Web开发的增强

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC 

Spring4新特性——Groovy Bean定义DSL

Spring4新特性——更好的Java泛型操作API 

Spring4新特性——JSR310日期API的支持

Spring4新特性——注解、脚本、任务、MVC等其他特性改进 

 

源码下载

https://github.com/zhangkaitao/spring4-1-showcase/tree/master/spring4.1-others

https://github.com/zhangkaitao/spring4-1-showcase/tree/master/spring4.1-mvc

你可能感兴趣的:(Spring4.1新特性——Spring核心部分及其他)