📓 Archive

  • Pricing
  • Chess
  • Syntax
  • 01_FACTORY_BEAN

    FGJ: Create:2024/06/27 Update: (2024-10-24)

    • Intro(FactoryBean) #

      spring.version = 4.3.7.RELEASE

      • 准备编码 #

        // 创建普通bean
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        public class Tool {
        
            private int id;
        
        }
        
        // 创建工厂
        @Data
        public class ToolFactory implements FactoryBean<Tool> {
        
            private int factoryId;
        
            private int toolId;
        
            @Override
            public Tool getObject() throws Exception {
                return new Tool(toolId);
            }
        
            @Override
            public Class<?> getObjectType() {
                return Tool.class;
            }
        
            @Override
            public boolean isSingleton() {
                return false;
            }
        }
        
        <!-- factory-bean.xml -->
        
        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        
            <!-- FactoryBean work process -->
            <bean id="toolFB" class="_framework.spring.factory_bean.beans.ToolFactory">
                <property name="factoryId" value="9090" />
                <property name="toolId" value="2" />
            </bean>
        
        </beans>
        
        public class SpringFactoryBeanTest {
        
            public static void main(String[] args) {
        
                ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("_framework/spring/res/factory-bean.xml");
                ToolFactory fb = applicationContext.getBean("&toolFB", ToolFactory.class);
                Tool tool1 = applicationContext.getBean(Tool.class);
                Tool tool2 = applicationContext.getBean(Tool.class);
                System.out.println();
                applicationContext.destroy();
        
            }
        
        }
        
      • 解析流程 #

        1). 初始化bean对象:在refresh()里面通过obtainFreshBeanFactory()方法创建扫描到beanDefinition的顶级工厂。然后通过方法finishBeanFactoryInitialization(beanFactory);实例化所有非懒加载的所有单例bean,此处就包含这个工厂bean对象。

        @Override
        public void preInstantiateSingletons() throws BeansException {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Pre-instantiating singletons in " + this);
            }
        
            // Iterate over a copy to allow for init methods which in turn register new bean definitions.
            // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
            List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
        
            // Trigger initialization of all non-lazy singleton beans...
            for (String beanName : beanNames) {
                RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                    if (isFactoryBean(beanName)) {
                        // 此处进行工厂bean对象构造。就是类似于正常bean的创建。
                        final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                        boolean isEagerInit;
                        if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                            isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                                @Override
                                public Boolean run() {
                                    return ((SmartFactoryBean<?>) factory).isEagerInit();
                                }
                            }, getAccessControlContext());
                        }
                        else {
                            isEagerInit = (factory instanceof SmartFactoryBean &&
                                    ((SmartFactoryBean<?>) factory).isEagerInit());
                        }
                        if (isEagerInit) {
                            getBean(beanName);
                        }
                    }
                    else {
                        getBean(beanName);
                    }
                }
            }
            ...
        }
        

        2). 手动通过容器进行获取:例如ToolFactory fb = applicationContext.getBean("&toolFB", ToolFactory.class);注意要获取工厂对象得加工厂名前缀,不然的话,指定类型就是报错,没有指定ToolFactory.class类型的话就是获取到工厂对象产生的Tool对象。下面会通过代码解释。

        首先通过getBean(名字,类型)调用的时候会进入到doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 方法。
        方法内部通过transformedBeanName(name);将传入的带&符号前缀的name 转换成不带&的。
        然后获取通过beanName获取在第一步中创建的工厂bean的实例。
        发现实例非null之后进入到getObjectForBeanInstance(sharedInstance, name, beanName, null);这个方法里面。这个方法里面决定返回工厂对象ToolFactoryBean还是通过工厂创建的对象Tool。

        Caution

        1). 如果是applicationContext.getBean("toolFB", ToolFactory.class);这种情况,则下面方法最后判断之前获取到的是Tool对象,因为咱们指定了ToolFactoryBean.class类型。所以会报错。
        2). 如果没有指定类型:applicationContext.getBean("toolFB"); 则获取Tool对象,并不是工厂bean。

        protected <T> T doGetBean(
        	final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        	throws BeansException {
        
            final String beanName = transformedBeanName(name);
            Object bean;
        
            // Eagerly check singleton cache for manually registered singletons.
            Object sharedInstance = getSingleton(beanName);
            if (sharedInstance != null && args == null) {
                if (logger.isDebugEnabled()) {
                    if (isSingletonCurrentlyInCreation(beanName)) {
                        logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                                "' that is not fully initialized yet - a consequence of a circular reference");
                    }
                    else {
                        logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
                    }
                }
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }
        
            ...
        
            // Check if required type matches the type of the actual bean instance.
            if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
                try {
                    return getTypeConverter().convertIfNecessary(bean, requiredType);
                }
                catch (TypeMismatchException ex) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Failed to convert bean '" + name + "' to required type '" +
                                ClassUtils.getQualifiedName(requiredType) + "'", ex);
                    }
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                }
            }
            return (T) bean;
        }
        

        3). 进入到getObjectForBeanInstance方法以后:

        3.1 先判断 如果想获取工厂bean对象,但是获取到的示例类型并不属于FactoryBean的话报一个异常。
        3.2 然后接着判断,如果是普通对象直接返回,或者name中包含&也直接返回。这就是获取factoryBean对象要加&的原因。
        3.3 要继续往下走的话,就是属于工厂对象,但是name不包含前缀&.也就是通过getObjectFromFactoryBean获取factorybean对象要创建的对象。

        protected Object getObjectForBeanInstance(
        	Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
        
            // Don't let calling code try to dereference the factory if the bean isn't a factory.
            if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
                throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
            }
        
            // Now we have the bean instance, which may be a normal bean or a FactoryBean.
            // If it's a FactoryBean, we use it to create a bean instance, unless the
            // caller actually wants a reference to the factory.
            if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
                return beanInstance;
            }
        
            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);
            }
            return object;
        }
        

        4). 通过Tool tool1 = applicationContext.getBean(Tool.class);获取需要通过工厂创建的bean对象解析。
        通过debug会进入到getBeanNamesForType(Tool.class)方法。
        并且在isTypeMatch中通过getTypeForFactoryBean((FactoryBean<?>) beanInstance);匹配到了。将刚才的beanName:toolFB返回。
        然后在resolveNamedBean中通过getBean(“toolFB”, Tool.class, args),继续获取bean。此时就会进入到3.3的情况中。通过工厂bean实例创建对象,并且返回。

        private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
            List<String> result = new ArrayList<String>();
        
            // Check all bean definitions.
            for (String beanName : this.beanDefinitionNames) {
                // Only consider bean as eligible if the bean name
                // is not defined as alias for some other bean.
                if (!isAlias(beanName)) {
                    try {
                        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                        // Only check bean definition if it is complete.
                        if (!mbd.isAbstract() && (allowEagerInit ||
                                ((mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading())) &&
                                        !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
                            // In case of FactoryBean, match object created by FactoryBean.
                            boolean isFactoryBean = isFactoryBean(beanName, mbd);
                            BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
                            boolean matchFound =
                                    (allowEagerInit || !isFactoryBean ||
                                            (dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
                                    (includeNonSingletons ||
                                            (dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
                                    isTypeMatch(beanName, type);
                            if (!matchFound && isFactoryBean) {
                                // In case of FactoryBean, try to match FactoryBean instance itself next.
                                beanName = FACTORY_BEAN_PREFIX + beanName;
                                matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
                            }
                            if (matchFound) {
                                result.add(beanName);
                            }
                        }
                    }
                    ...
                }
            }
            ...
            return StringUtils.toStringArray(result);
        }
        
      • 总结 #

    • Reference #


    comments powered by Disqus