专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
芋道源码  ·  弃用 ... ·  昨天  
芋道源码  ·  SpringBoot ... ·  2 天前  
芋道源码  ·  一个注解完美实现分布式锁 ·  2 天前  
芋道源码  ·  公司弃用 Nginx,选择这款工具! ·  3 天前  
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;

    }

}


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.

     *

NOTE: 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


觉得本文对你有帮助?请分享给更多人

关注「ImportNew」,看技术干货