Spring 第二讲 BeanFactory 和ApplicationContext
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
BeanFactory 接口,典型功能有:
- getBean
ApplicationContext 接口,是 BeanFactory 的子接口。它扩展了 BeanFactory 接口的功能,如:
- 国际化
- 通配符方式获取一组 Resource 资源
- 整合 Environment 环境(能通过它获取各种来源的配置信息)
- 事件发布与监听,实现组件之间的解耦
java
@Configuration
public class Config {
@Bean
public Bean1 bean1(){
return new Bean1();
}
@Bean
public Bean2 bean2(){
return new Bean2();
}
}
@Data
@Slf4j
public class Bean1 {
@Autowired
private Bean2 bean2;
public Bean1(){
log.info("bean1 构造");
}
}
@Slf4j
public class Bean2 {
public Bean2(){
log.info("bean2 构造");
}
}
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
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
当我们使用BeanFactory 加载这个Config
类会有多少个Bean
java
public class BeanFactoryMain {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 定义(class scope )BeanDefinition
AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(Config.class)
.getBeanDefinition();
// 注册bean
beanFactory.registerBeanDefinition("config", configBeanDefinition);
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("\t"+beanDefinitionName);
}
System.out.println("------------------------------");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
shell
# 打印结果
config
------------------------------
1
2
3
2
3
只有自己注册的config 没有其他的Bean1 和 Bean2 是因为没有后置处理器处理去解析Config
我们给BeanFactory加载一些后置处理器
java
public class BeanFactoryMain {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 定义(class scope )BeanDefinition
AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(Config.class)
.getBeanDefinition();
// 注册bean
beanFactory.registerBeanDefinition("config", configBeanDefinition);
// 给 beanFactory 添加一些常用的后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("\t"+beanDefinitionName);
}
System.out.println("------------------------------");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
shell
## 打印结果
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
------------------------------
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
发现还是没有我们的Bean1 和 Bean2 是因为我们的后置处理器已经是Bean了 但是却没有工作
java
public class BeanFactoryMain {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 定义(class scope )BeanDefinition
AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(Config.class)
.getBeanDefinition();
// 注册bean
beanFactory.registerBeanDefinition("config", configBeanDefinition);
// 给 beanFactory 添加一些常用的后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 获取BeanFactory后置处理器 补充了Bean
Map<String, BeanFactoryPostProcessor> beansOfType =
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
// 执行后置处理器方法
beansOfType
.forEach((key, value) -> value.postProcessBeanFactory(beanFactory));
// 创建所有的单例Bean
beanFactory.preInstantiateSingletons();
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("\t"+beanDefinitionName);
}
System.out.println("------------------------------");
}
}
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
shell
# 打印结果
config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
bean1
bean2
------------------------------
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
但是我们Debug 发现Bean1 里的属性却是null,因为我们没有让我们的BeanPostProcessor 发挥作用
java
public class BeanFactoryMain2 {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// bean 定义(class scope )BeanDefinition
AbstractBeanDefinition configBeanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(Config.class)
.getBeanDefinition();
// 注册bean
beanFactory.registerBeanDefinition("config", configBeanDefinition);
// 给 beanFactory 添加一些常用的后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
// 获取Bean后置处理器 补充了Bean
Map<String, BeanFactoryPostProcessor> beansOfType =
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
// 执行后置处理器方法
beansOfType
.forEach((key, value) -> value.postProcessBeanFactory(beanFactory));
// Bean 后置处理器, 对bean 的生命周期各个阶段提供扩展 例如@Autowired
Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
// 添加后置处理器 getBean 的时候就会执行后置处理器
beanPostProcessorMap.values()
.forEach(beanFactory::addBeanPostProcessor);
// 创建所有的单例Bean
beanFactory.preInstantiateSingletons();
for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("\t"+beanDefinitionName);
}
System.out.println("------------------------------");
}
}
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
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
这个时候才发现我们的Bean1才正常。而ApplicationContext 和BeanFactory 不一样。
ApplicationContext
我们获取的ApplicationContext 都是通过设计模式中的组合模式将我们BeanFactory 当做属性加载进来。而通过ApplicationContext 获取Bean 也是通过其中的BeanFactory 去获取的。
java
public class GenericApplicationContext
extends AbstractApplicationContext
implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
}
1
2
3
4
5
6
7
2
3
4
5
6
7
java
public abstract class AbstractApplicationContext
extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(requiredType);
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
除去BeanFactory 还实现了EnvironmentCapable
,MessageSource
,ApplicationEventPublisher
,ResourcePatternResolver
MessageSource
MessageSource 是解决国际化的问题,我们在resource 创建3个文件
message.properties
shell
1
message_zh.properties
shell
user.login.username=用户名
user.login.password=密码
1
2
2
message_en.properties
shell
user.login.username=User name
user.login.password=Password
1
2
2
yaml
spring:
messages:
basename: messages
1
2
3
2
3
java
@SpringBootApplication
public class App {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args);
System.out.println(ctx.getMessage("user.login.password", null, Locale.CHINA));
System.out.println(ctx.getMessage("user.login.password", null, Locale.US));
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
ResourceLoader
加载文件使用的接口
java
@SpringBootApplication
public class App {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args);
// ResourceLoader
// 外部文件 file:
// classpath:
// 其他jar包 classpath*:
Resource resource = ctx.getResource("classpath:application.yml");
System.out.println(resource);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
EnvironmentCapable
环境属性的接口
java
@SpringBootApplication
public class App {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args);
// EnvironmentCapable
ConfigurableEnvironment environment = ctx.getEnvironment();
System.out.println(environment.getProperty("java_home"));
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
ApplicationEventPublisher
不解释使用的太多了