Spring 第三讲 BeanFactory 后置处理器
pom.xml 准备
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
<relativePath/>
</parent>
<groupId>org.laoshiren</groupId>
<artifactId>spring-bean-init</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
BeanFactory后置处理器
java
public class MyBeanFactoryPostProcessor {
public static void main(String[] args) {
GenericApplicationContext ctx = new GenericApplicationContext();
ctx.registerBean("config", Config.class);
// 需要添加BeanFactory后置处理器
ctx.registerBean(ConfigurationClassPostProcessor.class);
// 扫描@ComponentScan @Bean @Import @ImportResource
ctx.refresh();
for (String beanDefinitionName : ctx.getBeanDefinitionNames()) {
System.out.println("\t" + beanDefinitionName);
}
ctx.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BeanFactoryPostProcessor 是如何工作的?首先我们都知道Spring 里大概流程就是:
- 告诉ApplicationContext 资源位置
- 把资源加载到BeanFactory 里
- ApplicationContext 把BeanFactoryPostProcessor 注册到BeanFactory 中
- BeanFactoryPostProcessor 执行对应的操作将Bean 加载到BeanFactory
- 实例化Bean
- BeanPostProcessor 做后续的操作。
java
public class AbstractApplicationContext {
public void refresh(){
// 上面省略
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess =
this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// 下面也省略
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
refresh()
方法中把BeanFactory 后置处理器注册到BeanFactory 然后调用了他的方法将Bean 加载到容器中。
那应该如何注册呢
我们以ComponentScan 为例,简单还原一下
- 看他的basePackages
- 找到对应的resource
- 看看带不带Component 注解
- 注册对应的BeanDefinition
java
public class MockAnnotationBeanFactoryPostProcessor {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config", Config.class);
DefaultListableBeanFactory defaultListableBeanFactory =
context.getDefaultListableBeanFactory();
// 查找是否存在 ComponentScan 注解
ComponentScan componentScan =
AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
if (componentScan!=null) {
for (String basePackage: componentScan.basePackages()) {
System.out.println(basePackage);
// 最终是以字节码的方式找
String filePath = "classpath:*"+basePackage.replace(".","/")+"/**/*.class";
System.out.println(filePath);
Resource[] resources = context.getResources(filePath);
// 没有context 的情况
// resources = new PathMatchingResourcePatternResolver().getResources(filePath);
// 读取类的元信息的工厂
CachingMetadataReaderFactory metadataReaderFactory =new CachingMetadataReaderFactory();
// bean Name 生存器
AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
System.out.println(resource);
// 读取类的元信息
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
// 类的元信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 注解元信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 无法获取到他的派生注解 比如@Controller @Service
boolean hasComponentAnnotation = annotationMetadata.hasAnnotation(Component.class.getName());
// 获取派生注解
boolean hasMetaComponentAnnotation = annotationMetadata.hasMetaAnnotation(Component.class.getName());
// 如果是 Component注解 或者是派生的注解
if (hasComponentAnnotation || hasMetaComponentAnnotation) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(classMetadata.getClassName())
.getBeanDefinition();
// Bean name
String beanName =
beanNameGenerator.generateBeanName(beanDefinition, defaultListableBeanFactory);
// 注册Bean
defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
}
}
context.refresh();
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
context.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@Bean 的解析处理
如何解析Configuration 修饰的类里的 @Bean 注解修饰方法。
- 找到类
- 找到方法
- 转换成BeanDefinition
- 加载到BeanFactory
java
public class MockAnnotationConfigurationBeanFactoryPostProcessor {
public static void main(String[] args) throws IOException {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("config",Config.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
CachingMetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
MetadataReader metadataReader =
metadataReaderFactory.getMetadataReader(new ClassPathResource("com/laoshiren/app/bean/Config.class"));
// 获取注解元信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取被注解标注的方法
Set<MethodMetadata> annotatedMethods = annotationMetadata.getAnnotatedMethods(Bean.class.getName());
for (MethodMetadata annotatedMethod : annotatedMethods) {
System.out.println(annotatedMethod);
// 创建BeanDefinition
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();
// 没搞懂如何拿到 config
// 第一个参数表示那些被@Bean修饰的方法
// 第二个参数需要FactoryBean 那谁是他的factoryBean 呢 这个Bean 被谁创建呢
beanDefinitionBuilder.setFactoryMethodOnBean(annotatedMethod.getMethodName(), "config")
// 有参数的方法需要指定装配模式 默认是No
//在对于构造方法的参数和工厂方法的参数都是CONSTRUCTOR
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
// 初始化方法
String initMethod = annotatedMethod.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();
if (StringUtils.hasText(initMethod)) {
beanDefinitionBuilder.setInitMethodName(initMethod);
}
// 同样还有销毁的方法
// beanDefinitionBuilder.setDestroyMethodName("");
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// 方法名字作为bean Name
beanFactory.registerBeanDefinition(annotatedMethod.getMethodName(), beanDefinition);
}
context.refresh();
for (String beanDefinitionName : context.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
context.close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@MapperScannerConfigurer
以后自己实现的BeanFactoryPostProcessor
都可以直接实现 BeanDefinitionRegistryPostProcessor
,这样就不用为了ConfigurableListableBeanFactory 无法直接注册BeanDefinition 而强转了。
java
public class MapperBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
try {
// 找注解省略
// 找包省略
// 找 mapper
PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
Resource[] resources = patternResolver
.getResources("classpath:com/laoshiren/app/mapper/mapper/**/*.class");
// 读取元数据
CachingMetadataReaderFactory readerFactory = new CachingMetadataReaderFactory();
AnnotationBeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
for (Resource resource : resources) {
MetadataReader metadataReader = readerFactory.getMetadataReader(resource);
// 类属性
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 不是接口就跳过
if (!classMetadata.isInterface()) {
continue;
}
// 没有@Mapper 注解就跳过
boolean hasMapper = annotationMetadata.hasAnnotation(Mapper.class.getName());
if (!hasMapper) {
continue;
}
// 准备生成MapperFactoryBean
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(MapperFactoryBean.class)
// 添加构造方法的值
.addConstructorArgValue(classMetadata.getClassName())
// 自动装配 去装SqlSessionFactory
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
.getBeanDefinition();
// 需要用各自的FactoryBean 里实现的类的名字
AbstractBeanDefinition beanNameDefinition = BeanDefinitionBuilder
.genericBeanDefinition(classMetadata.getClassName())
.getBeanDefinition();
// 更具beanNameDefinition 创建BeanName
String beanName = beanNameGenerator.generateBeanName(beanNameDefinition, registry);
// 直接注册beanDefinition 会导致后注册上来的BeanName 与前面的一致而覆盖(因为都是MapperFactoryBean)
// 所以需要重新注册一个Bean 就用mapper本身作为name去注册防止覆盖
// 注册到beanFactory
registry.registerBeanDefinition(beanName, beanDefinition);
}
} catch (IOException e) {
throw new BeanCreationException(e.getMessage());
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58