spring学习总结011 --- FactoryBean

FactoryBean是spring提供的一个接口,交由用户自己实现bean实例化方法,接口如下:

实例:

public class FactoryBeanInfo implements BeanNameAware {
    private int id;
    private String name;
    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}
@Component
public class MyFactoryBean implements FactoryBean<FactoryBeanInfo> {

    @Override
    public FactoryBeanInfo getObject() throws Exception {
        return FactoryBeanInfo.builder().id(1).name("bale").build();
    }

    @Override
    public Class<?> getObjectType() {
        return FactoryBeanInfo.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {FactoryBeanConfig.class})
public class FactoryBeanTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void test_factoryBean_base() {
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        log.info("Bean definition names:{}", Arrays.toString(beanDefinitionNames));

        FactoryBeanInfo factoryBeanInfo = applicationContext.getBean(FactoryBeanInfo.class);
        log.warn("Factory bean info:{}", factoryBeanInfo); // 没有拿到beanName
    }
}

运行结果:

[main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener, org.springframework.test.context.event.EventPublishingTestExecutionListener]
[main] INFO org.springframework.test.context.support.DefaultTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener@3c0ecd4b, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@14bf9759, org.springframework.test.context.support.DirtiesContextTestExecutionListener@5f341870, org.springframework.test.context.event.EventPublishingTestExecutionListener@553f17c]
[main] INFO com.demo.FactoryBeanTest - Bean definition names:[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, factoryBeanConfig, myFactoryBean]
[main] WARN com.demo.FactoryBeanTest - Factory bean info:FactoryBeanInfo(id=1, name=bale, beanName=null)

Process finished with exit code 0

有两个问题要分析:

1、FactoryBeanInfo很明显不是在容器创建的时候创建的,是在getBean的时候创建的,那么FactoryBeanInfo创建流程是什么?

2、FactoryBeanInfo明明实现了BeanNameAware接口,但是spring为什么没有为其填充beanName?

FactoryBeanInfo创建流程

主要的创建流程在AbstractBeanFactory#isTypeMatch方法和AbstractBeanFactory#getTypeForFactoryBean方法中:

总结起来就是:getBean过程中先获取已经解析好的bean定义,获取到beanNames,遍历beanNames,并获取bean实例;如果bean类型是FactoryBean,那么调用FactoryBean的getObjectType获取需要创建的bean的className;

接下来就是getBean ---> doGetBean很熟悉的流程;

需要注意的就是保证getObjectType和getObject返回的对象类型一致

实现了BeanNameAware接口,为什么没有为其填充beanName

接着上面的流程,doGetBean传入的参数beanName为MyFactoryBean,requiredType为FactoryBeanInfo:

因此先从单例池中拿到myBeanFactory实例,最终调用MyFactoryBean的getObject方法:

 所以,BeanNameAware未生效的原因为:FactoryBean中自定义Bean实例创建方法并未走createInstance --> populateBean  ---> initializeBean方法

posted @ 2020-07-14 16:44  光头用沙宣  阅读(204)  评论(0编辑  收藏  举报