zoukankan      html  css  js  c++  java
  • 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方法

  • 相关阅读:
    python note 30 断点续传
    python note 29 线程创建
    python note 28 socketserver
    python note 27 粘包
    python note 26 socket
    python note 25 约束
    Sed 用法
    python note 24 反射
    python note 23 组合
    python note 22 面向对象成员
  • 原文地址:https://www.cnblogs.com/sniffs/p/13299716.html
Copyright © 2011-2022 走看看