Spring源码解析——IoC部分(三)
在本系列的前两篇文章里面我们详细分析了Spring 容器的Bean信息存入过程,这一篇我们来看看依赖注入过程的源码。Bean的依赖注入实际发生在创建Bean时,创建Bean发生在第一次向容器索取Bean时,创建Bean会有解决循环依赖的措施,还会涉及到CGLIB。本文分2个大的部分:Bean创建与依赖注入和CGLIB实例化Bean。
1 Bean创建与依赖注入
1.1 获取Bean与依赖注入
该流程始于调用BeanFactory接口的getBean()方法,其实现在AbstractBeanFactory。getBean有多个重载方法,他们最终都指向doGetBean()。
[code]@Override public <T> T getBean(String name, Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @Override public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); }
//AbstractBeanFactory.doGetBean()
[code]protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { final String beanName = transformedBeanName(name); Object bean; // getSingleton依次从BeanFactory的一/二/三级缓存获取Bean,与解决循环依赖密切相关,我们在第2部分详细解读 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { if (isPrototypeCurrentlyInCreation(beanName)) { // 如果容器正在创建这个Bean,大概率表示我们正在一个循环依赖中 throw new BeanCurrentlyInCreationException(beanName); } // 检查beandefinition是否已经存在于BeanFactory BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // 当前容器中没有就在父级容器中查找 String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // 如果父级容器中也没有,传入参数并委托父级容器创建Bean return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null) { // 如果参数为空,用类型作为参数,委托父级容器创建Bean return parentBeanFactory.getBean(nameToLookup, requiredType); } else { //否则用BeanName作为参数,委托父级容器创建Bean return (T) parentBeanFactory.getBean(nameToLookup); } } //如果不要求类型匹配,把该Bean标志为已创建 if (!typeCheckOnly) { markBeanAsCreated(beanName); } //以下是使用BeanDefinition创建Bean(还包括填充属性)的过程 try { //取出BeanDefinition final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); //检查该类是否抽象类 // 保证当前类依赖的类正确实例化。这一段分析了Bean的依赖对象并尝试实例化被依赖的Bean,是一个递归调 // 用,不过调试发现从来没有发生过递归,即使是循环依赖也没有递归过,解决依赖/循环依赖都是在下文属性填充发生的。 String[] dependsOn = mbd.getDependsOn(); //取出该类的依赖,几乎所有运行到这里取出来都是null 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 { // 尝试获取被依赖的Bean,这是一个【递归调用】,直到取到一个没有依赖其他Bean的Bean, getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 创建Singleton作用域的单例模式Bean if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { //创建Bean和填充属性,重点👉。注意:理论上在这之前【递归调用】已经创建了所有被依赖的Bean,但被依赖 //问题实际并不是在【递归调用】解决的,而是在createBean里面的实例填充这一步解决的。 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); } //创建prototype作用域的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); } //创建其它作用域的Bean 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, () -> { 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; } } // 检查创建的Bean是否和需要的Bean类型相符 if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
1.2 Bean创建
Bean创建发生在AbstractAutowireCapableBeanFactory.createBean()中,创建bean和填充属性。
[code]/** * AbstractAutowireCapableBeanFactory的最关键方法:创建Bean实例, * 为Bean实例填充属性, 调用Bean后处理器等. * @see #doCreateBean */ @Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; // 确定Bean Class这时候已经被完全解析, 克隆BeanDefinition(防止因为mergedBeanDefinition不能保存动态解析 //的Class信息产生的影响) Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // 方法复写前的参数校验 try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // 如果这个类配置了Bean后处理器,得到的bean是一个代理(proxy) Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } try { //开始创建Bean实例并返回,接下来进去看看👉 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); } }
[code]/** * 实际创建Bean的地方:实例化Bean,填充属性,调用初始化方法(如果有配置的话) */protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // BeanWrapper用来持有Bean BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { //如果是单例模式,删除并返回BeanFactory中缓存的同名Bean instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //重点,创建Bean实例👉 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Bean后处理器可以对已生成的Bean实例做一些处理 synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; //标记为已处理 } } // 存入二级缓存(Eagerly cache,或称“提前曝光”),解决循环依赖的关键 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // 初始化已经完成实例化的Bean Object exposedObject = bean; try { //重点,填充属性👉 populateBean(beanName, mbd, instanceWrapper); //调用初始化方法 exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } // 如果是单例Bean且需要销毁,注册进去 try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
先看实例化方法的细节:
[code]/** * 用适当的策略创建Bean实例(工厂方法,构造方法注入或者简单实例化) */ protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 确认解析完成 Class<?> beanClass = resolveBeanClass(mbd, bea 1aa70 nName); //判断是否有是否可以实例化 if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } //从Bean提供者获取完成实例化的Bean(应该是一些非Spring提供的实例化容器,比如Quartz自己的容器) Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } //工厂方法实例化 if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { //构造方法实例化 return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } } Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { //构造方法实例化 return autowireConstructor(beanName, mbd, ctors, args); } ctors = mbd.getPreferredConstructors(); if (ctors != null) { //构造方法实例化 return autowireConstructor(beanName, mbd, ctors, null); } //无参构造方法实例化 return instantiateBean(beanName, mbd); }
再看属性填充方法:
[code]/** * 使用BeanDefinition中的值填充Bean属性 */ @SuppressWarnings("deprecation") // for postProcessPropertyValues protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { //非空检查 if (bw == null) { throw ... } // 给InstantiationWareBeanPostProcessors在设置属性之前修改bean的状态的机会,可用于支持属性注入 boolean continueWithPropertyPopulation = true; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } if (!continueWithPropertyPopulation) { return; } PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); 先处理@Autowaired标注的依赖注入 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds = null; if (hasInstAwareBpps) { if (pvs == null) { pvs = mbd.getPropertyValues(); } for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } } if (needsDepCheck) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } checkDependencies(beanName, mbd, filteredPds, pvs); } if (pvs != null) { //属性注入,里面是对各种类型的属性进行解析和注入,不再进去细看了....吧? applyPropertyValues(beanName, mbd, bw, pvs); } }
2. 循环依赖处理
我们先把依赖注入代码画成流程图如上,然后假设两个类通过属性循环依赖:
public class A{
@Autowired
private B b;
}
public class B{
@Autowired
private A a;
}
对照流程图讲述:在对A实例化前检查【在建集合】中没有A,把A加入【在建集合】,实例化完成后加入【半成品集合】,然后开始属性填充,发现需要B类型的Bean,调用getBean(bBeanName)分别从一二三级缓存获取不到,开始创建B类型的Bean:实例化B前检查【在建集合】中没有B,把B加入【在建集合】,实例化后加入半成品集合,开始填充属性,发现需要A类型Bean,调用getBean(bBeanName)在【半成品集合】(二级缓存)获取到A类型的Bean,B属性填充完成,B从【在建集合移除】。B类型Bean创建完成,开始返回,A类型半成品得到B类型Bean,完成属性填充,A类型Bean创建完成,A从【在建集合移除】。属性循环依赖得到解决。
再看构造函数依赖:
public class A{
pricate B b;
public A(B b){
this.b = b;
}
}
public class B{
pricate A a;
public B(A a){
this.a = a;
}
}
对照流程图讲述:在对A实例化前检查【在建集合】中没有A,把A加入【在建集合】,实例化未完成发现需要B类型的Bean,【半成品集合】中还没有A,调用getBean(bBeanName)分别从一二三级缓存获取不到,开始创建B类型的Bean:实例化B前加入【在建集合】,实例化实例化未完成发现需要A类型Bean,调用getBean(bBeanName)从一二三级缓存获取不到A类型的Bean,开始创建A类型的Bean:在对A实例化前检查【在建集合】中发现已经有A,抛出循环依赖异常:
循环依赖是通过在建集合(singletonsCurrentlyInCreation)和半成品集合(ealySingltonBeans)进行巧妙解决,属性循环依赖可以解决,构造器循环依赖无法解决。看一下加入和移除在建集合的代码以及加入和移除半成品集合的代码,免得看官觉得我乱说:
[code]// AbstractBeanFactory.doGetBean()创建单例Bean节选 if (mbd.isSingleton()) { //注意这里的lambd表达式,执行顺序是先getSingleton()后lambd,getSingleton操作在建集合,lambd表达式操作半成品集合 sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); //lambd表达式,后执行 } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
[code]/** * 出自DefaultSingeltonBeanRegistry,创建Bean前后加入和移出在建集合 */ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } //加入在建集合 // protected void beforeSingletonCreation(String beanName) { // if (!this.inCreationCheckExclusions.contains(beanName) && // !this.singletonsCurrentlyInCreation.add(beanName)) { // throw new BeanCurrentlyInCreationException(beanName); // } // } beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 执行lambd表达式的地方,里面在实例化和填充Bean属性,也是操作半成品集合的位置 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } //从在建集合移除 //protected void afterSingletonCreation(String beanName) { // if (!this.inCreationCheckExclusions.contains(beanName) && // !this.singletonsCurrentlyInCreation.remove(beanName)) { // throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); // } // } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
。。。。省略部分代码。。。。
// 提前曝光,解决循环依赖 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); //单例且允许循环依赖且正在创建 if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //操作集合 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
。。。。。。。
}
/** * 出自DefaultSingletonFactory,操作半成品集合 */ protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); //半成品集合 this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
从上面可以看到,解决循环依赖确实如我所述,在半成品集合与在建集合上面用空间换取事件,赢得了解决循环依赖的成功(构造器循环依赖无法解决)。
以上就是IoC的依赖注入与循环依赖的源码分析,IoC三部曲的终章到此结束,如有不当之处欢迎指正。如果各位看官喜欢这样的叙述风格,敬请关注Spring源码解读系列之AOP/MVC。
- SpringIOC--初始化源码解析
- Spring源码解析:IoC容器的基本结构设计
- Spring 源码解析IoC
- 【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)
- Spring源码阅读之IoC容器初始化2 -- BeanDefinition载入与解析
- (六)Spring核心框架 - IOC的源码解析
- 【Spring】Spring IOC原理及源码解析之scope=request、session
- spring IoC源码分析 (3)Resource解析
- Spring源码解析二:IOC容器初始化过程详解
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【I】
- Spring源码-IOC容器(十)-@Autowired解析
- 做一个合格的程序猿之浅析Spring IoC源码(十一)Spring refresh()方法解析后记2
- Spring IoC源码解析——Bean的创建和初始化
- SpringIOC--初始化源码解析
- spring 实现IOC过程源码解析<一>
- [Spring3.x源码]IoC(二)解析XML建立上下文
- springIOC源码解析(五)
- springIOC源码解析(六)
- spring源码解析-Ioc1
- spring Ioc源码解读-xml资源加载与解析