深入瞭解 Spring IOC DI 原理

什麼是 IOC

IOC 被稱爲控制反轉,通俗的說就是 我們需要使用一個對象而我們不在由自己去實現控制而交給Spring框架來控制對象的使用。

先上圖:
未使用spring框架
在這裏插入圖片描述
使用spring框架
在這裏插入圖片描述
可以看到 Spring將我們的控制權由對象A轉移到Spring進行。

  1. 那麼什麼是DI( 依賴注入 )?
    這個雖然和控制反轉將的是一個概念,但是DI是從被調用者的角度來講的。如上圖,我們被依賴的對象B不需要由A來控制而是需要通過我們的Spring來將B對象注入到Spring中然後直接由A來使用,所以叫依賴注入。

  2. 爲什麼使用Spring IOC
    當我們一個龐大的項目需要用到很多的對象,如果每使用一個對象都要由程序員去new 的話會造成大量的工作量。而最重要的一點就是管理問題,就像一個公司 一樣,如果所有的人員都可以互相調度使用那麼必定會造成一個混亂不堪的現象。但Spring IOC 容器那麼就會充當一個管理調度的工作,他可以給人員提供一個有序的管理。

  3. 深入 Spring IOC
    IOC 架構 有 ApplicationContext 和 BeanFactory 兩種實現方法。
    根據我們的實例分析源碼:

首先我們有一個目標類Library,如下

public class Library {
private String id;

private String address;


public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public String getAddress() {
    return address;
}

public void setAddress(String address) {
    this.address = address;
}

@Override
public String toString() {
    return "com.wy.bean.Library{" +
            "id='" + id + '\'' +
            ", address='" + address + '\'' +
            '}';
}

}
這裏我們通過ApplicationContext對配置信息進行裝配並進行實例化(在FileSystemXmlApplicationContext 中實例化)

ApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/application.xml");
Library library =  (Library) context.getBean("library");

而BeanFactory是先進行xml裝配而不進行實例化的,他會在getBean()時候進行實例化

Resource resource=new ClassPathResource("application.xml");
        BeanFactory factory=new DefaultListableBeanFactory();
        BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
        bdr.loadBeanDefinitions(resource);

        BeanFactory factory2 =  new XmlBeanFactory(resource);

        Library library2 =(Library) factory2.getBean("library");
  1. ApplicationContext 實現方式
    這裏我們先介紹一下Spring ApplicationContext,這個模塊是我們的啓動配置模塊,稱爲Spring的上下文。並且 ApplicationContext具有BeanFactory的所有功能。如下圖:
    在這裏插入圖片描述
    因爲ApplicationContext實現了BeanFatory的所有功能,並且還有許多其他功能,所以通常使用ApplicationContext加載文件並進行ioc的管理。這裏先只對BeanFactory進行深入。

  2. BeanFactory
    BeanFactory基礎架構:
    在這裏插入圖片描述

BeanFactory基礎接口
BeanFactory是我們的頂級接口,其接口屬性如下:
在這裏插入圖片描述

BeanFactory接口屬性
getBean() 方法:該方法實現是在 AbstractBeanFactory 中實現

public Object getBean(String name, Object... args) throws BeansException {
    return this.doGetBean(name, (Class)null, args, false);
}

真的方法應該是doGetBean(),可大概瞭解一下

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        //轉化Bean名字
        String beanName = this.transformedBeanName(name);
        //根據beanName獲取單例模式的bean,如果沒有則進行註冊,有關單例模式可以查看我的另一篇單例的文章
        Object sharedInstance = this.getSingleton(beanName);
        Object bean;
        if (sharedInstance != null && args == null) {
            if (this.logger.isTraceEnabled()) {
                if (this.isSingletonCurrentlyInCreation(beanName)) {
                    this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
                } else {
                    this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
           //從實例類中獲取實例
            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        } else {
            //校驗原型是否在創建
            if (this.isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
            //獲取此實例父級容器
            BeanFactory parentBeanFactory = this.getParentBeanFactory();
            if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
                String nameToLookup = this.originalBeanName(name);
                //instanceof 判斷parent..Factory是否是一個Abs..Factory的實例
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory)parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
                }
                 //從父級容器中中獲取bean
                if (args != null) {
                    return parentBeanFactory.getBean(nameToLookup, args);
                }

                if (requiredType != null) {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }

                return parentBeanFactory.getBean(nameToLookup);
            }

            if (!typeCheckOnly) {
                this.markBeanAsCreated(beanName);
            }

            try {
                RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
                this.checkMergedBeanDefinition(mbd, beanName, args);
                String[] dependsOn = mbd.getDependsOn();
                String[] var11;
                if (dependsOn != null) {
                    var11 = dependsOn;
                    int var12 = dependsOn.length;

                    for(int var13 = 0; var13 < var12; ++var13) {
                        String dep = var11[var13];
                        if (this.isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }

                        this.registerDependentBean(dep, beanName);

                        try {
                            this.getBean(dep);
                        } catch (NoSuchBeanDefinitionException var24) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", var24);
                        }
                    }
                }

                if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
                    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                } else if (mbd.isPrototype()) {
                    var11 = null;

                    Object prototypeInstance;
                    try {
                        this.beforePrototypeCreation(beanName);
                        prototypeInstance = this.createBean(beanName, mbd, args);
                    } finally {
                        this.afterPrototypeCreation(beanName);
                    }

                    bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                } else {
                    String scopeName = mbd.getScope();
                    Scope 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, () -> {
                            this.beforePrototypeCreation(beanName);

                            Object var4;
                            try {
                                var4 = this.createBean(beanName, mbd, args);
                            } finally {
                                this.afterPrototypeCreation(beanName);
                            }

                            return var4;
                        });
                        bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    } catch (IllegalStateException var23) {
                        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", var23);
                    }
                }
            } catch (BeansException var26) {
                this.cleanupAfterBeanCreationFailure(beanName);
                throw var26;
            }
        }

        if (requiredType != null && !requiredType.isInstance(bean)) {
            try {
                T convertedBean = this.getTypeConverter().convertIfNecessary(bean, requiredType);
                if (convertedBean == null) {
                    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
                } else {
                    return convertedBean;
                }
            } catch (TypeMismatchException var25) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", var25);
                }

                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
        } else {
            return bean;
        }
    }

我們仔細看其中的這樣其中有下面一段代碼,我們在創建Bean的時候根據我們的屬性去設置,分別根據我們的配置(單例,原型)執行不同的實例化方式,最後都到createBean()中去進行實例化

  //單例模式
if (mbd.isSingleton()) {
                    sharedInstance = this.getSingleton(beanName, () -> {
                        try {
                            //創建實例
                            return this.createBean(beanName, mbd, args);
                        } catch (BeansException var5) {
                            this.destroySingleton(beanName);
                            throw var5;
                        }
                    });
                    bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
//原型模式
                } else if (mbd.isPrototype()) {
                    var11 = null;
                    Object prototypeInstance;
                    try {
                        this.beforePrototypeCreation(beanName);
                       //創建實例
                        prototypeInstance = this.createBean(beanName, mbd, args);
                    } finally {
                        this.afterPrototypeCreation(beanName);
                    }

                    bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
//scope 模型
                } else {
                    String scopeName = mbd.getScope();
                    Scope scope = (Scope)this.scopes.get(scopeName);
                    if (scope == null) {如下
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
createBean()方法如下 ,其真正實例化的方法是在doCreateBean()中

protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)  
           throws BeanCreationException {  
       if (logger.isDebugEnabled()) {  
           logger.debug("Creating instance of bean '" + beanName + "'");  
       }  
       //判斷需要創建的Bean是否可以實例化,即是否可以通過當前的類加載器加載  
       resolveBeanClass(mbd, beanName);  
       //校驗和準備Bean中的方法覆蓋  
       try {  
           mbd.prepareMethodOverrides();  
       }  
       catch (BeanDefinitionValidationException ex) {  
           throw new BeanDefinitionStoreException(mbd.getResourceDescription(),  
                   beanName, "Validation of method overrides failed", ex);  
       }  
       try {  
           //如果Bean配置了初始化前和初始化後的處理器,則試圖返回一個需要創建//Bean的代理對象  
           Object bean = resolveBeforeInstantiation(beanName, mbd);  
           if (bean != null) {  
               return bean;  
           }  
       }  
       catch (Throwable ex) {  
           throw new BeanCreationException(mbd.getResourceDescription(), beanName,  
                   "BeanPostProcessor before instantiation of bean failed", ex);  
       }  
       //真正的創建bean的方法
       Object beanInstance = doCreateBean(beanName, mbd, args);  
       if (logger.isDebugEnabled()) {  
           logger.debug("Finished creating instance of bean '" + beanName + "'");  
       }  
       return beanInstance;  
   }  

doCreateBean()方法的詳細代碼解釋

 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {  
       //封裝被創建的Bean對象  
       BeanWrapper instanceWrapper = null;  
       if (mbd.isSingleton()){
            //單態模式的Bean,先從容器中緩存中獲取同名Bean  
           instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);  
       }  
       if (instanceWrapper == null) {  
           //創建實例對象  
           instanceWrapper = createBeanInstance(beanName, mbd, args);  
       }  
       final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);  
       //獲取實例化對象的類型  
       Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);  
       //調用PostProcessor後置處理器  
       synchronized (mbd.postProcessingLock) {  
           if (!mbd.postProcessed) {  
               applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);  
               mbd.postProcessed = true;  
           }  
       }  
       // Eagerly cache singletons to be able to resolve circular references  
       //向容器中緩存單態模式的Bean對象,以防循環引用  
       boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&  
               isSingletonCurrentlyInCreation(beanName));  
       if (earlySingletonExposure) {  
           if (logger.isDebugEnabled()) {  
               logger.debug("Eagerly caching bean '" + beanName +  
                       "' to allow for resolving potential circular references");  
           }  
           //這裏是一個匿名內部類,爲了防止循環引用,儘早持有對象的引用  
           addSingletonFactory(beanName, new ObjectFactory() {  
               public Object getObject() throws BeansException {  
                   return getEarlyBeanReference(beanName, mbd, bean);  
               }  
           });  
       }  
       //Bean對象的初始化,依賴注入在此觸發  
       //這個exposedObject在初始化完成之後返回作爲依賴注入完成後的Bean  
       Object exposedObject = bean;  
       try {  
           //將Bean實例對象封裝,並且Bean定義中配置的屬性值賦值給實例對象  
           populateBean(beanName, mbd, instanceWrapper);  
           if (exposedObject != null) {  
               //初始化Bean對象  
               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) {  
           //獲取指定名稱的已註冊的單態模式Bean對象  
           Object earlySingletonReference = getSingleton(beanName, false);  
           if (earlySingletonReference != null) {  
               //根據名稱獲取的以註冊的Bean和正在實例化的Bean是同一個  
               if (exposedObject == bean) {  
                   //當前實例化的Bean初始化完成  
                   exposedObject = earlySingletonReference;  
               }  
               //當前Bean依賴其他Bean,並且當發生循環引用時不允許新創建實例對象  
               else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {  
                   String[] dependentBeans = getDependentBeans(beanName);  
                   Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);  
                   //獲取當前Bean所依賴的其他Bean  
                   for (String dependentBean : dependentBeans) {  
                       //對依賴Bean進行類型檢查  
                       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;  
    }
到這一步了還是沒有找到我們要的具體實例化的代碼,那麼進入我們的createBeanInstance(),這裏選擇了幾種實例化的方式:工廠,自動裝配,Bean的構造方法,默認的無參構造方法。

//創建Bean的實例對象  
   protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {  
       //檢查確認Bean是可實例化的  
       Class beanClass = resolveBeanClass(mbd, beanName);  
       //使用工廠方法對Bean進行實例化  
       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());  
       }  
       if (mbd.getFactoryMethodName() != null)  {  
           //調用工廠方法實例化  
           return instantiateUsingFactoryMethod(beanName, mbd, args);  
       }  
       //使用容器的自動裝配方法進行實例化  
       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) {  
               //配置了自動裝配屬性,使用容器的自動裝配實例化  
               //容器的自動裝配是根據參數類型匹配Bean的構造方法  
               return autowireConstructor(beanName, mbd, null, null);  
           }  
           else {  
               //使用默認的無參構造方法實例化  
               return instantiateBean(beanName, mbd);  
           }  
       }  
       //使用Bean的構造方法進行實例化  
       Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);  
       if (ctors != null ||  
               mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||  
               mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {  
           //使用容器的自動裝配特性,調用匹配的構造方法實例化  
           return autowireConstructor(beanName, mbd, ctors, args);  
       }  
       //使用默認的無參構造方法實例化  
       return instantiateBean(beanName, mbd);  
   }   
   //使用默認的無參構造方法實例化Bean對象  
   protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {  
       try {  
           Object beanInstance;  
           final BeanFactory parent = this;  
           //獲取系統的安全管理接口,JDK標準的安全管理API  
           if (System.getSecurityManager() != null) {  
               //這裏是一個匿名內置類,根據實例化策略創建實例對象  
               beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {  
                   public Object run() {  
                       return getInstantiationStrategy().instantiate(mbd, beanName, parent);  
                   }  
               }, getAccessControlContext());  
           }  
           else {  
               //將實例化的對象封裝起來  
               beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);  
           }  
           BeanWrapper bw = new BeanWrapperImpl(beanInstance);  
           initBeanWrapper(bw);  
           return bw;  
       }  
       catch (Throwable ex) {  
           throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);  
       }  
   }

進入到 無參構造方法中 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); 這段代碼就發現,春天來了!實例化,wc!

@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							constructorToUse = clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
                       //使用BeanUtil進行實例化
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// 使用CGLIB動態代理方法進行實例化
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

使用Beanutil 的實例化代碼!使用的是反射的newInstance()方法!

return ctor.newInstance(argsWithDefaultValues);
通過以上代碼算是瞭解到底層進行實例化的代理設計模式,CGLIB動態代理,進入動態代理我們發現下面這段代碼,使用的是反射的newInstance()進行了最終的實例化!

				Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
				instance = enhancedSubclassConstructor.newInstance(args);

看完實例化的源碼後我們總結一下BeanFactory實例化的簡單流程:

  1. 通過使用BeanFacrory 的 getBean()接口 來告訴IOC容器需要根據beanName獲取實例
  2. getBean() 由 AbstractBeanFactory 的 dogetBean()具實現
  3. doGetBean()中我們需要首先去獲取是否存在,然後對配置信息進行一個判斷。然後去進入到實例化的方法
  4. 進入 createBean() 選擇在實例化前進行校驗
  5. doCreateBean() 來對我們配置的模型進行實例化的具體實現並且在實例化後完成依賴注入。
  6. doCreateBean() 實例化的具體實現是在createBeanInstance()中進行的,他會根據我們的要求去進行相應的模式設計!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章