专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
芋道源码  ·  Nginx性能优化的几个方法 ·  10 小时前  
芋道源码  ·  还在用Jenkins?快来试试这款简而轻的自 ... ·  10 小时前  
芋道源码  ·  ES+MySQL优雅的实现模糊搜索 ·  昨天  
Java编程精选  ·  患者带着DeepSeek来看病,医学博主自嘲 ... ·  4 天前  
51好读  ›  专栏  ›  ImportNew

正确实现用 spring 扫描自定义的 annotation

ImportNew  · 公众号  · Java  · 2017-01-03 20:58

正文

(点击 上方公众号 ,可快速关注)


来源:hengyunabc

链接:blog.csdn.net/hengyunabc/article/details/51289327

如有好文章投稿,请点击 → 这里了解详情


背景


在使用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 before 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 after 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.

*

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.

*

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;

}







请到「今天看啥」查看全文