注意:前面学习了ComponentsIndex机制,在学习本文前请把META-INF/spring.components这个文件里面的内容删除或者注释,否则会有影响。
这个文件本质是一个properties的格式,所以可以用#注释,Java原生方法读取会忽略被注释的行。
为什么先学习FactoryBean?
之前我们分析了BeanDefinition的扫描,入口是org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors此方法,当然此方法还会解析@Bean、@Import这个我们还没有分析,总之经过这一步可以获取到一堆的BeanDefinition。后面有个步骤就会真的去创建Bean了,具体的方法就在下面的finishBeanFactoryInitialization方法,这个方法会创建非懒加载的单例Bean。
finishBeanFactoryInitialization方法的最后会执行preInstantiateSingletons方法,这个方法里面我们先跳过多线程创建Bean(这个是Spring6的新特性,后面单独学习),就直接到了instantiateSingleton方法,可以在这里打个断点,看看调用链路。而instantiateSingleton方法里面就会有FactoryBean的概念了,FactoryBean可能理解成一种特殊的Bean,但不管是普通Bean还是FactoryBean,最终都会调用getBean()方法。getBean方法其实就是Bean生命周期的入口,这个方法我们在测试代码里也调用了。所以,我先要学习FactoryBean。
FactoryBean使用
@Component
public class MyFactoryBean implements FactoryBean<User> { // &myFactoryBean:MyFactoryBean对象 myFactoryBean:User对象
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}最好加上泛型,JDK21会增加校验
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println(applicationContext.getBean("&myFactoryBean")); // MyFactoryBean对象
System.out.println(applicationContext.getBean("myFactoryBean")); // User对象
}
}getBean("myFactoryBean")对应的是 User对象
getBean("&myFactoryBean")对应的是 MyFactoryBean对象
这个地方相当于使用@Component注册了一个MyFactoryBean,但值得一提的是,这上过程中BeanDefinition只生成了一个,其实就是之前分析的BeanDefinition的扫描过程就是把MyFactoryBean扫描到了,至于如何产生MyFactoryBean和User两个Bean的,看下面的源码分析就会明白。
源码初步调试
下面我们通过断点调试来分析FactoryBean的底层原理:

这里可以看下this里面的beanDefinitionMap,确实只有一个myFactoryBean对应的BeanDefinition
接着调试isFactoryBean方法:

再进入

反正第一次会进入if判断,看下断点的调用链路就知道了(这里会调用很多次)。我们只看关键的判断:FactoryBean.class.isAssignableFrom(beanType)。
我们还是回到外层方法看看:
private void instantiateSingleton(String beanName) {
// 根据beanName判断是不是FactoryBean,会根据beanName找到BeanDefinition,从而找到对应类型,从而进行判断
if (isFactoryBean(beanName)) {
// 创建FactoryBean本身
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// 创建FactoryBean中的getObject()方法返回的Bean
if (bean instanceof SmartFactoryBean<?> smartFactoryBean && smartFactoryBean.isEagerInit()) {
// 调用FactoryBean的getObject()
getBean(beanName);
}
}
else {
getBean(beanName);
}
}这里有个smartFactoryBean接口,我们先介绍一下。
SmartFactoryBean
SmartFactoryBean继承了FactoryBean,多提供了一个isEagerInit方法,就类似于饿汉模式。结合上面的源码,其实也很容易理解,就是如果个isEagerInit方法返回true,容器启动时就会将getObject方法返回的对象放入容器作为Bean。
@Component
public class MyFactoryBean implements SmartFactoryBean<User> { // &myFactoryBean:MyFactoryBean对象 myFactoryBean:User对象
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isEagerInit() {
return true;
}
}通过调试猜测FactoryBean的getBean工作原理
代码如下:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
User user = applicationContext.getBean("myFactoryBean", User.class); // 断点1
System.out.println(user); // 断点2
}
}@Component
public class MyFactoryBean implements FactoryBean<User> { // &myFactoryBean:MyFactoryBean对象 myFactoryBean:User对象
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return User.class;
}
}@ComponentScan
public class MyConfig {
@Bean
public ConversionServiceFactoryBean conversionService() {
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToUserConverter()));
return conversionServiceFactoryBean;
}
}这里我故意搞了一个前面学习过程中的代码,刚好是一个FactoryBean
断点调试:

beanDefinitionMap确实只有一个myFactoryBean。再通过底层容器,看看单例池的内容:

这里就要注意了,单例池中还是myFactoryBean对应MyFactoryBean类型,也就是说看起来和普通的没有区别。但是上面还有一个factoryBeanObjectCache缓存,它里面刚刚好有一个我们配置类配置的ConversionServiceFactoryBean。
接着我们代码往下走一步:

缓存池中多了一个myFactoryBean对应的类型是User。
这里直接说大概的工作原理:对于普通bean,getBean方法就直接返回对应的对象,但是对于FactoryBean,会查那个缓存返回。
getBean源码分析
/*
org.springframework.beans.factory.support.DefaultListableBeanFactory#instantiateSingleton -->
org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String) -->
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean -->
org.springframework.beans.factory.support.AbstractBeanFactory#transformedBeanName(此方法有一个循环处理&) -->
假设sharedInstance不为null -->
org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance -->
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean -->
org.springframework.beans.factory.support.FactoryBeanRegistrySupport#doGetObjectFromFactoryBean 调用factory.getObject
*/
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 传进来的是&test,那么直接返回当前beanInstance
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
if (!(beanInstance instanceof FactoryBean)) {
// 这个相当于你估计把一个不是FactoryBean的去获取的一个检查,如 &userService
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
mbd.isFactoryBean = true;
}
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
return beanInstance;
}
Object object = null;
if (mbd != null) {
mbd.isFactoryBean = true;
}
else {
// 从factoryBeanObjectCache中拿到getObject()方法中的对象
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 调用getObject()方法并缓存到factoryBeanObjectCache中
object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic);
}
return object;
}
// 总结:相当于先给你把&干了,直接获取myFactoryBean本身这个bean,然后再判断如果名称前第一个字符是&,就直接返回myFactoryBean。
// 如果不是FactoryBean,最普通的情况,如getBean("userService"),也是直接返回。
// 如果名称前没有&,并且是FactoryBean,那么就会先从缓存factoryBeanObjectCache中拿,拿到就返回
// 拿不到就走org.springframework.beans.factory.support.FactoryBeanRegistrySupport#getObjectFromFactoryBean创建,并放入缓存,并返回总结
Spring容器启动时,只会先创建MyFactoryBean,并且缓存到单例池,key为"myFactoryBean",然后在getBean("myFactoryBean")的时候,才会调用MyFactoryBean的getObject()方法,并将返回的对象缓存在factoryBeanObjectCache中。
FactoryBean有一个子接口SmartFactoryBean,它额外有一个属性eagerInit,可以用来控制需不需要在Spring容器启动时直接调用getObject()方法把具体的对象创建出来并缓存到Spring容器中。
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
System.out.println(applicationContext.getBean("&myFactoryBean")); // myFactoryBean
System.out.println(applicationContext.getBean("myFactoryBean")); // user
System.out.println(applicationContext.getBean("userService")); // userService
System.out.println(applicationContext.getBean("&userService")); // 报错
}
}工作原理总结:
先去掉名称的&,从单例池获取bean,再:
判断名称是否以&开头,如果是,则判断是不是FactoryBean,不是就报错,是就直接返回
如果名称不是否以&开头,并且不是FactoryBean,则返回(通常的普通Bean的情况)
如果不是否以&开头,并且是FactoryBean类型,就要走factoryBeanObjectCache缓存或者调用getObject创建了(通常第一次getBean时要创建,不考虑实现SmartFactroyBean的情况)