美文网首页spring cloud基础知识点工作生活
spring容器之parentBeanFactory的检测和依赖

spring容器之parentBeanFactory的检测和依赖

作者: 会上树的程序猿 | 来源:发表于2019-07-05 23:07 被阅读0次

上节我们了解了spring对bean的获取,我们知道了我们从缓存中获取的bean大概有两种,一种是scope不是单例的bean,一种是单例的bean但还没有初始化完成.对于这两种类型的bean:

  • 第一种是spring是通过一些检测以及依赖的处理
  • 第二种是spring通过初始化对应的scope来完成

首先我们来看一下spring对于第一种的处理过程:

    if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        //如果容器中没有找到,则从父类容器中加载
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            //当前类的爸爸中没找到,从爷爷辈去找,直到找到
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                //调用AbstractBeanFactory的doGetBean方法去获取bean的实例
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
            }
            //args为首次创建bean的实例时的参数
            else if (args != null) {
                //使用代理的方式去获取bean实例
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            //bean的真实类型
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            //这里表示我们的args和requiredType都为null,直接通过得到的bean的名字去获取实例
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }
        //对bean的真实类型检查,在检查之前不可使用该bean
        if (!typeCheckOnly) {
            //对已经创建完的bean的实例做标记,如:已完成创建
            markBeanAsCreated(beanName);
        }

        try {
            //合并父子bean的定义
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            //检查合并之后的bean的定义
            checkMergedBeanDefinition(mbd, beanName, args);

            //先初始化当前bean所依赖的bean
            //如:我的订单类需要商品类,此刻spring会先初始化商品类,大概就是这样的
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    //给当前bean注册一个依赖bean
                    registerDependentBean(dep, beanName);
                    try {
                        //递归处理
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // Create bean instance.
            //创建bean实例
            //单例的情况下
            if (mbd.isSingleton()) {
                //从缓存(singletonObjects)中去拿
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        //最后从缓存中移除对应的实例原因有:
                        //1.每当有bean在创建时,允许循环参考来解析对应的beanDefinition
                        //2.删除临时引用该bean的bean
                        destroySingleton(beanName);
                        throw ex;
                    }
                });

                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            //原型的情况下:
            else if (mbd.isPrototype()) {

                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    //创建完bean的处理
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                //获取bean的作用域
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                            ex);
                }
            }

简单的来捋一下过程:

  • 首先是判断当前bean是否在创建过程中,如果是直接抛BeanCurrentlyInCreationException异常
AbstractBeanFactory.java
if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

这就是检测,跟踪代码来到:

  /** Names of beans that are currently in creation. */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
        new NamedThreadLocal<>("Prototype beans currently in creation");
/**
 * Return whether the specified prototype bean is currently in creation
 * (within the current thread).
 * @param beanName the name of the bean
 */
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
    Object curVal = this.prototypesCurrentlyInCreation.get();
    return (curVal != null &&
            (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
  1. 对parentBeanFactory的检测
        //如果容器中没有找到,则从父类容器中加载
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            //当前类的爸爸中没找到,从爷爷辈去找,直到找到
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                //调用AbstractBeanFactory的doGetBean方法去获取bean的实例
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
            }
            //args为首次创建bean的实例时的参数
            else if (args != null) {
                //使用代理的方式去获取bean实例
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            //bean的真实类型
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            //这里表示我们的args和requiredType都为null,直接通过得到的bean的名字去获取实例
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }

可以看到的是,当获取到的parentBeanFactory不为null且containsBeanDefinition不包含beanDefinition实例时,递归处理寻找,直到找到为止
其次在整个的过程中,我们可以看到的是将获取bean的任务交给了parentBeanFactory#getBean方法处理

  • 首先是获取最原始的bean
String nameToLookup = originalBeanName(name);


/**
 * Determine the original bean name, resolving locally defined aliases to canonical names.
 * @param name the user-specified name
 * @return the original bean name
 */
protected String originalBeanName(String name) {
    String beanName = transformedBeanName(name);
    if (name.startsWith(FACTORY_BEAN_PREFIX)) {
        beanName = FACTORY_BEAN_PREFIX + beanName;
    }
    return beanName;
}

在获取的过程中,首先是对name的转换,如果name是以&开头,那么我们转换之后的beanName就应该是"&"+beanName

  • 之后是通过getBean()方法来获取bean
  1. 类型检查
//对bean的真实类型检查,在检查之前不可使用该bean
        if (!typeCheckOnly) {
            //对已经创建完的bean的实例做标记,如:已完成创建
            markBeanAsCreated(beanName);
        }

代码很简单,我们可以看到参数typeCheckOnly是关键点,其目的是调用getBean()时,表示是否仅仅作为获取bean是的类型检查,如果不是仅仅做类型检查,而是在创建bean的过程中则调用markBeanAsCreated方法对创建过程中的bean进行标记,这里就是这么做的,我们直接看代码:

AbstractBeanFactory.java
/** 该缓存中存放的是已经创建完成的bean*/
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));

/**
 * 1.该方法的主要的作用就是将我们的bean做一个标记:如该bean已经创建或者是正在创建
 * 2.允许bean工厂去优化自己本身的缓存,这样可以保证该bean的重复创建:原型
 * @param beanName bean的名字
 */
protected void markBeanAsCreated(String beanName) {
    //这里表示alreadyCreated缓存中没有创建的bean
    if (!this.alreadyCreated.contains(beanName)) {
        //全局的同步锁
        //mergedBeanDefinitions为合并后的beanDefinition
        synchronized (this.mergedBeanDefinitions) {
            //alreadyCreated中没有的话
            if (!this.alreadyCreated.contains(beanName)) {
                // Let the bean definition get re-merged now that we're actually creating
                // the bean... just in case some of its metadata changed in the meantime.
                //从mergedBeanDefinitions删除beanName对应的bean,等到下一次访问时在创建它
                clearMergedBeanDefinition(beanName);
                //将beanName进行保存操作
                this.alreadyCreated.add(beanName);
            }
        }
    }
}

/**
 * Remove the merged bean definition for the specified bean,
 * recreating it on next access.
 * @param beanName the bean name to clear the merged definition for
 */
protected void clearMergedBeanDefinition(String beanName) {
    this.mergedBeanDefinitions.remove(beanName);
}
  1. 将beanDefinition合并为rootBeanDefinition
AbstractBeanFactory.java
//合并父子bean的定义
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查合并之后的bean的定义
checkMergedBeanDefinition(mbd, beanName, args);

首先是获取RootBeanDefinition的过程,跟踪代码:

AbstractBeanFactory.java
/** Map from bean name to merged RootBeanDefinition. */
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    // Quick check on the concurrent map first, with minimal locking.
    //以最快的速度从缓存中去检索,缩小检索范围
    RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    if (mbd != null) {
        return mbd;
    }
    //获取RootBeanDefinition
    //如果返回的子beanDefinition的话,递归合并beanDefinition相关属性
    return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}

简单的过一下获取合并后的RootBeanDefinition的步骤:

(1). 首先是从mergedBeanDefinitions缓存中通过beanName去获取RootBeanDefinition,如果存在则返回.

(2). 不存在的话,调用getMergedBeanDefinition方法获取,如果获取到的是子beanDefinition的话进行合并相关属性,这里关于如何合并的过程不再细说:

protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
        throws BeanDefinitionStoreException {

    return getMergedBeanDefinition(beanName, bd, null);
}

(3). 调用checkMergedBeanDefinition(mbd, beanName, args)进行对bean的检查

/**
 * Check the given merged bean definition,
 * potentially throwing validation exceptions.
 * @param mbd the merged bean definition to check
 * @param beanName the name of the bean
 * @param args the arguments for bean creation, if any
 * @throws BeanDefinitionStoreException in case of validation failure
 */
protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args)
        throws BeanDefinitionStoreException {

    if (mbd.isAbstract()) {
        throw new BeanIsAbstractException(beanName);
    }
}
  1. 循环依赖处理

所谓依赖,实际上是一个bean作为另一个bean的引用,我们来看代码:

//先初始化当前bean所依赖的bean
//如:我的订单类需要商品类,此刻spring会先初始化商品类,大概就是这样的
String[] dependsOn = mbd.getDependsOn();
        if (dependsOn != null) {
        for (String dep : dependsOn) {
              if (isDependent(beanName, dep)) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
            //给当前bean注册一个依赖bean
            registerDependentBean(dep, beanName);
                    try {
                        //递归处理
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

当一个bean需要依赖与另外一个bean,则先初始化需要依赖的bean,简单的看一下过程:

4.1.初始化依赖的bean

AbstractBeanDefinition.java
private String[] dependsOn;

public String[] getDependsOn() {
    return this.dependsOn;
}

4.2. 循环遍历然后调用isDependent(beanName, dep)方法检验当前依赖是否注册,是的话抛BeanCreationException异常.

DefaultSingletonBeanRegistry.java
/**保存的是依赖beanName之间的映射关系*/
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

protected boolean isDependent(String beanName, String dependentBeanName) {
    
    synchronized (this.dependentBeanMap) {
        return isDependent(beanName, dependentBeanName, null);
    }
}

private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {

    //如果是alreadySeen中包含beanName说明已经注册了依赖的bean
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    //获取最原始bean 的beanName
    String canonicalName = canonicalName(beanName);
    //从dependentBeanMap中通过beanName获取所有的依赖bean的集合
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    if (dependentBeans == null) {
        return false;
    }
    //如果dependentBeanName存在于dependentBeans中,说明已经有依赖的bean
    if (dependentBeans.contains(dependentBeanName)) {
        return true;
    }
    //遍历
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
            alreadySeen = new HashSet<>();
        }
        //将beanName添加到alreadySeen中作为参数
        alreadySeen.add(beanName);
        //递归调用自己
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}

4.3. 调用registerDependentBean(dep, beanName)方法给当前bean注册依赖,这里是已经检验成功的情况下:

/**保存的是依赖beanName之间的映射关系*/
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

/**
 * 给当前bean注册一个依赖的bean
 * @param beanName 当前要创建的bean
 * @param dependentBeanName 当前bean所依赖的bean的名字
 */
public void registerDependentBean(String beanName, String dependentBeanName) {
    //获取原始beanName
    String canonicalName = canonicalName(beanName);
    // 添加 <canonicalName, <dependentBeanName>> 到 dependentBeanMap 中
    synchronized (this.dependentBeanMap) {
        Set<String> dependentBeans =
                this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
        if (!dependentBeans.add(dependentBeanName)) {
            return;
        }
    }
    //同上
    synchronized (this.dependenciesForBeanMap) {
        Set<String> dependenciesForBean =
                this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
        dependenciesForBean.add(canonicalName);
    }
}

4.4. 调用getBean(String beanName)进行依赖bean的实例化过程.

关于parentBeanFactory的检测和依赖处理到这里就说完了

相关文章

网友评论

    本文标题:spring容器之parentBeanFactory的检测和依赖

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