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方法