,否则会走单例 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;
}
}
结语
FactoryBean 和 BeanFactory 是两个不同的概念。前者是一个接口,我们可以在实现该接口时通过调用 getObject
方法来返回实例,同时 FactoryBean
本身也是一个实例。后者是 Spring 容器的工厂,通过其中的 bean
定义 Map
一个一个地实例化我们通过注解等方式注入进去的 bean
工厂。在判断 FactoryBean
时,如果当前 B