背景
在使用spring时,有时候有会有一些自定义annotation的需求,比如一些Listener的回调函数。

比如:

  1. @Service
  2. public class MyService {
  3. @MyListener
  4. public void onMessage(Message msg){
  5. }
  6. }

一开始的时候,我是在Spring的ContextRefreshedEvent事件里,通过context.getBeansWithAnnotation(Component.class) 来获取到所有的bean,然后再检查method是否有@MyListener的annotation。

后来发现这个方法有缺陷,当有一些spring bean的@Scope设置为session/request时,创建bean会失败。

参考:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes

在网上搜索了一些资料,发现不少人都是用context.getBeansWithAnnotation(Component.class),这样子来做的,但是这个方法并不对。

BeanPostProcessor接口
后来看了下spring jms里的@JmsListener的实现,发现实现BeanPostProcessor接口才是最合理的办法。

  1. public interface BeanPostProcessor {
  2.  
  3. /**
  4. * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
  5. * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
  6. * or a custom init-method). The bean will already be populated with property values.
  7. * The returned bean instance may be a wrapper around the original.
  8. * @param bean the new bean instance
  9. * @param beanName the name of the bean
  10. * @return the bean instance to use, either the original or a wrapped one;
  11. * if {@code null}, no subsequent BeanPostProcessors will be invoked
  12. * @throws org.springframework.beans.BeansException in case of errors
  13. * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
  14. */
  15. Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  16.  
  17. /**
  18. * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
  19. * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
  20. * or a custom init-method). The bean will already be populated with property values.
  21. * The returned bean instance may be a wrapper around the original.
  22. * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
  23. * instance and the objects created by the FactoryBean (as of Spring 2.0). The
  24. * post-processor can decide whether to apply to either the FactoryBean or created
  25. * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
  26. * <p>This callback will also be invoked after a short-circuiting triggered by a
  27. * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
  28. * in contrast to all other BeanPostProcessor callbacks.
  29. * @param bean the new bean instance
  30. * @param beanName the name of the bean
  31. * @return the bean instance to use, either the original or a wrapped one;
  32. * if {@code null}, no subsequent BeanPostProcessors will be invoked
  33. * @throws org.springframework.beans.BeansException in case of errors
  34. * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
  35. * @see org.springframework.beans.factory.FactoryBean
  36. */
  37. Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
  38.  
  39. }

所有的bean在创建完之后,都会回调postProcessAfterInitialization函数,这时就可以确定bean是已经创建好的了。

所以扫描自定义的annotation的代码大概是这个样子的:

  1. public class MyListenerProcessor implements BeanPostProcessor {
  2. @Override
  3. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  4. return bean;
  5. }
  6.  
  7. @Override
  8. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  9. Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
  10. if (methods != null) {
  11. for (Method method : methods) {
  12. MyListener myListener = AnnotationUtils.findAnnotation(method, MyListener.class);
  13. // process
  14. }
  15. }
  16. return bean;
  17. }
  18. }

  

SmartInitializingSingleton 接口
看spring jms的代码时,发现SmartInitializingSingleton 这个接口也比较有意思。

就是当所有的singleton的bean都初始化完了之后才会回调这个接口。不过要注意是 4.1 之后才出现的接口。

  1. public interface SmartInitializingSingleton {
  2.  
  3. /**
  4. * Invoked right at the end of the singleton pre-instantiation phase,
  5. * with a guarantee that all regular singleton beans have been created
  6. * already. {@link ListableBeanFactory#getBeansOfType} calls within
  7. * this method won't trigger accidental side effects during bootstrap.
  8. * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
  9. * lazily initialized on demand after {@link BeanFactory} bootstrap,
  10. * and not for any other bean scope either. Carefully use it for beans
  11. * with the intended bootstrap semantics only.
  12. */
  13. void afterSingletonsInstantiated();
  14.  
  15. }

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/SmartInitializingSingleton.html

正确实现用spring扫描自定义的annotation的更多相关文章

  1. spring扫描自定义注解并进行操作

    转载:http://blog.csdn.net/cuixuefeng1112/article/details/45331233 /**  * 扫描注解添加服务到缓存以供判断时候为对外开放service ...

  2. spring AOP自定义注解方式实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  3. spring AOP自定义注解 实现日志管理

    今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...

  4. springboot扫描自定义的servlet和filter代码详解_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 这几天使用spring boot编写公司一个应用,在编写了一个filter,用于指定编码的filter,如下: /** ...

  5. 利用Spring AOP自定义注解解决日志和签名校验

    转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...

  6. spring中自定义Event事件的使用和浅析

    在我目前接触的项目中,用到了许多spring相关的技术,框架层面的spring.spring mvc就不说了,细节上的功能也用了不少,如schedule定时任务.Filter过滤器. intercep ...

  7. Spring 扫描标签<context:component-scan/>

    一. <context:annotation-config/> 此标签支持一些注入属性的注解, 列如:@Autowired, @Resource注解 二. <context:comp ...

  8. 6.2 dubbo在spring中自定义xml标签源码解析

    在6.1 如何在spring中自定义xml标签中我们看到了在spring中自定义xml标签的方式.dubbo也是这样来实现的. 一 META_INF/dubbo.xsd 比较长,只列出<dubb ...

  9. 6.1 如何在spring中自定义xml标签

    dubbo自定义了很多xml标签,例如<dubbo:application>,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个简单的例子. 一 编写模型类 package ...

随机推荐

  1. spark submit参数及调优

    park submit参数介绍 你可以通过spark-submit --help或者spark-shell --help来查看这些参数.   使用格式:  ./bin/spark-submit \   ...

  2. dubbo源码之服务发布与注册

    服务端发布流程: dubbo 是基于 spring 配置来实现服务的发布的,对于dubbo 配置文件中看到的<dubbo:service>等标签都是服务发布的重要配置 ,对于这些提供可配置 ...

  3. LeetCode(69):x 的平方根

    Easy! 题目描述: 实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去. 示例 1: 输入: ...

  4. 理解并设计rest/restful风格接口

    网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信.这导致AP ...

  5. JMeter 中对于Json数据的处理方法

    JMeter中对于Json数据的处理方法 http://eclipsesource.com/blogs/2014/06/12/parsing-json-responses-with-jmeter/ J ...

  6. 引用的作用&引用与指针的区别

    引入 C语言中函数有两种传参的方式: 传值和传址.以传值方式, 在函数调用过程中会生成一份临时变量用形参代替, 最终把实参的值传递给新分配的临时变量即形参. 它的优点是避免了函数调用的一些副作用, 但 ...

  7. 磁盘修改AF

    请严格按照如下流程: 1 以管理员打开 硬盘安装助手 2 选择苹果Mac系统镜像 (cdr格式的) 3 直接选择要写入的盘,不要点击右边的方框中的勾选 (此时就可以写入了,虽然最后还是显示 Chang ...

  8. Html中,id、name、class、type的区别

    <input type="text" name="name" id="name" class="txt"> ...

  9. 树递归写法ref实现

    using System; using System.Collections.Generic; using System.Linq; namespace ConsoleAppTest { class ...

  10. Java-把日期字符串转换成另一种格式的日期字符串

    package com.example.demo.utils; import java.text.ParseException; import java.text.SimpleDateFormat; ...