Spring IOC(5) Spring Bean的创建 上
到目前为止,Spring
源码中AbstractApplicationContext#refresh
方法的已经解读到第11个方法finishBeanFactoryInitialization
,前10个方法介绍了:
BeanFactory
的准备,创建,刷新,个性化BeanFactory
的扩展点,自定义属性解析;- 环境信息
Environment
的加载(包括环境变量、系统变量等); BeanDefinition
的加载,解析;BeanFactoryPostProcessor
的注册与执行流程,BeanDefinitionRegistryPostProcessor
的解析,ConfigurationClassPostProcessor
对Spring
注解的解析过程(@Component、@PropertySources、@PropertySource、@ComponentScans、@ComponentScan、@Import
等注解的解析)BeanPostProcessor
的注册流程;- 国际化,
Spring
事件驱动的加载执行过程;
在前面,通过注解或XML的方式解析生成了BeanDefinition
,接下来就是Spring最为核心的,根据BeanDefinition
实例化Bean,并且对Bean的属性进行依赖注入。
其中Spring给了我们众多的扩展点,也涉及到面试常问的点——循环依赖的问题,本章我们探讨较为简单的内容——Spring怎么实例化一个Bean,根据JavaSE
知识,我们知道实例化一个Bean 可以通过new or 反射的方式,Spring也不外呼这两种方式
前期准备
finishBeanFactoryInitialization
解析过程
1 | protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { |
这个方法的大致流程:
- 判断是否存在转换服务,有就设置,
Spring
转换器接口ConversionService
的默认实现是DefaultConversionService
,这个默认的转换器实现中,内置了很多的转换器 - 判断是否有内置的值解析器,没有就创建一个处理占位符的解析器
- 实例化
LoadTimeWeaverAware
,这里从容器中获取了AOP
的织入,如果有的话就开始进行早期的Bean
的创建 - 停止使用临时的类加载器
- 冻结
BeanDefinition
的元数据信息,防止被修改 - 开始实例化所有的单例bean对象
除了beanFactory.preInstantiateSingletons()
方法,其他都是Bean
创建的准备,接下来一个一个分析,首先是转换服务的设置。
Bean 的创建步骤
在Spring
源码中对Bean
的创建遵循一个步骤就是:getBean
–> doGetBean
–> createBean
–> doCreateBean
,常规的Bean
的创建过程都是按照这个步骤执行,然后反射实例化,属性填充,初始化,放到一级缓存中。那么非常规的有可能就不遵循这个步骤,比如FactoryBean
,InstantiationAwareBeanPostProcessor
等。
DefaultListableBeanFactory
#preInstantiateSingletons
1 |
|
Spring
前期解析bean后解析 出来的BeanDefinition
放入两个集合BeanDefinitionMap
和BeanDefinitionNames
,这里遍历的是BeanDefinitionNames
这个集合,存放的是beanName
。
进行了BeanDefinition
的合并处理,最终返回的全是RootBeanDefinition
1 | protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { |
FactoryBean
FactoryBean
是用来创建Bean
对象的,他是一个接口,方法:
getObject
获取bean对象getObjectType
获取bean的类型isSingleton
是否是单例的,默认是true
在创建对象时,你可以直接在getObject
方法中进行new
,或者反射,或者是其他都可以,非常的灵活。
1 | public class MyFactoryBean implements FactoryBean<MyUser> { |
FactoryBean
创建Bean
的时候,如果xml
注册的是一个FactoryBean
的实现,但是获取出来又是具体的MyUser
对象,这里Spring
使用了懒加载的机制,在Spring
对Bean
进行初始化时,实际上只将FactoryBean
的实现类注册到了Spring
容器中,当我们需要使用的时候,才去判断,如果是FactoryBean
类型的,那么就去调用getObject
方法去创建对象。如果是第二次去获取Bean
,那么是从缓存中获取的,如果是获取&
前缀的Bean
,那就直接返回。
BeanFactory 和FactoryBean 的区别?
BeanFactory
是一个Bean
的创建工厂,比如AbstractApplicationContext
就是BeanFactory
的实现类,这个类就是用来创建Bean
的,创建出来的Bean
放在缓存中。
FactoryBean
就是Bean
实例,是由BeanFactory
创建的,并且FactoryBean
也是用来创建Bean
对象,使用getObject
方法进行创建,也是会放在缓存中供下次直接获取,而且如果在使用时需要使用FactoryBean
的实例时需要以&
前缀才能获取到,比如getBean("&myFactoryBean");
如果是获取通过getObject
方法创建的对象时,就不需要添加&
前缀,比如getBean("myFactoryBean");
相同点:
- 都是用来创建对象的
- 都是创建出来之后放入缓存中供下次直接使用
不同点:
BeanFactory
是一个对象创建工厂,而FactoryBean
是一个Bean
实例BeanFactory
创建的对象一般来说都是使用反射调用构造函数创建的,而FactoryBean
创建对象是调用getObject
方法创建,并且创建方式不一定是通过反射,可以是直接new
对象或者其他方式FactoryBean
在获取对象时,可以获取到两个对象,一个是存放在BeanFactory
创建的缓存中,通过&beanName
获取的FactoryBean
的实现类对象,一个是调用getObject
创建的,通过beanName
获取的具体对象。

单例Bean的创建
在创建时会调用getBean
,然后doGetBean
,一般来说在Spring
中只要是do
开头方法基本就是真正干活的方法
1 | protected <T> T doGetBean( |
去掉不重要的代码,可以看到首先是从缓存中获取,如果没有获取到就进行一些列检查,最终检查是否单例的Bean
,此时这里的缓存为singletonObjects
被称为一级缓存 是一个ConcurrentHashMap
key是bean的名称
1 | protected Object getSingleton(String beanName, boolean allowEarlyReference) { |
如果是,那么就会调用getSingleton
方法,传入一个beanName
,一个ObjectFactory
的lambda
表达式,表达式中有个createBean
方法,这个方法就是创建的Bean
方法。
1 | sharedInstance = getSingleton(beanName, () -> { |
执行lambda
表达式的具体方法时执行createBean
1 | public interface ObjectFactory<T> { |
getSingleton
1 | public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { |
我们可以发现这个getSingleton
方法,功能是,如果当前bean在单例池没有,那么调用ObjectFactory
的getObject
方法获取,在外层其实调用了createBean
方法,让我们来看看createBean
createBean
这个方法其实是在AbstractAutowireCapableBeanFactory
中实现( DefaultListableBeanFactory
的父类)AbstractAutowireCapableBeanFactory
的定位是一个提供 bean 创建(使用构造函数解析)、属性填充、和初始化的BeanFactory
1 | protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) |
首先是进行了Bean
的类型的解析,主要是用于后面的反射创建对象时使用,并设置到RootBeanDefinition
中,然后进行方法覆盖操作。在里面遇到了重要bean的提前初始化,由resolveBeforeInstantiation
实现。
提前初始化
这是spring给我们的一个扩展点。让对象可以提前创建,而不用再继续走doCreateBean
方法里面的复杂逻辑,这样的话就提供给用户能够自己控制对象的创建过程以及执行增强等操作。
源码实现
1 | protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) { |
InstantiationAwareBeanPostProcessor
是具备实例化感知能力的bean后置处理器,这里重点在于postProcessBeforeInstantiation
和 postProcessAfterInitialization
方法。
注意Instantiation 和 Initialization 的区别,前者是实例化(反射生成bean对象,任何属性都没有赋值,生成对象叫实例化)后者是初始化(属性赋值,初始化方法调用叫初始化)

applyBeanPostProcessorsBeforeInstantiation
提供我们自己定一个bean,而不是spring帮我们反射生成bean的扩展,后续spring不会帮我们进行依赖注入applyBeanPostProcessorsAfterInitialization
提供对bean进行代理的扩展,初始化后,我们可以对这个bean进行代理
使用
需要提前实例化的对象
1
2
3
4
5
6
public class MyBeforeInstantiation {
public void beforeInvoke(){
System.out.println("提前实例化,开始执行业务....");
}
}InstantiationAwareBeanPostProcessor
的实现类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
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessBeforeInstantiation 方法");
// 提前进行实例化
if (beanClass == MyBeforeInstantiation.class) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setCallback(new MyMethodInterceptor());
Object obj = enhancer.create();
System.out.println("创建对象:" + obj);
return obj;
}
return null;
}
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessAfterInstantiation 方法");
return false;
}
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessProperties 方法");
return pvs;
}
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessBeforeInitialization 方法");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "执行了 postProcessAfterInitialization 方法");
return bean;
}
}使用了CGLIB 动态代理去增强创建代理对象,编写一个回调拦截器:
1
2
3
4
5
6
7
8
9public class MyMethodInterceptor implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("方法执行前:"+method);
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("方法执行后:"+method);
return o1;
}
}测试
1
2
3ApplicationContext ac = new AnnotationConfigApplicationContext(Context.class);
MyBeforeInstantiation bean = ac.getBean(MyBeforeInstantiation.class);
bean.beforeInvoke();
结果
1 | ... |
里只执行了两个方法,一个是postProcessBeforeInstantiation
,是InstantiationAwareBeanPostProcessor
的前置实例化接口,一个是postProcessAfterInitialization
,是BeanPostProcessor
的后置实例化接口。
doCreateBean
如果前面的InstantiationAwareBeanPostProcessor
没有返回一个bean 那么接下来就是spring容器为我们生成这个bean。
1 | protected Object doCreateBean(String beanName, RootBeanDefinition mbd, Object[] args) |
这里会先从缓存中获取FactoryBean
实例化的对象,如果有就进行下面的逻辑,一般来说基本是获取不到的,来看 createBeanInstance
createBeanInstance
1 | protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args){ |
这里有2个扩展点,分别是2个return,意味着只要获取到Bean
,那么就不需要进行下一步的执行
obtainFromSupplier
这里先用getInstanceSupplier
获取Supplier,是BeanDefinition
的方法,在解析BeanFactoryPostProcessor
时可以进行BeanDefinition
的处理。而在BeanFactoryPostProcessor
接口注册和执行的时候,完全是可以自己定义一个BeanFactoryPostProcessor
进行扩展实现。
这个属性位于AbstractBeanDefinition
类中,一般来说用户自定义的BeanDefinition
都是GenericBeanDefinition
,而GenericBeanDefinition
是继承这个抽象类的,所以我们在进行BFPP
扩展实现时可以对GenericBeanDefinition
设置这个属性值,这个属性值是一个Supplier
函数式接口,相当于lambda
表达式的用法,接下来自己实现一个验证一下。
创建一个
SupplierUser
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
public class SupplierUser {
private String username;
public SupplierUser() {
}
public SupplierUser(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String toString() {
return "SupplierUser{" +
"username='" + username + '\'' +
'}';
}
}创建一个创建
SupplierUser
的类1
2
3
4
5public class CreateSupplier {
public static SupplierUser createUser(){
return new SupplierUser("redwinter");
}
}创建BFPP的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class SupplierBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("supplierUser");
// 获取原生的BeanDefinition
GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) beanDefinition;
// 实例化Supplier
genericBeanDefinition.setInstanceSupplier(CreateSupplier::createUser);
// 设置类型
genericBeanDefinition.setBeanClass(CreateSupplier.class);
}
}测试类
1
2
3
4
5
6
public void SupplierBeanTest(){
ApplicationContext ac = new AnnotationConfigApplicationContext(Context.class);
SupplierUser bean = ac.getBean(SupplierUser.class);
System.out.println(bean);
}结果
1
SupplierUser{username='redwinter'}
FactoryMethod 对象的创建
这也是一个扩展点,根据源码可以看出这个属性也是在BeanDefinition
中的,但是这个可以通过标签的方式进行设置,在Spring
中factory-method
创建Bean
有两种方式,一种是静态工厂创建,一种是实例工厂创建。
目前创建bean的几种方式:
- 使用FactoryBean创建
- 使用InstantiationAwreBeanPostProcessor的前置实例化方法postProcessBeforeInstantiation进行创建
- 使用Supplier进行创建
- 使用factory-method标签进行创建
- 实例工厂创建(配合factory-bean标签)
- 静态工厂创建
- 反射创建(常规的,完整的创建流程)
下一篇继续介绍Bean
的创建流程。
参考
https://www.cnblogs.com/redwinter/p/16241328.html