美文网首页
Spring IOC - FactoryBean (不是Bean

Spring IOC - FactoryBean (不是Bean

作者: overflowedstack | 来源:发表于2020-05-02 21:51 被阅读0次
    1. 什么是FactoryBean

    在Spring IOC容器初始化时,很多地方有判断当前bean是否FactoryBean的逻辑,对FactoryBean和普通Bean有不同的处理。
    那么什么是FactoryBean呢?
    FactoryBean是一个接口,这个接口提供了下面几个方法。实现这个接口,可以让我们自定义Bean的创建过程。

    public interface FactoryBean<T> {
        @Nullable
        T getObject() throws Exception;
    
        @Nullable
        Class<?> getObjectType();
    
        default boolean isSingleton() {
            return true;
        }
    }
    
    2. Demo

    先来看一个demo。
    main 方法:

        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            MyFactoryBean myFactoryBean = (MyFactoryBean) context.getBean("&myFactoryBean");
            System.out.println(myFactoryBean);
            User user = (User) context.getBean("myFactoryBean");
            System.out.println(user);       
        }
    

    MyBeanFactory:

    @Component
    public class MyFactoryBean implements FactoryBean{
        @Override
        public Object getObject() throws Exception {
            // TODO Auto-generated method stub
            return new User();
        }
        @Override
        public Class getObjectType() {
            // TODO Auto-generated method stub
            return null;
        }
    }
    

    User:

    public class User {
    }
    

    AppConfig:

    @ComponentScan("io.github.dunwu.spring.core.bean.factorybean")
    public class AppConfig {
    }
    

    运行,输出如下:

    io.github.dunwu.spring.core.bean.factorybean.MyFactoryBean@38c5cc4c
    io.github.dunwu.spring.core.bean.factorybean.User@37918c79
    

    可以看到,当以&为前缀,去get bean的时候,返回的是MyFactoryBean对象。而不带这个前缀时,返回的是在factory bean中自定义创建的user bean。
    为什么会有这种结果呢,来看一下底层实现,一切就会变得明朗了。

    3. Spring容器初始化FactoryBean对象

    Spring容器初始化时,会扫描到myFactoryBean对象,并创建这个bean。
    在DefaultListableBeanFactory.preInstantiateSingletons() 中,会判断是否是factory bean,如果是,则对bean name加上前缀&,创建bean,并以myFactoryBean为key(去除前缀),将创建好的bean放进singletonObjects中。

                    if (isFactoryBean(beanName)) {
                        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                        //省略此处代码
                    } else {}
    

    后面从spring容器中get &myFactoryBean时,先通过beanName = transformedBeanName(name)去除前缀,以myFactoryBean为key,就能直接从singletonObjects中拿到已经创建好的factory bean。

    4. 通过FactoryBean创建自定义Bean

    当调用context.getBean("myFactoryBean")时,先通过getSingleton(beanName)拿到缓存的myFactoryBean。接下来getObjectForBeanInstance(sharedInstance, name, beanName, null)会最终调用如下逻辑:

            Object object = null;
            if (mbd == null) {
                object = getCachedObjectForFactoryBean(beanName);
            }
            if (object == null) {
                // Return bean instance from factory.
                FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
                // Caches object obtained from FactoryBean if it is a singleton.
                if (mbd == null && containsBeanDefinition(beanName)) {
                    mbd = getMergedLocalBeanDefinition(beanName);
                }
                boolean synthetic = (mbd != null && mbd.isSynthetic());
                object = getObjectFromFactoryBean(factory, beanName, !synthetic);
            }
    

    它会先从factoryBeanObjectCache里查看,是否已经有此bean的cache。

        /** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */
        private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
    

    如果没有,那么getObjectFromFactoryBean就会最终调用此factory bean的getObject方法,创建bean。

    5. 这不是BeanFactory

    虽然它们名字像,但是作用完全不一样!
    BeanFactory是个Factory,也就是IOC容器或对象工厂。在Spring中,BeanFactory是IOC容器的核心接口。

    6. 应用场景

    在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在<bean>中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑。

    相关文章

      网友评论

          本文标题:Spring IOC - FactoryBean (不是Bean

          本文链接:https://www.haomeiwen.com/subject/udgkghtx.html