【Spring源码分析】原型Bean实例化过程、byName与byType及FactoryBean获取Bean源码实现

摘要

之前的文章,分析了非懒加载的单例Bean整个加载过程,除了非懒加载的单例Bean之外,Spring中还有一种Bean就是原型(Prototype)的Bean。

原型Bean加载过程

之前的文章,分析了非懒加载的单例Bean整个加载过程,除了非懒加载的单例Bean之外,Spring中还有一种Bean就是原型(Prototype)的Bean,看一下定义方式:

<?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-3.0.xsd">

    <bean id="prototypeBean" class="org.xrq.action.PrototypeBean" scope="prototype"  />
    
</beans>

原型Bean加载流程总得来说和单例Bean差不多,看一下不同之处,在AbstractBeanFactory的doGetBean的方法的这一步:

else if (mbd.isPrototype()) {
    // It's a prototype -> create a new instance.
    Object prototypeInstance = null;
    try {
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        afterPrototypeCreation(beanName);
    }
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}

第6行createBean是一样的,原型Bean实例化的主要区别就在于第6行,它是直接创建bean的,而单例bean我们再对比一下:

if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, new ObjectFactory() {
        public Object getObject() throws BeansException {
            try {
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                // Explicitly remove instance from singleton cache: It might have been put there
                // eagerly by the creation process, to allow for circular reference resolution.
                // Also remove any beans that received a temporary reference to the bean.
                destroySingleton(beanName);
                throw ex;
            }
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

它优先会尝试getSington,即先尝试从singletonObjects中获取一下bean是否存在,如果存在直接返回singletonObjects中的bean对象。

接着,我们看到原型bean创建和单例bean创建的区别还在于第5行和第9行,先看第5行的代码:

protected void beforePrototypeCreation(String beanName) {
    Object curVal = this.prototypesCurrentlyInCreation.get();
    if (curVal == null) {
        this.prototypesCurrentlyInCreation.set(beanName);
    }
    else if (curVal instanceof String) {
        Set<String> beanNameSet = new HashSet<String>(2);
        beanNameSet.add((String) curVal);
        beanNameSet.add(beanName);
        this.prototypesCurrentlyInCreation.set(beanNameSet);
    }
    else {
        Set<String> beanNameSet = (Set<String>) curVal;
        beanNameSet.add(beanName);
    }
}

这段主要是说bean在创建前要把当前beanName设置到ThreadLocal中去,其目的是保证多线程不会同时创建同一个bean。接着看第9行的代码实现,即bean创建之后做了什么:

protected void afterPrototypeCreation(String beanName) {
    Object curVal = this.prototypesCurrentlyInCreation.get();
    if (curVal instanceof String) {
        this.prototypesCurrentlyInCreation.remove();
    }
    else if (curVal instanceof Set) {
        Set<String> beanNameSet = (Set<String>) curVal;
        beanNameSet.remove(beanName);
        if (beanNameSet.isEmpty()) {
            this.prototypesCurrentlyInCreation.remove();
        }
    }
}

很好理解,就是把当前bean移除一下,这样其它线程就可以创建bean了。第11行的代码不看了,意思是如果bean是FactoryBean的实现类的话,调用getObject()方法获取真正的对象。

byName源码实现

Spring有为开发者提供Autowire(自动装配)的功能,自动装配最常用的就是byName和byType这两种属性。由于自动装配是为了解决对象注入导致的<property>过多的问题,因此很容易找到byName与byType的Spring源码实现应该在属性注入这一块,定位到属性注入的代码AbstractAutowireCapableBeanFactory的populateBean方法,直接截取重点:

if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
        mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
    MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

    // Add property values based on autowire by name if applicable.
    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
        autowireByName(beanName, mbd, bw, newPvs);
    }

    // Add property values based on autowire by type if applicable.
    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
        autowireByType(beanName, mbd, bw, newPvs);
    }

    pvs = newPvs;
}

看到第6行~第8行判断是否byName形式,是就执行byName自动装配代码;第11行~第13行判断是否byType形式,是就执行byType自动装配代码。那么首先看一下第7行的byName代码实现:

protected void autowireByName(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        if (containsBean(propertyName)) {
            Object bean = getBean(propertyName);
            pvs.add(propertyName, bean);
            registerDependentBean(propertyName, beanName);
            if (logger.isDebugEnabled()) {
                logger.debug("Added autowiring by name from bean name '" + beanName +
                        "' via property '" + propertyName + "' to bean named '" + propertyName + "'");
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
                        "' by name: no matching bean found");
            }
        }
    }
}

篇幅问题,代码不一层层跟了,逻辑梳理一下:

  • 第4行,找到Bean中不是简单属性的属性,这句话有点绕,意思就是找到属性是对象类型的属性,但也不是所有的对象类型都会被找到,比如CharSequence类型、Number类型、Date类型、URL类型、URI类型、Locale类型、Class类型就会忽略,具体可见BeanUtils的isSimpleProperty方法
  • 第5行~第7行,遍历所有被找到的属性,如果bean定义中包含了属性名,那么先实例化该属性名对应的bean
  • 第9行registerDependentBean,注册一下当前bean的依赖bean,用于在某个bean被销毁前先将其依赖的bean销毁

其余代码都是一些打日志的,没什么好说的。

byType源码实现

上面说了byName的源码实现,接下来看一下byType源码实现:

protected void autowireByType(
        String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {

    TypeConverter converter = getCustomTypeConverter();
    if (converter == null) {
        converter = bw;
    }

    Set<String> autowiredBeanNames = new LinkedHashSet<String>(4);
    String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
    for (String propertyName : propertyNames) {
        try {
            PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
            // Don't try autowiring by type for type Object: never makes sense,
            // even if it technically is a unsatisfied, non-simple property.
            if (!Object.class.equals(pd.getPropertyType())) {
                MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
                // Do not allow eager init for type matching in case of a prioritized post-processor.
                boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
                DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
                Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
                if (autowiredArgument != null) {
                    pvs.add(propertyName, autowiredArgument);
                }
                for (String autowiredBeanName : autowiredBeanNames) {
                    registerDependentBean(autowiredBeanName, beanName);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
                                propertyName + "' to bean named '" + autowiredBeanName + "'");
                    }
                }
                autowiredBeanNames.clear();
            }
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
        }
    }
}

前面一样,到第10行都是找到Bean中属性是对象类型的属性。

接着就是遍历一下PropertyName,获取PropertyName对应的属性描述,注意一下16行的判断及其对应的注释:不要尝试自动装配Object类型,这没有任何意义,即使从技术角度看它是一个非简单的对象属性

第18行~第20行跳过(没有太明白是干什么的),byType实现的源码主要在第21行的方法resolveDependency中,这个方法是AbstractAutowireCapableBeanFactory类的实现类DefaultListableBeanFactory中的方法:

public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
    Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException  {

    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    if (descriptor.getDependencyType().equals(ObjectFactory.class)) {
        return new DependencyObjectFactory(descriptor, beanName);
    }
    else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) {
        return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName);
    }
    else {
        return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter);
    }
}

这里判断一下要自动装配的属性是ObjectFactory.class还是javaxInjectProviderClass还是其他的,我们装配的是其他的,看一下12行的代码实现:

protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
    Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException  {

    Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
    if (value != null) {
        if (value instanceof String) {
            String strVal = resolveEmbeddedValue((String) value);
            BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
            value = evaluateBeanDefinitionString(strVal, bd);
        }
        TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
        return converter.convertIfNecessary(value, type);
    }

    if (type.isArray()) {
        ...
    }
    else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
        ...
    }
    else if (Map.class.isAssignableFrom(type) && type.isInterface()) {
        ...
    }
    else {
        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
        if (matchingBeans.isEmpty()) {
            if (descriptor.isRequired()) {
                raiseNoSuchBeanDefinitionException(type, "", descriptor);
            }
            return null;
        }
        if (matchingBeans.size() > 1) {
            String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
            if (primaryBeanName == null) {
                throw new NoSuchBeanDefinitionException(type, "expected single matching bean but found " +
                        matchingBeans.size() + ": " + matchingBeans.keySet());
            }
            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(primaryBeanName);
            }
            return matchingBeans.get(primaryBeanName);
        }
        // We have exactly one match.
        Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(entry.getKey());
        }
        return entry.getValue();
    }
}

第四行结果是null不看了,为了简化代码Array装配、Collection装配、Map装配的代码都略去了,重点看一下普通属性的装配。首先是第25行获取一下自动装配的候选者:

protected Map<String, Object> findAutowireCandidates(
    String beanName, Class requiredType, DependencyDescriptor descriptor) {

    String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this, requiredType, true, descriptor.isEager());
    Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
    for (Class autowiringType : this.resolvableDependencies.keySet()) {
        if (autowiringType.isAssignableFrom(requiredType)) {
            Object autowiringValue = this.resolvableDependencies.get(autowiringType);
            autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
            if (requiredType.isInstance(autowiringValue)) {
                    result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
                break;
            }
        }
    }
    for (String candidateName : candidateNames) {
        if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
            result.put(candidateName, getBean(candidateName));
        }
    }
    return result;
}

代码逻辑整理一下:

  • 首先获取候选者bean名称,通过DefaultListableBeanFactory的getBeanNamesForType方法,即找一下所有的Bean定义中指定Type的实现类或者子类
  • 接着第7行~第16行的判断要自动装配的类型是不是要自动装配的纠正类型,这个在【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作一文讲PrepareBeanFactory方法的时候有讲过,如果要自动装配的类型是纠正类型,比如是一个ResourceLoader,那么就会为该类型生成一个代理实例,具体可以看一下第10行的AutowireUtils.resolveAutowiringValue方法的实现
  • 正常来说都是执行的第17行~第21行的代码,逐个判断查找一下beanName对应的BeanDefinition,判断一下是不是自动装配候选者,默认都是的,如果<bean>的autowire-candidate属性设置为false就不是

这样,拿到所有待装配对象的实现类或者子类的候选者,组成一个Map,Key为beanName,Value为具体的Bean。接着回看获取Bean之后的逻辑:

Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    if (matchingBeans.isEmpty()) {
        if (descriptor.isRequired()) {
            raiseNoSuchBeanDefinitionException(type, "", descriptor);
        }
        return null;
    }
    if (matchingBeans.size() > 1) {
        String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
        if (primaryBeanName == null) {
            throw new NoSuchBeanDefinitionException(type, "expected single matching bean but found " +
                    matchingBeans.size() + ": " + matchingBeans.keySet());
        }
        if (autowiredBeanNames != null) {
            autowiredBeanNames.add(primaryBeanName);
        }
        return matchingBeans.get(primaryBeanName);
    }
    // We have exactly one match.
    Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
    if (autowiredBeanNames != null) {
        autowiredBeanNames.add(entry.getKey());
    }
    ...
}

整理一下逻辑:

  • 如果拿到的Map是空的且属性必须注入,抛异常
  • 如果拿到的Map中有多个候选对象,判断其中是否有<bean>中属性配置为”primary=true”的,有就拿执行第13行~第15行的代码,没有就第8行的方法返回null,抛异常,这个异常的描述相信Spring用的比较多的应该比较熟悉
  • 如果拿到的Map中只有一个候选对象,直接拿到那个

通过这样一整个流程,实现了byType自动装配,byType自动装配流程比较长,中间细节比较多,还需要多看看才能弄明白。

最后注意一点,即所有待注入的PropertyName–>PropertyValue映射拿到之后都只是放在MutablePropertyValues中,最后由AbstractPropertyAccessor类的setPropertyValues方法遍历并进行逐一注入。

通过FactoryBean获取Bean实例源码实现

我们知道可以通过实现FactoryBean接口,重写getObject()方法实现个性化定制Bean的过程,这部分我们就来看一下Spring源码是如何实现通过FactoryBean获取Bean实例的。代码直接定位到AbstractBeanFactory的doGetBean方法创建单例Bean这部分:

// Create bean instance.
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, new ObjectFactory() {
        public Object getObject() throws BeansException {
            try {
                return createBean(beanName, mbd, args);
            }
            catch (BeansException ex) {
                // Explicitly remove instance from singleton cache: It might have been put there
                // eagerly by the creation process, to allow for circular reference resolution.
                // Also remove any beans that received a temporary reference to the bean.
                destroySingleton(beanName);
                throw ex;
            }
        }
    });
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

FactoryBean首先是个Bean且被实例化出来成为一个对象之后才能调用getObject()方法,因此还是会执行第3行~第16行的代码,这段代码之前分析过了就不说了。之后执行第17行的方法:

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;
}

首先第5行~第7行判断一下是否beanName以”&”开头并且不是FactoryBean的实现类,不满足则抛异常,因为beanName以”&”开头是FactoryBean的实现类bean定义的一个特征。

接着判断第12行~第14行,如果:

  • bean不是FactoryBean的实现类
  • beanName以”&”开头

这两种情况,都直接把生成的bean对象返回出去,不会执行余下的流程。

最后流程走到第16行~第30行,最终调用getObject()方法实现个性化定制bean,先执行第28行的方法:

protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
                this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
            }
            return (object != NULL_OBJECT ? object : null);
        }
    }
    else {
        return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
    }
}

第1行~第11行的代码与第12行~第13行的代码最终都是一样的,调用了如下一段:

private Object doGetObjectFromFactoryBean(
        final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
        throws BeanCreationException {

    Object object;
    try {
        if (System.getSecurityManager() != null) {
            AccessControlContext acc = getAccessControlContext();
            try {
                object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                            return factory.getObject();
                        }
                    }, acc);
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            object = factory.getObject();
        }
    }
    catch (FactoryBeanNotInitializedException ex) {
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }
        
    // Do not accept a null value for a FactoryBean that's not fully
    // initialized yet: Many FactoryBeans just return null then.
    if (object == null && isSingletonCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(
                beanName, "FactoryBean which is currently in creation returned null from getObject");
    }

    if (object != null && shouldPostProcess) {
        try {
            object = postProcessObjectFromFactoryBean(object, beanName);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);
        }
    }

    return object;
}

第12行和第21行的代码,都一样,最终调用getObject()方法获取对象。回过头去看之前的getObjectFromFactoryBean方法,虽然if…else…逻辑最终都是调用了以上的方法,但是区别在于:

  • 如果FactoryBean接口实现类的isSington方法返回的是true,那么每次调用getObject方法的时候会优先尝试从FactoryBean对象缓存中取目标对象,有就直接拿,没有就创建并放入FactoryBean对象缓存,这样保证了每次单例的FactoryBean调用getObject()方法后最终拿到的目标对象一定是单例的,即在内存中都是同一份;
  • 如果FactoryBean接口实现类的isSington方法返回的是false,那么每次调用getObject方法的时候都会新创建一个目标对象。
IT家园
IT家园

网友最新评论 (0)

发表我的评论
取消评论
表情