前言
本文继笔者学习mybatis源码后,仿照mybatis利用spring的拓展点将Mapper接口的代理类装入IOC的办法,实现自定义注解,让spring将指定包中有此注解的类拆卸进IOC容器来治理之,最终是放入容器的单例池中。
实现
1. 自定义注解
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface XxgComponent {}
2. XxgComponentScannerConfigurer
2.1 实现BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor
,是spring给咱们的一个拓展点,其本身继承自BeanFactoryPostProcessor
接口。
实现此接口的类,spring在初始化之后,会调用其以下两个办法:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry var1) throws BeansException;void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
故咱们能够在其实现类对应的办法中,执行咱们的业务逻辑--即让spring扫描咱们自定义注解对应的类。
2.2 代码
public class XxgComponentScannerConfigurer implements BeanDefinitionRegistryPostProcessor { private String basePackages; public void setBasePackages(String basePackages) { this.basePackages = basePackages; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { // left intentionally blank } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { XxgComponentScanner scanner = new XxgComponentScanner(registry); scanner.registerFilters(); scanner.scan(basePackages); }}
3.扫描类XxgComponentScanner
3.1 ClassPathBeanDefinitionScanner
此类是spring用于扫描bean的类,
- 其
doScan()
办法会依据配置的拦截器规定,来将须要的类装配成BeanDefinitionHolder
对象并返回。 - 调用其
scan()
办法,其本身先调用doScan()
办法,而后会将扫描到的BeanDefinitionHolder
对象放入IOC容器
故,咱们能够继承其类,而后:
- 不应用其默认拦挡规定,而是依据咱们自定义注解来拦挡
- 重写其
doScan()
办法,首先调用父类的doScan()
获取到有咱们自定义注解的BeanDefinitionHolder
对象们,而后能够遍历操作之,更改一些咱们须要的参数,比方设置scope为单例等。
3.2 代码
public class XxgComponentScanner extends ClassPathBeanDefinitionScanner { public XxgComponentScanner(BeanDefinitionRegistry registry) { // 第二个参数:useDefaultFilters // 设置为false,不应用默认拦截器 super(registry, false); } @Override public Set<BeanDefinitionHolder> doScan(String... basePackages) { // 利用spring的扫描办法,扫描mapper接口所在的包,获取所有BeanDefinitionHolder Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); processBeanDefinitions(beanDefinitions); return beanDefinitions; } private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitionHolders) { for (BeanDefinitionHolder holder : beanDefinitionHolders) { GenericBeanDefinition beanDefinition = (GenericBeanDefinition)holder.getBeanDefinition(); beanDefinition.setScope("singleton"); System.out.println(beanDefinition.getBeanClassName()); } } // 定义拦截器,让spring拆卸咱们须要的对象到IOC容器 public void registerFilters() { // 设置 只扫描有@XxgComponent注解的类 addIncludeFilter(new AnnotationTypeFilter(XxgComponent.class)); // 设置 疏忽 package-info.java addExcludeFilter((metadataReader, metadataReaderFactory) -> { String className = metadataReader.getClassMetadata().getClassName(); return className.endsWith("package-info"); }); }}
4.让spring治理咱们的XxgComponentScannerConfigurer
<!-- 测试自定义拆卸bean注解--> <bean class="com.dbc.springMybatis.util.XxgComponentScannerConfigurer"> <property name="basePackages" value="com.dbc.springMybatis.myBean"/> </bean>