至于在平时业务编码中处理Spring的事务同步的时候选择哪种方式呢??我觉得两种方式都是ok的,看各位的喜好了(我个人偏爱注解方式,耦合度低很多并且还可以使用事件链,有时候非常好使)
需要提一句:@TransactionalEventListener同@EventListener一样是存在一个加载时机问题的,若你对加载时机有严格要求和把控,建议使用API的方式而非注解方式,避免监听器未被执行而导致逻辑出错~
由于此篇文章出现的类和API大都是Spring4.2开始有的,所以借此机会介绍几个 我认为的 相对比较重要(常用)的Spring4.2的新特性,希望对小伙伴们能有所帮助
Spring4.2新特性(部分)
说明:新特性中有些一看标题就知道什么意思和怎么用的,就不做案例介绍了
1、@Bean能注解在Java8默认方法上了
2、@Import可以引入没任何注解标注的类作为组件了
在这之前,@Import只能导入配置类(注解了@Configuration等的类),现在即使非常普通的javaBean都能被导入进来作为组件了
3、@Configuration配置类上可以使用@Order来按照预期顺序处理了
4、@Resource可以和@Lazy配合使用了(重难点)
之前只能@Autowired和@Lazy配合使用来注入多例的代理Bean,现在@Resource也可以了。给出一个范例如下:
@Import(ScopedBean.class) // 使用@Import注入 即使它头上没有任何注解也是ok的 @Configuration public class Main { @Lazy @Resource ScopedBean bean; public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class); Main bean = context.getBean(Main.class); //如果bean上没有@Lazy注解, 则2个获取的bean是一个实例, //加了@Lazy注解后, 则2次获取的是2个实例 System.out.println(bean.bean); System.out.println(bean.bean); context.close(); } } // 多例 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) class ScopedBean { }
把@Lazy注解去掉,其余任何什么都不变:
@Resource ScopedBean bean; ... System.out.println(bean.bean); //com.fsx.maintest.ScopedBean@5fdcaa40 System.out.println(bean.bean); //com.fsx.maintest.ScopedBean@5e0826e7
可以看到,没有标注@Lazy每次获取Bean都是同一个Bean了。(因为Spring为属性注入值,会立马getBean,所以这个时候@Scope可能达不到你的效果了,使用时需要引起注意~)
主要是为了方便实现Scope代理(或延迟获取, 比如注入时还没初始化等)情况, 也就是当singleton引用prototype时, 就需要@Lazy
5、提供@EventListener注解等相关API
这是本文主要讲述的内容了,当然还有@TransactionalEventListener等API,再提一句:它的condition属性是可以使用SpEL表达式的
6、提供@AliasFor注解
提供@AliasFor注解, 来给注解的属性起别名, 让使用注解时, 更加的容易理解(比如给value属性起别名, 更容易让人理解).
此注解的解析原理非常复杂,后面会做更加详细的讨论,此处先知道怎么用即可
给出如下使用案例作为参考:
@MainBean(beanName = "mainbean") public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Main.class); String[] beannames = context.getBeanNamesForType(Main.class); //当加上@AliasFor时, 输出"mainbean" //当去掉@AliasFor注解后, 输出"main"(`main`是默认的beanName生成策略生成的) System.out.println(beannames[0]); context.close(); } } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @interface MainBean { @AliasFor(annotation = Component.class, attribute = "value") String beanName() default ""; }