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

比如:

@Service
public class MyService {
@MyListener
public 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 {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
} @Override
public 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扫描自定义注解并进行操作

    转载: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. Dubbo常用配置文件分析及核心源码阅读(SPI.Extension)

    1.多版本支持: 基于上篇博客的 快速启动 Dubbo 服务 的代码进行多版本支持的演示:基于原来的实现类GpHelloImpl ,我们需要新增一个新版本的实类:GpHelloImpl2 public ...

  2. LeetCode(84): 柱状图中最大的矩形

    Hard! 题目描述: 给定 n 个非负整数,用来表示柱状图中各个柱子的高度.每个柱子彼此相邻,且宽度为 1 . 求在该柱状图中,能够勾勒出来的矩形的最大面积. 以上是柱状图的示例,其中每个柱子的宽度 ...

  3. py4测试题

    1.8<<2等于? 32 2.通过内置函数计算5除以2的余数 print(divmod(5,2))------>1 3.s=[1,"h",2,"e&qu ...

  4. python 内置数据类型之数字

    目录: 1.2. 数字 1.2.1. 数字类型 1.2.2. 浮点数 1.2.3. 进制记数 1.2.4. 设置小数精度 1.2.5. 分数 1.2.6. 除法 1.2 数字   1.2.1 数字类型 ...

  5. NPOI操作Excel(三)--解析Excel

    通过前面两篇的基础学习,我们对NPOI有了一定了了解,下面就开始进入实战,解析下面格式的Excel(下面只是列举了几个例子),并保存入库 首先我们先分析一下,要解析这样的Excel,需要把指标[橘色背 ...

  6. IDEA部署项目和多余的项目删掉的演示

  7. python的学习和使用

    1.python的官网:https://www.python.org/ Python简介: .Python 是一个高层次的结合了解释性.编译性.互动性和面向对象的脚本语言. .Python 的设计具有 ...

  8. [转] Lodash

    与underscore 类似 , 是1个js库,内部封装了诸多对字符串.数组.对象等常见数据类型的处理函数. 模块组成 Lodash 提供的辅助函数主要分为以下几类,函数列表和用法实例请查看 Loda ...

  9. bzoj2018年5月赛

    题解: 老早之前看的并没有写题解.. t1: 我刚开始想的是线段树来维护.. 看了题解发现直接二分就行了 很容易发现因数只会有30个 那么我们就统计每一种因数在这段区间的个数 然后开个vector记录 ...

  10. mysql字符集问题汇总

    1.设置mysql字符集:在my.ini中添加以下设置,没有my.ini可以将my_default.ini改成他.character-set-server=utf8[client]loose-defa ...