栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring源码解析(5)之bean实例化过程(上)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring源码解析(5)之bean实例化过程(上)

一、前言

        进过前面的分析,接下来就是对面bean加载的过程,其实bean的加载加载过程远比bean的解析要复杂的很多,下面我们对下面的这行代码后面的作用为切入点。

public class MainClass {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
        System.out.println(context.getBean("tulingAspect"));
    }
}

        context.getBean("tulingAspect");在这行代码中实现了什么功能呢?我们可以快速体验一下Spring中代码是如果实现的。下面这个是我整理原理的一个代码调用流程图,可以先提前看,下面我们会对具体的某个方法的主干作用进行分析。

        

         i1:>org.springframework.beans.factory.support.AbstractBeanFactory#getBean(java.lang.String)         i2>org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean         i2.1>:org.springframework.beans.factory.support.AbstractBeanFactory#transformedBeanName 转换 beanName         i2.2>:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton 去缓存 中获取bean         i2.3>:org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance 对 缓存中的获取的bean进行后续处理         i2.4>:org.springframework.beans.factory.support.AbstractBeanFactory#isPrototypeCurrentlyInCreation 判断原型bean的依赖注入         i2.5>:org.springframework.beans.factory.support.AbstractBeanFactory#getParentBeanFactory 检查父 容器加载bean         i2.6>:org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition 将 bean定义转为RootBeanDifination         i2.7>:检查bean的依赖(bean加载顺序的依赖) i2.8>:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton根据 scope 的添加来创建bean

         i3>:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean创建 bean的方法         i4>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean 真 正的创建bean的逻辑         i4.1>:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance 调用构造函数创建对象

        i4.2>:判断是否需要提早暴露对象(mbd.isSingleton() && this.allowCircularReferences && i sSingletonCurrentlyInCreation(beanName));         i4.3>org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory 暴露对象解决循环依赖         i4.4>:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean 给创建的bean进行赋值         i4.5>:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean对 bean进行初始化         i4.5.1>:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods 调用XXAware接口         i4.5.2>applyBeanPostProcessorsBeforeInitialization 调用bean的后置处理器进行对处理
        i4.5.2>applyBeanPostProcessorsBeforeInitialization 调用bean的后置处理器进行对处理

       i4.5.3>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods 对象的初始化方法         i4.5.3.1>:org.springframework.beans.factory.InitializingBean#afterPropertiesSet 调用 InitializingBean的方法

        i4.5.3.2>:String initMethodName = mbd.getInitMethodName(); 自定义的初始化方法         i5>:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton 把创建好的实 例化好的bean加载缓存中         i6>:org.springframework.beans.factory.support.AbstractBeanFactory#getObjectForBeanInstance对创建的 bean进行后续的加工

        以上就是getBean大体的调用过程,下面将跟着这些步骤进行源码的学习。

        i1:getBean       
	@Override
	public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}
         i2:doGetBean

        

  这个方法很长,让我们具体来看着他具体是做了那些事情,这里给大家提一点学习源码的建议,看spring源码,看不懂就先跳,有些太过复杂的可以知道这行代码是干嘛的就行,可以先把大体的流程先看完,然后学习源码本身就是一件很枯燥很需要精力的事情,我们需要自己多看几遍然后自己调试几遍。

  1. 转换对应的beanName,这里或许很多人不理解,传进来的name不就是beanName么?其实传进来的有可能是别名或者是我们的BeanFactory,所以需要进行一系列的解析,其中解析包括以下内容,(1)去除BeanFactory的修饰符(在我Spring源码分析(1)之常见底层核心注解_jokeMqc的博客-CSDN博客 已经有介绍对应的用法了)(2)去指定的alias获取最终表示的beanName。
  2. 尝试去缓存中加载单例,这里就是为了解决循环依赖的关键代码,本节课讲完bean的加载过程会介绍spring是如果解决循环依赖的,要记得我们单例bean在容器中只会被实例化一次,后续在创建bean就直接从单例缓存池中去获取了,这里只是尝试去获取。这里为了解决循环依赖问题,在对象刚刚创建好的时候(还没有进行属性赋值),就会将创建bean的ObjectFactory提早的暴露到缓存中去,一旦下一个bean创建的时候需要上一个bean那直接就从缓存里面去获取就行了。(后面会着重将这一个)
  3. bean的实例化,如果我们从缓存中获取得到bean,我们只是获取得到bean的原始状态,不一定是我们最终需要的bean,需要getObjectForBeanInstance方法中如果bean没有实例化则在这里进行实例化.
  4. 对原型依赖的检查,为什么原型对象解决不了循环依赖,这里就说明了,我们的ioc容器并不会对原型对象进行缓存,而是获取一次则创建一次bean,isPrototypeCurrentlyInCreation是检查如果A中有B的属性,B中有A的属性,那么当依赖注入的时候,此时就会有A还没有创建完,然后需要去创建B,继而又要创建A,这个时候就会抛出异常了。
  5. 检测parentFactory,其实这里代码的意思很简单,如果当前的bean存在父容器并且当前容器找不到对应的bean定义,那么就去父容器中进行加载。
  6. 合并父类属性(下面也会有具体的介绍)
  7. 寻找依赖,就是我们在bean标注的depends-on,但是需要注意的一点就是如果A depends-on B,B depends-on A这个就会抛异常的
  8. 针对不同的scope进行bean的创建
  9. 类型转换,到这里其实整个bean的加载过程已经结束了。
	protected  T doGetBean(
			final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)
			throws BeansException {
		
		final String beanName = transformedBeanName(name);
		Object bean;

		
		 // 直接从缓存中去取或从对象工厂缓存去取
		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);
		}

		else {
			
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
// 获取父容器
			BeanFactory parentBeanFactory = getParentBeanFactory();
			// 如果beanDefinitionMap以及所有加载的bean不包含 本次加载的bean则从父容器中去加载
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (args != null) {
					// 从父容器中递归查询
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}
			
			// 这里不是做类型检查,而是创建bean,这里需要标记一下
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// 用来处理bean的加载顺序,比如要在创建instA的情况下要先创建instrB
				
				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 + "'");
						}
						// 注册依赖
						registerDependentBean(dep, beanName);
						try {
						    // 有限创建依赖对象
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}
// 创建bean,单例
				if (mbd.isSingleton()) {
					// 创建单例bean
					sharedInstance = getSingleton(beanName, new ObjectFactory() {
						// 在getSingleton方法中进行回调的
						@Override
						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);
				}
				
				// 创建非单例的bean
				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);
				} 
else {
					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, new ObjectFactory() {
							@Override
							public Object getObject() throws BeansException {
								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);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// Check if required type matches the type of the actual bean instance.
		if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
			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;
	} 
        2.1 缓存中获取单例bean 

        前面介绍过了,我们的单例bean只会被容器创建一次,之后获取都是去缓存中获取。这个方法涉及到循环依赖的解决,他首先会从singletonObjects中去获取实例,如果获取不到并且当前的bean正在创建中再从earlySingletonObjects中去获取,如果还再获取不到则从singletonFactories中去获取,然后调用这个ObjectFactory的getObject()来创建bean,并放到earlySingletonObjects中

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 去缓存map中获取已经实例化的对象
		Object singletonObject = this.singletonObjects.get(beanName);
		// 缓存中没有获取到判断该对象是否正在创建中
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 加锁防止并发创建
			synchronized (this.singletonObjects) {
				// 保存早期对象缓存中是否存在该对象
				singletonObject = this.earlySingletonObjects.get(beanName);
				// 早期对象缓存中没有
				if (singletonObject == null && allowEarlyReference) {
					// 早期对象暴露工厂缓存(用来解决循环依赖)
					ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//调用该早期方法
						singletonObject = singletonFactory.getObject();
						//放入到早期对象缓存中
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
        2.2从bean的实例中去获取对象

        在上面的源码分析中可以看得到,在bean的整个生命周期里面,getObjectForInstance()出现的频率很高,无论是从缓存中获取的bean还是根据scope策略加载的bean,总之,我们获取得到的bean第一步就是调用这个方法来进行检测,其实就是检查当前的bean是否是FactoryBean类型的bean,如果是,那么就需要调用该bean对应的factoryBean实例中的getObject()方法来返回对应的对象。 

        

	
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

		// 判断该beanName是否以&开头但是又不是factoryBean类型,则抛异常
		if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
			throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
		}

		
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}
		
		// 加载factoryBean
		Object object = null;
		if (mbd == null) {
			
			object = getCachedObjectForFactoryBean(beanName);
		}
		
		
		if (object == null) {
			// 进过前面的判断,程序走到这一步可以保证此时的bean肯定是factoryBean,所以可以进行类型转换
			FactoryBean factory = (FactoryBean) beanInstance;
			// 如果mbd为空,并且包含有该beanName的BeanDefinition
			if (mbd == null && containsBeanDefinition(beanName)) {
				// 合并我们的bean定义
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			// 继续调用getObjectFromFactoryBean去获取实例
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

       上面的代码并没有什么重要信息,他其中最核心的代码就是getObjectFromFactoryBean,我们接下来往下看看。

        2.2.1getObjectFromFactoryBean

               对FactoryBean正确性,对非FactoryBean不做任何处理,然后将Factory中解析bean的工作委托给getObjectFactoryBean。

                到这里我们也发现,真正做事情也就交给了doGetObjectFromFactoryBean,而且如果返回的bean是单例,那就必须要包场全局唯一,如果没有必要重复创建,可以使用缓存来提高性能,也就是说已经加载过就要记录下来以便于下次重复使用。

	
	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) {
					// 没有获取到,则使用factoryBean的getObject()方法去获取对象
					object = doGetObjectFromFactoryBean(factory, beanName);
					// only post-process and store if not put there already during getObject() call above
					// (e.g. because of circular reference processing triggered by custom getBean calls)
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
else {
						if (object != null && shouldPostProcess) {
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								return object;
							}
							beforeSingletonCreation(beanName);
							try {
								// 调用ObjectFactory的后置处理器
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								afterSingletonCreation(beanName);
							}
						}
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
						}
					}
				}
				return (object != NULL_OBJECT ? object : null);
			}
		}
		else {
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (object != null && shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}
        2.2.2 doGetObjectFromFactoryBean

        在这个方法中,我们可以看得到想要看得到的方法,也就是对应factory.getObject(),上面说了,如果bean为FactoryBean类型,则当提取的并不是FactoryBean,而是FactoryBean对应的getObject()方法返回的bean,而doGetObjectFromFactoryBean正是实现这个功能的,然后我们得到对应的bean并没有返回。而是继续调用postProcessObjectFromFactoryBean,然后继续看看这个方法做了什么事情。

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

		Object object;
		try {
			if (System.getSecurityManager() != null) {
				AccessControlContext acc = getAccessControlContext();
				try {
					object = AccessController.doPrivileged(new PrivilegedExceptionAction() {
						@Override
						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");
		}
		return object;
	} 
        2.2.3 postProcessObjectFromFactoryBean 

        这里就是就是调用对应的后置处理器进行处理。

	protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
		return applyBeanPostProcessorsAfterInitialization(object, beanName);
	}

	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			result = processor.postProcessAfterInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}
        2.3getMergedLocalBeanDefinition将bean定义转换为RootBeanDefinition

        首先回去合并的缓存中去判断当前的bean是否已经合并过,如果合并过就直接返回。

	
	protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
		// 去合并的bean定义缓存中判断当前bean是否合并过
		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
		if (mbd != null) {
			return mbd;
		}
		// 没有合并过调用合并方法
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}
  1.  去缓存中获取bean定义信息,获取得到则直接返回。
  2. 如果获取不到,则判断当前的bean是否存在父类,如果不存在,则进行深克隆后然后对应的RootBeanDefinition
  3. 如果存在父类,首先获取得到父类的名称,然后判断父类名称跟当前beanName是否一样,如果一样,则判断父类一定是在父容器中,然后去父容器那里获取得到对应BeanDenifition。
  4. 最后以父BeanDenifition为基础创建RootDefinition,也就是合并后的BeanDefinition,然后用子类属性覆盖父类的属性,然后把合并好的放入到缓存中,最后返回。
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
			throws BeanDefinitionStoreException {

		return getMergedBeanDefinition(beanName, bd, null);
	}
	
	
	protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, BeanDefinition containingBd)
			throws BeanDefinitionStoreException {
		// 加锁,防止并发合并
		synchronized (this.mergedBeanDefinitions) {
			RootBeanDefinition mbd = null;

			// Check with full lock now in order to enforce the same merged instance.
			// 去缓存中获取一次bean定义
			if (containingBd == null) {
				mbd = this.mergedBeanDefinitions.get(beanName);
			}
			
			// 尝试没有获取到
			if (mbd == null) {
				// 当前的bean定义是否存在父类
				if (bd.getParentName() == null) { // 没有
					// 转为rootBeanDefinition,进行深度克隆然后返回
					if (bd instanceof RootBeanDefinition) {
						mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
					}
					else {
						mbd = new RootBeanDefinition(bd);
					}
				}
else { // 存在父类
					// 首先定义一个父的bean
					BeanDefinition pbd;
					try {
						// 获取父的bean名称
						String parentBeanName = transformedBeanName(bd.getParentName());
						
						if (!beanName.equals(parentBeanName)) {
							
							pbd = getMergedBeanDefinition(parentBeanName);
						}
else {
							// 获取父容器
							BeanFactory parent = getParentBeanFactory();
							if (parent instanceof ConfigurableBeanFactory) {
								// 从父容器那里获取父类的BeanDefinitioin定义
								pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
							}
							else {
								throw new NoSuchBeanDefinitionException(parentBeanName,
										"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
										"': cannot be resolved without an AbstractBeanFactory parent");
							}
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
								"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
					}
					// 以父BeanDefiniton为基础创建RootBeanDefinition,也就是合并后的BeanDefinition
					mbd = new RootBeanDefinition(pbd);
					// 用子类的属性覆盖父BeanDefinition的属性
					mbd.overrideFrom(bd);
				}

				// 如果之前没有配置,就把当前设置为单例(这里相当于设置默认的)
				if (!StringUtils.hasLength(mbd.getScope())) {
					mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
				}

				if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
					mbd.setScope(containingBd.getScope());
				}

				// 缓存合并后的BeanDefinition
				if (containingBd == null && isCacheBeanmetadata()) {
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}

			return mbd;
		}
	}

        大家可以接着阅读spring的bean的加载过程(下) Spring源码解析(6)之bean实例化过程(下)_jokeMqc的博客-CSDN博客

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号