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

原创 2016年05月01日 14:07:04

背景

在使用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启动后获取所有拥有特定注解的Bean

最近项目中遇到一个业务场景,就是在Spring容器启动后获取所有的Bean中实现了一个特定接口的对象,第一个想到的是ApplicationContextAware,在setApplicationCon...
  • joshua1830
  • joshua1830
  • 2016年08月04日 11:00
  • 5423

applicationContext.getBeansWithAnnotation

getBeansWithAnnotation MapString,Object> getBeansWithAnnotation(ClassAnnotation> annotationType) ...
  • glory1234work2115
  • glory1234work2115
  • 2016年07月20日 20:46
  • 2683

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

今天又个需求,就是根据注解来判断是否接口为对外开放,那么启动spring容器的时候把这些注解修饰的bean name放进缓存当中。 /**  * 扫描注解添加服务到缓存以供判断时候为对外开放ser...
  • cuixuefeng1112
  • cuixuefeng1112
  • 2015年04月28日 09:22
  • 5298

Spring自动扫描类的加载顺序

写这篇文章的原因是本地代码运行结果和线上服务器运行结果不一致,类的加载顺序不一样,导致了意想不到的bug,由此展开了对spring自动扫描类的加载机制的探索,先看一下代码,主要涉及到RedissonP...
  • KeepStrong
  • KeepStrong
  • 2018年02月04日 19:53
  • 71

利用spring AOP和Annotation来简化DAO实现

通常在数据库DAO层的查询中,我们会定义一个DAO接口,而在实现中我们只是拼接查询参数并且指定一个ibatis的sqlmap中的sqlid进行查询, Dao的实现很类似,而且非常简单,其实可以简...
  • zhongweijian
  • zhongweijian
  • 2013年01月06日 23:32
  • 6966

Spring自定义annotation实现

spring自定义annotation
  • c275046758
  • c275046758
  • 2017年06月30日 17:12
  • 693

Spring的Annotation支持

请自行在所有的Annotation上将#换为艾特符号! 由于现在的主流Java框架受到了Rails框架的启发,开始渐渐的疏远XML配置方式,Spring也不例外,也支持使用Annotation来代替X...
  • AZHELL
  • AZHELL
  • 2017年03月19日 12:44
  • 432

Annotation(三)——Spring注解开发

Spring框架的核心功能IoC(Inversion of Control),也就是通过Spring容器进行对象的管理,以及对象之间组合关系的映射。通常情况下我们会在xml配置文件中进行action,...
  • liujiahan629629
  • liujiahan629629
  • 2014年03月31日 22:22
  • 23762

Spring基于 Annotation 的简单介绍

1.使用 @Repository、@Service、@Controller 和 @Component 将类标识为 Bean: Spring 自 2.0 版本开始,陆续引入了一些注解用于简化 Spri...
  • chjttony
  • chjttony
  • 2011年03月29日 15:07
  • 49276

SpringMVC-<mvc:annotation-driven>的作用

背景        事实上,我们更多的时候使用这个标签只是因为我们看到人家那么配的。但是我们对其中的配置大多数时候是浑然不知的。但是,当我们想去扩展其中的一些东西的时候,才发现这个有多麽的重要!标签的...
  • wangmeng951011
  • wangmeng951011
  • 2017年03月07日 21:35
  • 1118
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:正确实现用spring扫描自定义的annotation
举报原因:
原因补充:

(最多只允许输入30个字)