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

  • 相关阅读:
    【JAVA并发编程实战】7、日志服务
    【JAVA并发编程实战】6、中断
    【JAVA并发编程实战】5、构建高效且可伸缩的结果缓存
    【JAVA并发编程实战】4、CountDownLatch
    【JAVA并发编程实战】3、同步容器
    【JAVA并发编程实战】2、对象的组合
    【JAVA并发编程实战】1、对象的共享
    【Effective Java】12、避免过度同步
    【Effective Java】11、同步访问共享的可变数据
    【Effective Java】10、java注解使用
  • 原文地址:https://www.cnblogs.com/sniffs/p/13299716.html
Copyright © 2020-2023  润新知