一、自定义BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,是一种比较特殊的BeanFactoryPostProcessor。BeanDefinitionRegistryPostProcessor中定义的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法 可以让我们实现自定义的注册bean定义的逻辑。下面的示例中就新定义了一个名为hello,类型为Hello的bean定义。

public class CustomBeanDefinitionRegistry implements BeanDefinitionRegistryPostProcessor {

    @Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } @Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
RootBeanDefinition helloBean = new RootBeanDefinition(Hello.class);
//新增Bean定义
registry.registerBeanDefinition("hello", helloBean);
} }
 测试时采用的配置是基于Java类的配置,对应的配置类如下:
@Configuration
public class SpringConfiguration { @Bean
public CustomBeanDefinitionRegistry customBeanDefinitionRegistry() {
return new CustomBeanDefinitionRegistry();
} }

测试如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={SpringConfiguration.class})
public class CustomBeanDefinitionRegistryTest { @Autowired
private Hello hello; @Test
public void test() {
//能运行就说明hello是不为空的
Assert.assertNotNull(hello);
} }

二、ClassPathScanningCandidateComponentProvider

在使用自定义的BeanDefinitionRegistryPostProcessor来添加自定义的bean定义时可以配合ClassPathScanningCandidateComponentProvider一起使用,ClassPathScanningCandidateComponentProvider可以根据一定的规则扫描类路径下满足特定条件的Class来作为候选的bean定义。 ClassPathScanningCandidateComponentProvider在扫描时可以通过TypeFilter来指定需要匹配的类和需要排除的类,使用ClassPathScanningCandidateComponentProvider时可以通过构造参数useDefaultFilter指定是否需要使用默认的TypeFilter,默认的TypeFilter将包含类上拥有 @Component、@Service、@Repository、@Controller、@javax.annotation.ManagedBean和@javax.inject.Named注解的类。在扫描时需要指定扫描的根包路径。以下是一些使用ClassPathScanningCandidateComponentProvider扫描并注册bean定义的示例。

扫描指定包及其子包下面的所有非接口和非抽象类。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
boolean useDefaultFilters = false;//是否使用默认的filter,使用默认的filter意味着只扫描那些类上拥有Component、Service、Repository或Controller注解的类。
String basePackage = "com.elim.learn.spring.bean";
ClassPathScanningCandidateComponentProvider beanScanner = new ClassPathScanningCandidateComponentProvider(useDefaultFilters);
TypeFilter includeFilter = new TypeFilter() { @Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
return metadataReader.getClassMetadata().isConcrete();
} };
beanScanner.addIncludeFilter(includeFilter);
Set<BeanDefinition> beanDefinitions = beanScanner.findCandidateComponents(basePackage);
for (BeanDefinition beanDefinition : beanDefinitions) {
//beanName通常由对应的BeanNameGenerator来生成,比如Spring自带的AnnotationBeanNameGenerator、DefaultBeanNameGenerator等,也可以自己实现。
String beanName = beanDefinition.getBeanClassName();
registry.registerBeanDefinition(beanName, beanDefinition);
}
}

扫描指定包及其子包下面拥有指定注解的类。

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
boolean useDefaultFilters = false;//是否使用默认的filter,使用默认的filter意味着只扫描那些类上拥有Component、Service、Repository或Controller注解的类。
String basePackage = "com.elim.learn.spring.bean";
ClassPathScanningCandidateComponentProvider beanScanner = new ClassPathScanningCandidateComponentProvider(useDefaultFilters);
TypeFilter includeFilter = new AnnotationTypeFilter(HelloAnnotation.class);
beanScanner.addIncludeFilter(includeFilter);
Set<BeanDefinition> beanDefinitions = beanScanner.findCandidateComponents(basePackage);
for (BeanDefinition beanDefinition : beanDefinitions) {
//beanName通常由对应的BeanNameGenerator来生成,比如Spring自带的AnnotationBeanNameGenerator、DefaultBeanNameGenerator等,也可以自己实现。
String beanName = beanDefinition.getBeanClassName();
registry.registerBeanDefinition(beanName, beanDefinition);
}
}

AnnotationTypeFilter是Spring自带的一个TypeFilter,可以扫描指定的注解。AnnotationTypeFilter一共有三个构造方法,分别如下:

ublic AnnotationTypeFilter(Class<? extends Annotation> annotationType) {
this(annotationType, true, false);
} public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations) {
this(annotationType, considerMetaAnnotations, false);
} public AnnotationTypeFilter(Class<? extends Annotation> annotationType, boolean considerMetaAnnotations, boolean considerInterfaces) {
super(annotationType.isAnnotationPresent(Inherited.class), considerInterfaces);
this.annotationType = annotationType;
this.considerMetaAnnotations = considerMetaAnnotations;
}

主要差别在于considerMetaAnnotations和considerInterfaces。

considerMetaAnnotations

指定considerMetaAnnotations="true"时则如果目标类上没有指定的注解,但是目标类上的某个注解上加上了指定的注解则该类也将匹配。比如:

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface HelloAnnotation { }
@HelloAnnotation
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface HasHelloAnnotation { }
@HasHelloAnnotation
public class Hello { }

considerInterfaces

在上面的代码中定义了两个注解HelloAnnotation和HasHelloAnnotation,其中HasHelloAnnotation上加上了@HelloAnnotation注解,类Hello上面加上了@HasHelloAnnotation注解,则在通过AnnotationTypeFilter扫描标注有HelloAnnotation注解的类时,如果指定了considerMetaAnnotations="true"则类Hello也会被扫描到。
指定considerInterfaces="true"时,则如果对应的类实现的接口上拥有指定的注解时也将匹配。比如下面这种情况扫描加了HelloAnnotation注解的类时就会扫描到Hello类。

@HelloAnnotation
public interface HelloInterface { }
public class Hello implements HelloInterface { }

父类上拥有指定的注解

如果我们需要扫描的目标注解上是加了@Inherited注解的,则如果一个类上没有指定的目标注解,但是其父类拥有对应的注解,则也会被扫描到。比如我们将HelloAnnotation加上@Inherited注解。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface HelloAnnotation { }

Hello类上加上@HelloAnnotation注解。

@HelloAnnotation
public class Hello { }
然后HelloChild类继承自Hello类。
```java
public class HelloChild extends Hello { }

这时候进行扫描时HelloChild也会被扫描到,但如果拿掉HelloAnnotation上的@Inherited,则HelloChild扫描不到。

扫描指定包及其子包下面能赋值给指定Class的Class

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
boolean useDefaultFilters = false;//是否使用默认的filter,使用默认的filter意味着只扫描那些类上拥有Component、Service、Repository或Controller注解的类。
String basePackage = "com.elim.learn.spring.bean";
ClassPathScanningCandidateComponentProvider beanScanner = new ClassPathScanningCandidateComponentProvider(useDefaultFilters);
//指定considerMetaAnnotations="true"时则如果目标类上没有指定的注解,但是目标类上的某个注解上加上了指定的注解则该类也将匹配。比如:
TypeFilter includeFilter = new AssignableTypeFilter(Hello.class);
beanScanner.addIncludeFilter(includeFilter);
Set<BeanDefinition> beanDefinitions = beanScanner.findCandidateComponents(basePackage);
for (BeanDefinition beanDefinition : beanDefinitions) {
//beanName通常由对应的BeanNameGenerator来生成,比如Spring自带的AnnotationBeanNameGenerator、DefaultBeanNameGenerator等,也可以自己实现。
String beanName = beanDefinition.getBeanClassName();
registry.registerBeanDefinition(beanName, beanDefinition);
}
}

AssignableTypeFilter也是Spring内置的一个TypeFilter,用于扫描指定类型的类。只要目标类型能够赋值给指定的类型,则表示匹配。即如果指定的是一个接口,则所有直接或间接实现该接口的类都将被扫描到。

基于ClassPathScanningCandidateComponentProvider的特性,我们常常可以利用它构建一个工具类用以扫描指定包路径下指定类型的Class,获取满足条件的Class,然后加以利用,这常用于需要扫描的类不是Spring bean的场景。

【spring源码分析】BeanDefinitionRegistryPostProcessor解析的更多相关文章

  1. spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

    更多文章点击--spring源码分析系列 主要分析内容: 一.BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor简述与demo示例 ...

  2. spring源码分析系列 (5) spring BeanFactoryPostProcessor拓展类PropertyPlaceholderConfigurer、PropertySourcesPlaceholderConfigurer解析

    更多文章点击--spring源码分析系列 主要分析内容: 1.拓展类简述: 拓展类使用demo和自定义替换符号 2.继承图UML解析和源码分析 (源码基于spring 5.1.3.RELEASE分析) ...

  3. Spring源码分析之AOP从解析到调用

    正文: 在上一篇,我们对IOC核心部分流程已经分析完毕,相信小伙伴们有所收获,从这一篇开始,我们将会踏上新的旅程,即Spring的另一核心:AOP! 首先,为了让大家能更有效的理解AOP,先带大家过一 ...

  4. spring源码分析系列

    spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor spring源码分析系列 ...

  5. Spring源码分析之IOC的三种常见用法及源码实现(二)

    Spring源码分析之IOC的三种常见用法及源码实现(二) 回顾上文 我们研究的是 AnnotationConfigApplicationContext annotationConfigApplica ...

  6. Spring源码分析之`BeanFactoryPostProcessor`调用过程

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 本文内容: AbstractApplicationContext#refresh前部分的一点小内容 ...

  7. Spring源码分析——BeanFactory体系之抽象类、类分析(二)

    上一篇分析了BeanFactory体系的2个类,SimpleAliasRegistry和DefaultSingletonBeanRegistry——Spring源码分析——BeanFactory体系之 ...

  8. Spring源码分析——BeanFactory体系之抽象类、类分析(一)

    上一篇介绍了BeanFactory体系的所有接口——Spring源码分析——BeanFactory体系之接口详细分析,本篇就接着介绍BeanFactory体系的抽象类和接口. 一.BeanFactor ...

  9. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  10. spring源码分析

    编译问题 spring-4.0.5.release编译是用jdk8编译的,为啥可以运行在jdk7的环境? 源码分析 spring源码分析,由一个点各个击破,比如依赖注入,autowired. spri ...

随机推荐

  1. bzoj1692

    题解: 二分最近的不相同 然后hash判断是否相同 然后贪心 代码: #include<bits/stdc++.h> using namespace std; #define ull un ...

  2. javascript es6系列教程 - 不定参数与展开运算符(...)

    三个点(...)在es6中,有两个含义: 用在形参中, 表示传递给他的参数集合, 类似于arguments, 叫不定参数. 语法格式:  在形参面前加三个点( ... ) 用在数组前面,可以把数组的值 ...

  3. Python Django 之 直接执行自定义SQL语句(一)

    一.执行自定义SQL方法 1.Executing custom SQL directly      直接执行自定义SQL,这种方式可以完全避免数据模型,而是直接执行原始的SQL语句. 2.Manage ...

  4. 图解前序遍历线索化二叉树,前序线索二叉树遍历,C\C++描述

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  5. 2.19 C++友元函数和友元类

    参考: http://www.weixueyuan.net/view/6350.html 总结: 借助friend关键字将其声明为友元函数,结果,在display函数体内,我们就能访问private属 ...

  6. 实力封装:Unity打包AssetBundle(三)

    前情提要:第二种打包方式 窗口初现 通过前面的两篇教程和一篇番外,我们已经完全实现了打包的功能.但是使用起来总是觉得有些晦涩别扭,如果不告诉别人怎么使用,对方肯定是一头雾水. What?你给我的这是啥 ...

  7. Java语法基础学习DayThree

    一.流程控制语句补充 1.switch语句 格式: switch(表达式) { case 值1: 语句体1; break; case 值2: 语句体2; break; ... default: 语句体 ...

  8. ios读取plist文件:

    @property (nonatomic,strong) NSArray *imageData;//定义一个数组 //懒加载数据 -(NSArray *)imageDate { if(_imageDa ...

  9. django面试大全

    1.Django请求的生命周期 a. wsgi, 创建socket服务端,用于接收用户请求并对请求进行初次封装. b. 中间件,对所有请求到来之前,响应之前定制一些操作. c. 路由匹配,在url和视 ...

  10. Day11作业及默写

    1.写函数,传入n个数,返回字典{'max':最大值,'min':最小值} 例如:min_max(2,5,7,8,4) 返回:{'max':8,'min':2}(此题用到max(),min()内置函数 ...