【spring源码分析】BeanDefinitionRegistryPostProcessor接口可自定义bean加入IOC
自定义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);
}
}
24.1 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定义的示例。
24.1.1 扫描指定包及其子包下面的所有非接口和非抽象类。
@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);
}
}
24.1.2 扫描指定包及其子包下面拥有指定注解的类。
@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一共有三个构造方法,分别如下:
public 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。
24.1.2.1 considerMetaAnnotations
指定considerMetaAnnotations="true"时则如果目标类上没有指定的注解,但是目标类上的某个注解上加上了指定的注解则该类也将匹配。比如:
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface HelloAnnotation { }
@HelloAnnotation
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface HasHelloAnnotation { }
@HasHelloAnnotation
public class Hello { }
24.1.2.2 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 { }
24.1.2.3 父类上拥有指定的注解
如果我们需要扫描的目标注解上是加了@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扫描不到。
24.1.3 扫描指定包及其子包下面能赋值给指定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接口可自定义bean加入IOC的更多相关文章
- spring源码分析——BeanPostProcessor接口
BeanPostProcessor是处理bean的后置接口,beanDefinitionMaps中的BeanDefinition实例化完成后,完成populateBean,属性设置,完成 初始化后,这 ...
- 【Spring源码分析系列】加载Bean
/** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * ...
- spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
更多文章点击--spring源码分析系列 主要分析内容: 一.BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor简述与demo示例 ...
- spring源码分析系列 (2) spring拓展接口BeanPostProcessor
Spring更多分析--spring源码分析系列 主要分析内容: 一.BeanPostProcessor简述与demo示例 二.BeanPostProcessor源码分析:注册时机和触发点 (源码基于 ...
- spring源码分析系列 (3) spring拓展接口InstantiationAwareBeanPostProcessor
更多文章点击--spring源码分析系列 主要分析内容: 一.InstantiationAwareBeanPostProcessor简述与demo示例 二.InstantiationAwareBean ...
- 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作
前言 之前两篇文章[Spring源码分析]非懒加载的单例Bean初始化过程(上篇)和[Spring源码分析]非懒加载的单例Bean初始化过程(下篇)比较详细地分析了非懒加载的单例Bean的初始化过程, ...
- spring源码分析系列
spring源码分析系列 (1) spring拓展接口BeanFactoryPostProcessor.BeanDefinitionRegistryPostProcessor spring源码分析系列 ...
- Spring源码分析:非懒加载的单例Bean初始化前后的一些操作
之前两篇文章Spring源码分析:非懒加载的单例Bean初始化过程(上)和Spring源码分析:非懒加载的单例Bean初始化过程(下)比较详细地分析了非懒加载的单例Bean的初始化过程,整个流程始于A ...
- Spring源码分析之`BeanFactoryPostProcessor`调用过程
前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 本文内容: AbstractApplicationContext#refresh前部分的一点小内容 ...
随机推荐
- nginx:支持https
1.查看nginx模块 nginx -V 注意是大写的V,小写的v是查看版本号的命令. 如果看到with-ssl那就是有的 2.注册ssl证书并下载 免费的ssl证书有: Let's Encrypt ...
- Oracle 12c Sharding测试过程中的问题解决
Sharding测试过程中的问题解决 1. 环境部署 软件的版本需要12.2.0.0.3及以上的版本 在配置GSM的时候报错信息不会很直观的展示出来,这对于安装部署有很大阻碍. 2. 数据导入 Dup ...
- MyBatis逆向工程:根据table生成Model、Mapper、Mapper.xml
逆向工程工具 下载地址:https://download.csdn.net/download/zhutouaizhuwxd/10779140 1.工程导入Eclipse 2.运行MainUI.jav ...
- SpringBoot + JPA 连接MySQL完整实例(一)
开发工具 1.Eclipse 2.Maven 3.Spring Boot 首先,Eclipse中配置好maven,具体请百度 工程结构: 实现步骤: 1.Eclipse中新建一个maven proje ...
- css选择器思维导图
- centos7安装配置zabbix4.0
zabbix01 198.8.8.211 zabbix-server4.0 zabbix02 198.8.8.212 zabbix-agent4.0 一:zabbix服务端环境 ...
- go语言基础学习
go基础学习,面向对象-方法在Go语言中,可以给任意自定义类型(包括内置类型,但不包括指针类型)添加相应的方法 使用= 和:=的区别: // = 使用必须使用先var声明例如: var a a=100 ...
- webstorm安装流程
第一步:双击安装目录 修改安装目录 尽量不要放在C盘 第二步: 把汉化包 直接复制文件到WebStorm安装目录中lib文件夹中即可,重新打开WebStorm就可以了
- 接口的鉴权&响应数据解密
前言: 1.开放的接口为了避免被别人攻击,频繁刷接口,浪费服务器资源,这就涉及到签名(Signature)加密了 2.API 使用签名方法(Signature)对接口进行鉴权(Authenticati ...
- PMS5003ST+Arduino Nano OLED屏显示
整合OLED显示和PMS5003报数 #include <Arduino.h> #include <pms.h> /////////////////////////////// ...