前言
让我们继续讲解Spring的Bean实例化过程。在上一节中,我们已经讲解了Spring是如何将Bean定义加入到IoC容器中,并使用合并的Bean定义来包装原始的Bean定义。接下来,我们将继续讲解Spring的 getBean()
方法,特别是针对 FactoryBean
的解析。
在 getBean()
方法中,Spring还支持对 FactoryBean
进行特殊处理。FactoryBean
是一个能够生成Bean实例的工厂Bean,其定义了 getObject()
方法,返回的是一个由工厂Bean管理的对象实例。在使用 getBean()
方法获取 FactoryBean
类型的Bean时,Spring会首先获取 FactoryBean
的实例,然后调用其 getObject()
方法来获取由工厂Bean创建的实际Bean实例。
因此,在使用 getBean()
方法获取Bean实例时,我们需要注意是否需要对 FactoryBean
进行特殊处理。如果需要获取 FactoryBean
的实例而不是它所管理的对象实例,可以在Bean名称前加上 &
符号来进行标识。例如:&myFactoryBean
表示获取 myFactoryBean
的实例。但是博主看到第一篇源码写的篇幅确实有些长,可能对于大家伙的碎片化时间掌握的不是很充分,所以以后我会尽力控制篇幅长度,既保证逻辑的连续性也保证尽快可以看完,那么接下来开始进入正题getbean方法之FactoryBean解析。
FactoryBean
所有符合过滤条件的Bean在Spring解析后都会被转化为合并后的Bean定义。尽管Spring提供了 getBean()
方法用于获取Bean实例,但实际上它底层仍然使用 createBean()
方法来创建Bean实例。在创建Bean实例之前,Spring先对当前Bean定义进行判断,以确定其是否为 FactoryBean
类型:
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
// 获取合并后的BeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
// 获取FactoryBean对象
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
// 创建真正的Bean对象(getObject()返回的对象)
getBean(beanName);
}
}
}
else {
// 创建Bean对象
getBean(beanName);
}
}
}
// 所有的非懒加载单例Bean都创建完了后
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}
他的源码逻辑大致如下:
- Spring会根据
beanName
去bean
定义Map
中获取当前合并的Bean
定义。 - Spring会对当前
Bean
定义进行判断,包括判断当前Bean
是否为抽象的、是否为单例、是否懒加载,以及是否为FactoryBean
。如果是FactoryBean
,则会走FactoryBean
的创建逻辑,否则会走单例Bean
的创建逻辑。 - 当所有单例非懒加载的
Bean
创建完成后,Spring会遍历所有单例Bean
,判断其是否为SmartInitializingSingleton
类型。如果是,则会自动调用afterSingletonsInstantiated
方法。
isFactoryBean
由于创建 Bean
的逻辑比较复杂,其中包含了许多细节,因此,在这里我们特别提到了一个方法 isFactoryBean()
。之所以要提到这个方法,是因为Spring支持使用 FactoryBean
来创建复杂对象。下面是该方法的主要源码:
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
return (beanInstance instanceof FactoryBean);
}
// No singleton instance found -> check bean definition.
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
// No bean definition found in this factory -> delegate to parent.
return ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
}
return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
}
大致逻辑如下:
transformedBeanName
的作用是不管传入的参数是&×××
还是×××
,都返回×××
。这是因为Spring标记FactoryBean
时使用&×××
作为FactoryBean
的beanName
。getSingleton
方法从单例池中获取Bean
实例,如果该实例是FactoryBean
,则直接返回该实例。- 如果
BeanFactory
中的Bean
定义Map
中不包含该beanName
的Bean
定义,并且当前BeanFactory
的父BeanFactory
实现了ConfigurableBeanFactory
接口,那么就需要查看当前父BeanFactory
中是否有该实例,并且判断该实例是否为FactoryBean
。举个例子来说:
// 创建一个父Spring容器
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
parent.register(AppConfig.class);
parent.refresh();
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.setParent(parent);
applicationContext.register(AppConfig1.class);
applicationContext.refresh();
UserService bean = applicationContext.getBean(UserService.class);
bean.test();
- 如果并没有实例化出来的bean,那么对bean定义进行判断。
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
Boolean result = mbd.isFactoryBean;
if (result == null) {
// 根据BeanDefinition推测Bean类型(获取BeanDefinition的beanClass属性)
Class<?> beanType = predictBeanType(beanName, mbd, FactoryBean.class);
// 判断是不是实现了FactoryBean接口
result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
mbd.isFactoryBean = result;
}
return result;
}
注释也基本写好了,基本上就是根据BeanDefinition推测Bean类型(获取BeanDefinition的beanClass属性),再根据bean类型判断是不是实现了FactoryBean接口,然后返回判断结果。
SmartFactoryBean
在 getBean
方法中,我们可以获取 FactoryBean
的实例并返回。接下来的步骤是判断当前的 FactoryBean
是否实现了 SmartFactoryBean
接口。需要注意的是,SmartFactoryBean
是 FactoryBean
接口的一个子接口。虽然我们在实现 FactoryBean
接口时不必实现 SmartFactoryBean
接口,但是如果实现了 SmartFactoryBean
接口,那么在创建 FactoryBean
时就会调用 getObject
方法返回实例。正常情况下,只有当容器启动完成后才会调用 getObject
方法。如果我们想在初始化时就调用,可以这样实现:
@Component
public class UserFactory implements SmartFactoryBean {
@Override
public Object getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isEagerInit() {
return true;
}
}
欢迎大家加入编程交流群
Qt编程交流群 57634222
C++编程交流群 910854771
编程交流群 241531722