背景

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

比如:

@Service
public class MyService {@MyListenerpublic void onMessage(Message msg){}
}

一开始的时候,我是在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接口才是最合理的办法。

public interface BeanPostProcessor {/*** Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet*/Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;/*** Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean* instance and the objects created by the FactoryBean (as of Spring 2.0). The* post-processor can decide whether to apply to either the FactoryBean or created* objects or both through corresponding {@code bean instanceof FactoryBean} checks.* <p>This callback will also be invoked after a short-circuiting triggered by a* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,* in contrast to all other BeanPostProcessor callbacks.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet* @see org.springframework.beans.factory.FactoryBean*/Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;}

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

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

public class MyListenerProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());if (methods != null) {for (Method method : methods) {MyListener myListener = AnnotationUtils.findAnnotation(method, MyListener.class);// process}}return bean;}
}

SmartInitializingSingleton 接口

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

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

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

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

正确实现用spring扫描自定义的annotation相关推荐

  1. spring 扫描自定义注解

    目录 一:定义自定义注解 二:使用自定义注解 3.1 定义使用注解的测试文件路径 3.2继承BeanPostProcessor增加spring扫描配置 四:测试 目录结构: 一:定义自定义注解 pac ...

  2. spring中自定义注解(annotation)与AOP中获取注解___使用aspectj的@Around注解实现用户操作和操作结果日志

    spring中自定义注解(annotation)与AOP中获取注解 一.自定义注解(annotation) 自定义注解的作用:在反射中获取注解,以取得注解修饰的类.方法或属性的相关解释. packag ...

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

    今天又个需求,就是根据注解来判断是否接口为对外开放,那么启动spring容器的时候把这些注解修饰的bean name放进缓存当中. /**  * 扫描注解添加服务到缓存以供判断时候为对外开放servi ...

  4. java 扫描自定义注解_利用spring 自定义注解扫描 找出使用自定义注解的类

    我们常常有扫描项目里带有指定注解的class, 下面是利用spring扫描自定义注解的方法, 还是比较灵活的 我这里将扫描到的class放到map, 你可以放到其他地方,以便后期使用 import l ...

  5. java 外部覆盖内部配置,Spring 与自定义注解、外部配置化的结合使用

    Spring 与自定义注解.外部配置化的结合使用 一.Java注解的简单介绍 注解,也叫Annotation.标注,是 Java 5 带来的新特性. 可使用范围 类.字段.方法.参数.构造函数.包等, ...

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

    转:spring AOP自定义注解方式实现日志管理 今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接 ...

  7. Spring Security自定义登录验证及登录返回结果

    Spring Security自定义登录验证及登录返回结果 一.功能描述 二.处理逻辑 简单流程 自定义UserDetails 自定义UserDetailsDAO 自定义UserDetailsServ ...

  8. Spring Security——自定义认证错误提示信息及自适应返回格式解决方案

    解决方案 package com.hailiu.web.handler;import com.hailiu.model.Log; import com.hailiu.web.bean.Response ...

  9. sessionattribute 被spring 扫描不到_Spring 系列之 Spring 常用注解总结(肝硬化的干货)...

    传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点: 1. 如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大:如果按需求分开.xml ...

最新文章

  1. SAP UI5 jQuery.sap.getModulePath 的工作原理
  2. 基于java+springboot+layui的流浪动物交流信息平台设计实现
  3. DT时代释放金融数据价值,驱动金融商业裂变
  4. 线程范围内的线程共享(多线程)
  5. 3. SQL 语句本身的优化(慢查询)
  6. ubuntu16.04 修改分辨路并永久保存
  7. 免费学plc的手机app_PLC网校app手机版 v1.2
  8. 台达变频器485通讯接线图_台达变频器RS485通讯设置
  9. 看了三篇韩寒的博客文章
  10. Python程序设计实验——2.掷骰子游戏
  11. 连续分配管理方式(单一连续分配 固定分区分配 动态分区分配)
  12. Kaldi 实践与探索 语音识别基本法 pdf
  13. 在线更换背景网站(白色背景换为蓝色背景证件照)
  14. 专访王豫翔:编程道路上的“三少三多”(摘录)
  15. 回顾使用云桌面的那些经验
  16. html 拉伸幕,html 对 div 进行 拉伸 拖拽
  17. python获取列表数字的下标
  18. flutter图片聊天泡泡_Flutter 非常丰富的消息气泡效果合集
  19. BigDecimal类型数据比较大小的方法和精度问题
  20. 安徽工业大学计算机考研调剂,安徽工业大学考研调剂

热门文章

  1. dubbo总结——dubbo的使用场景
  2. 4- vue django restful framework 打造生鲜超市 -restful api 与前端源码介绍
  3. Linux的简单Nginx
  4. 关于ubuntu 16.04 docker常用命令
  5. [转]JDBC中日期时间的处理技巧
  6. 深入了解一下PYTHON中关于SOCKETSERVER的模块-C
  7. 浏览器拦截弹出窗口 IE Firefox……浏览器
  8. Oracle 10g新增DROP DATABASE命令
  9. C#使用ExecuteReader返回DataReader既有查询结果集又有输出参数或返回值的使用注意事项...
  10. 云栖大会变迁史(2009-2017)