Spring自定义Annotation扫描

xiaoxiao2021-02-28  115

背景

最近遇到需要在系统启动前针对自定义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) @Slf4j public 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来提供所需内容

@Autowired private TestModelAnnotationParser parser;

目录

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

转载请注明原文地址: https://www.6miu.com/read-60758.html

最新回复(0)