Spring自定义Annotation扫描

来源:互联网 发布:电子书资源 知乎 编辑:程序博客网 时间:2024/05/21 22:59

背景

最近遇到需要在系统启动前针对自定义Annotation的类缓存一些配置信息,以便系统快速映射调用。在翻看了一些资料后,发现spring可比较优雅的支持这种方案,其中涉及以下三个接口、类:

-ClassPathBeanDefinitionScanner - 根据包路径扫描标注实现类,也是本文改造的主体
-BeanFactoryPostProcessor - Bean加载后置处理接口
-ApplicationContextAware - 获取ApplicationContext接口

一、ClassPathBeanDefinitionScanner 继承类 AnnotationScanner

public class AnnotationScanner extends ClassPathBeanDefinitionScanner {    /**     * 实体类对应的AnnotationClazz     */    @Setter    private Class<? extends Annotation> selfAnnotationClazz;    /**     * 传值使用的临时静态变量     */    private static Class<? extends Annotation> staticTempAnnotationClazz = null;    /**     * 因构造函数无法传入指定的Annotation类,需使用静态方法来调用     * @param registry     * @param clazz     * @return     */    public static synchronized AnnotationScanner getScanner(BeanDefinitionRegistry registry,Class<? extends Annotation> clazz){        staticTempAnnotationClazz = clazz;        AnnotationScanner scanner = new AnnotationScanner(registry);        scanner.setSelfAnnotationClazz(clazz);        return scanner;    }    private AnnotationScanner(BeanDefinitionRegistry registry) {        super(registry);    }    // 构造函数需调用函数,使用静态变量annotationClazz传值    @Override    public void registerDefaultFilters() {        // 添加需扫描的Annotation Class        this.addIncludeFilter(new AnnotationTypeFilter(staticTempAnnotationClazz));    }    // 以下为初始化后调用的方法    @Override    public Set<BeanDefinitionHolder> doScan(String... basePackages) {        return super.doScan(basePackages);    }    @Override    public boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {        return super.isCandidateComponent(beanDefinition)                && beanDefinition.getMetadata().hasAnnotation(this.selfAnnotationClazz.getName());    }}

二、BeanFactoryPostProcessor 、ApplicationContextAware 接口实现类

@Component@Lazy(true)@Slf4jpublic class TestModelAnnotationParser implements ApplicationContextAware, BeanFactoryPostProcessor {    private static final String EVENT_NAME = "TestModel注解扫描";    private static final String RESOURCE_PATTERN = "com.test.example";    private static final String PATH_DOT = ".";    private ApplicationContext applicationContext;    /**     * Bean加载后置处理     */    @Override    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {        // 使用自定义扫描类,针对@TestModel进行扫描        AnnotationScanner scanner = AnnotationScanner.getScanner((BeanDefinitionRegistry) beanFactory, TestModel.class);        // 设置ApplicationContext        scanner.setResourceLoader(this.applicationContext);        // 执行扫描        int count = scanner.scan(RESOURCE_PATTERN);        log.info(EVENT_NAME + ", 扫描类数量:"+count);        // 取得对应Annotation映射,BeanName -- 实例        Map<String, Object> annotationMap = beanFactory.getBeansWithAnnotation(TestModel.class);        // .... doSomething,根据需要进行设置,    }    /**     * 获取ApplicationContext     */    @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {        this.applicationContext = applicationContext;    }}

至此,可以在需要的地方使用@Autowired,或通过ApplicationContext.getBean方式取得。当然更优雅的方式是另外配置一个Bean来提供所需内容

@Autowiredprivate TestModelAnnotationParser parser;

目录

    • 背景
    • 一ClassPathBeanDefinitionScanner 继承类 AnnotationScanner
    • 二BeanFactoryPostProcessor ApplicationContextAware 接口实现类
    • 目录

阅读全文
0 0
原创粉丝点击