浅谈Spring IoC容器的依赖注入原理
本文介绍了浅谈spring ioc容器的依赖注入原理,分享给大家,具体如下:
ioc容器初始化的过程,主要完成的工作是在ioc容器中建立 beandefinition 数据映射,并没有看到ioc容器对bean依赖关系进行注入,
假设当前ioc容器已经载入用户定义的bean信息,依赖注入主要发生在两个阶段
正常情况下,由用户第一次向ioc容器索要bean时触发
但我们可以在 beandefinition 信息中通过控制 lazy-init 属性来让容器完成对bean的预实例化,即在初始化的过程中就完成某些bean的依赖注入的过程
1.getbean触发的依赖注入
在基本的ioc容器接口 beanfactory 中,有一个 getbean 的接口定义,这个接口的实现就是触发依赖注入发生的地方.为了进一步了解这个依赖注入的过程,我们从 defaultlistablebeanfactory 的基类 abstractbeanfactory 入手去看看getbean的实现
// 这里是对 beanfactory 接口的实现,比如getbean接口方法 //这些getbean接口方法最终是通过调用dogetbean来实现的 @override public object getbean(string name) throws beansexception { return dogetbean(name, null, null, false); } @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); } public <t> t getbean(string name, class<t> requiredtype, object... args) throws beansexception { return dogetbean(name, requiredtype, args, false); } //这里是实际取得bean的地方,也就是触发依赖注入发生的地方 @suppresswarnings("unchecked") protected <t> t dogetbean( final string name, final class<t> requiredtype, final object[] args, boolean typecheckonly) throws beansexception { final string beanname = transformedbeanname(name); object bean; // eagerly check singleton cache for manually registered singletons. //急切地检查单例人士缓存手动注册的单例 //先从缓存中取得bean,处理那些已经被创建过的单例bean,这种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 + "'"); } } //这里的getobjectforbeaninstance完成的是factorybean的相关处理,以取得factorybean的相关处理,以取得factorybean的生产结果,beanfactory和factorybean的区别已在前面讲过,这个过程在后面还会详细地分析 bean = getobjectforbeaninstance(sharedinstance, name, beanname, null); } else { // fail if we're already creating this bean instance: // we're assumably within a circular reference. if (isprototypecurrentlyincreation(beanname)) { throw new beancurrentlyincreationexception(beanname); } // // 检查ioc容器中的beandefinition是否存在,若在当前工厂不存在则去顺着双亲beanfactory链一直向上找 beanfactory parentbeanfactory = getparentbeanfactory(); if (parentbeanfactory != null && !containsbeandefinition(beanname)) { // not found -> check parent. string nametolookup = originalbeanname(name); if (args != null) { // delegation to parent with explicit args. return (t) parentbeanfactory.getbean(nametolookup, args); } else { // no args -> delegate to standard getbean method. return parentbeanfactory.getbean(nametolookup, requiredtype); } } if (!typecheckonly) { markbeanascreated(beanname); } try { //根据bean的名字取得beandefinition final rootbeandefinition mbd = getmergedlocalbeandefinition(beanname); checkmergedbeandefinition(mbd, beanname, args); // guarantee initialization of beans that the current bean depends on. //递归获得当前bean依赖的所有bean(如果有的话) 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); getbean(dep); } } //通过调用createbean方法创建singleton bean实例 if (mbd.issingleton()) { sharedinstance = getsingleton(beanname, new objectfactory<object>() { @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); } //这里是创建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); } 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<object>() { @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. // 这里对创建的bean进行类型检查,如果没有问题,就返回这个新创建的bean,这个bean已经是包含了依赖关系的bean if (requiredtype != null && bean != null && !requiredtype.isassignablefrom(bean.getclass())) { 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; }
依赖注入就是在这里被触发的.而依赖注入的发生是在容器中的beandefinition数据已经建立好的前提下进行的.虽然我们可以用最简单的方式来描述ioc容器,那就是视其为一个hashmap,但只能说这个hashmap是容器的最基本的数据结构,而不是ioc容器的全部.
关于这个依赖注入过程会在下面详解,图1.1可以看到依赖注入的大致过程.
图1.1 依赖注入的过程
getbean是依赖注入的起点,之后会调用abstractautowirecapablebeanfactory中的createbean来生产需要的bean,还对bean初始化进行了处理,比如实现了在beandefinition中的init-method属性定义,bean后置处理器等.下面通过createbean代码了解这个过程
@override protected object createbean(string beanname, rootbeandefinition mbd, object[] args) throws beancreationexception { if (logger.isdebugenabled()) { logger.debug("creating instance of bean '" + beanname + "'"); } rootbeandefinition mbdtouse = mbd; // make sure bean class is actually resolved at this point, and // clone the bean definition in case of a dynamically resolved class // which cannot be stored in the shared merged bean definition. //这里判断需要创建的bean是否可以被实例化,这个类是否可以通过类加载器来载入 class<?> resolvedclass = resolvebeanclass(mbd, beanname); if (resolvedclass != null && !mbd.hasbeanclass() && mbd.getbeanclassname() != null) { mbdtouse = new rootbeandefinition(mbd); mbdtouse.setbeanclass(resolvedclass); } // prepare method overrides. try { mbdtouse.preparemethodoverrides(); } catch (beandefinitionvalidationexception ex) { throw new beandefinitionstoreexception(mbdtouse.getresourcedescription(), beanname, "validation of method overrides failed", ex); } try { // give beanpostprocessors a chance to return a proxy instead of the target bean instance. //如果bean配置了postprocessor,那么这里返回的是一个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 { object beaninstance = docreatebean(beanname, mbdtouse, args); if (logger.isdebugenabled()) { logger.debug("finished creating instance of bean '" + beanname + "'"); } return beaninstance; } catch (beancreationexception ex) { // a previously detected exception with proper bean creation context already... throw ex; } catch (implicitlyappearedsingletonexception ex) { // an illegalstateexception to be communicated up to defaultsingletonbeanregistry... throw ex; } catch (throwable ex) { throw new beancreationexception( mbdtouse.getresourcedescription(), beanname, "unexpected exception during bean creation", ex); } } //接着到docreate中去看看bean是怎样生成的 protected object docreatebean(final string beanname, final rootbeandefinition mbd, final object[] args) { // instantiate the bean. //用来持有创建出来的bean对象 beanwrapper instancewrapper = null; //如果是单例,则先把缓存中的同名bean清除 if (mbd.issingleton()) { instancewrapper = this.factorybeaninstancecache.remove(beanname); } //这里是创建bean的地方,由createbeaninstance来完成 if (instancewrapper == null) { //根据指定bean使用对应的策略创建新的实例,如:工厂方法,构造函数自动注入,简单初始化 instancewrapper = createbeaninstance(beanname, mbd, args); } final object bean = (instancewrapper != null ? instancewrapper.getwrappedinstance() : null); class<?> beantype = (instancewrapper != null ? instancewrapper.getwrappedclass() : null); // allow post-processors to modify the merged bean definition. synchronized (mbd.postprocessinglock) { if (!mbd.postprocessed) { applymergedbeandefinitionpostprocessors(mbd, beantype, beanname); mbd.postprocessed = true; } } // eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like beanfactoryaware. //是否需要提前曝光:单例&允许循环依赖&当前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"); } //为避免后期循环依赖,可以在bean初始化完成前将创建实例的objectfactory加入工厂 addsingletonfactory(beanname, new objectfactory<object>() { @override public object getobject() throws beansexception { //对bean再次依赖引用,主要应用smartinstantialiationaware beanpostprocessor, //其中我们熟知的aop就是在这里将advice动态织入bean中,若无则直接返回bean,不做任何处理 return getearlybeanreference(beanname, mbd, bean); } }); } // initialize the bean instance. //这里是对bean的初始化,依赖注入往往在这里发生,这个exposedobject在初始化处理完后悔返回作为依赖注入完成后的bean object exposedobject = bean; try { //对bean进行填充,将各个属性值注入,其中可能存在依赖于其他bean的属性,则会递归初始化依赖bean populatebean(beanname, mbd, instancewrapper); if (exposedobject != null) { //调用初始化方法,比如init-method 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); // earlysingletonreference 只有在检测到有循环依赖的情况下才会非空 if (earlysingletonreference != null) { if (exposedobject == bean) { //如果exposedobject 没有在初始化方法中被改变,也就是没有被增强 exposedobject = earlysingletonreference; } else if (!this.allowrawinjectiondespitewrapping && hasdependentbean(beanname)) { string[] dependentbeans = getdependentbeans(beanname); set<string> actualdependentbeans = new linkedhashset<string>(dependentbeans.length); for (string dependentbean : dependentbeans) { //检测依赖 if (!removesingletonifcreatedfortypecheckonly(dependentbean)) { actualdependentbeans.add(dependentbean); } } //因为bean创建后其所依赖的bean一定是已经创建的,actualdependentbeans非空则表示当前bean创建后其依赖的bean却没有全部创建完,也就是说存在循环依赖 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."); } } } } // register bean as disposable. try { //根据scope注册bean registerdisposablebeanifnecessary(beanname, bean, mbd); } catch (beandefinitionvalidationexception ex) { throw new beancreationexception(mbd.getresourcedescription(), beanname, "invalid destruction signature", ex); } return exposedobject; }
依赖注入其实包括两个主要过程
- 生产bea所包含的java对象
- bean对象生成之后,把这些bean对象的依赖关系设置好
我们从上可以看到与依赖注入关系特别密切的方法有
createbeaninstance
生成bean包含的java对象
populatebean.
处理对各种bean对象的属性进行处理的过程(即依赖关系处理的过程)
先来看 createbeaninstance源码
/** * create a new instance for the specified bean, using an appropriate instantiation strategy: * factory method, constructor autowiring, or simple instantiation. * @param beanname the name of the bean * @param mbd the bean definition for the bean * @param args explicit arguments to use for constructor or factory method invocation * @return a beanwrapper for the new instance */ protected beanwrapper createbeaninstance(string beanname, rootbeandefinition mbd, object[] args) { // make sure bean class is actually resolved at this point. // 确认需要创建的bean实例的类可以实例化 class<?> beanclass = resolvebeanclass(mbd, beanname); 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()); } supplier<?> instancesupplier = mbd.getinstancesupplier(); if (instancesupplier != null) { return obtainfromsupplier(instancesupplier, beanname); } //若工厂方法非空,则使用工厂方法策略对bean进行实例化 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); } } // need to determine the constructor... // 使用构造函数对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); } // no special handling: simply use no-arg constructor. //使用默认的构造函数对bean进行实例化 return instantiatebean(beanname, mbd); } /** * instantiate the given bean using its default constructor. * @param beanname the name of the bean * @param mbd the bean definition for the bean * @return a beanwrapper for the new instance */ //最常见的实例化过程instantiatebean protected beanwrapper instantiatebean(final string beanname, final rootbeandefinition mbd) { //使用默认的实例化策略对bean进行实例化,默认的实例化策略是 //cglibsubclassinginstantiationstrategy,也就是使用cglib实例化bean try { object beaninstance; final beanfactory parent = this; if (system.getsecuritymanager() != null) { beaninstance = accesscontroller.doprivileged(new privilegedaction<object>() { @override 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); } }
这里使用了cglib对bean进行实例化.cglib是一个字节码生成器的类库,它提供了一系列的api来提供生成和转换java的字节码的功能.
在spring aop中也使用cglib对java的字节码进行增强.在ioc容器中,要了解怎样使用cglib来生成bean对象,需要看一下simpleinstantiationstrategy类.它是spring用来生成bean对象的默认类,它提供了两种实例化bean对象的方法
- 通过beanutils,使用了java的反射功能
- 通过cglib来生成
public class simpleinstantiationstrategy implements instantiationstrategy { @override public object instantiate(rootbeandefinition bd, string beanname, beanfactory owner) { // don't override the class with cglib if no overrides. if (bd.getmethodoverrides().isempty()) { //这里取得指定的构造器或者生成对象的工厂方法来对bean进行实例化 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(new privilegedexceptionaction<constructor<?>>() { @override public constructor<?> run() throws exception { return clazz.getdeclaredconstructor((class[]) null); } }); } else { constructortouse = clazz.getdeclaredconstructor((class[]) null); } bd.resolvedconstructororfactorymethod = constructortouse; } catch (throwable ex) { throw new beaninstantiationexception(clazz, "no default constructor found", ex); } } } //通过beanutils进行实例化,这个beanutils的实例化通过constructor来实例化bean,在beanutils中可以看到具体的调用ctor.newinstance(args) return beanutils.instantiateclass(constructortouse); } else { // 使用cglib来实例化对象 return instantiatewithmethodinjection(bd, beanname, owner); } } }
bean之间依赖关系的处理
依赖关系处理的入口是前面提到的populatebean方法.由于其中涉及的面太多,在这里就不贴代码了.简要介绍一下依赖关系处理的流程:在populatebean方法中,
首先取得在beandefinition中设置的property值,然后开始依赖注入的过程。
首先处理autowire的注入,可以byname或者是bytype,之后对属性进行注入。
接着需要对bean reference进行解析,在对managelist、manageset、managemap等进行解析完之后,就已经为依赖注入准备好了条件,这是真正把bean对象设置到它所依赖的另一个bean属性中去的地方,其中处理的属性是各种各样的。
依赖注入发生在beanwrapper的setpropertyvalues中,具体的完成却是在beanwrapper的子类beanwrapperimpl中实现的,它会完成bean的属性值的注入,其中包括对array的注入、对list等集合类以及对非集合类的域进行注入。
进过一系列的注入,这样就完成了对各种bean属性的依赖注入过程。
在bean的创建和对象依赖注入的过程中,需要依据beandefinition中的信息来递归地完成依赖注入。
从前面的几个递归过程中可以看到,这些递归都是以getbean为入口的。
一个递归是在上下文体系中查找需要的bean和创建bean的递归调用;
另一个递归是在依赖注入时,通过递归调用容器的getbean方法,得到当前bean的依赖bean,同时也触发对依赖bean的创建和注入。
在对bean的属性进行依赖注入时,解析的过程也是一个递归的过程。这样,根据依赖关系,一层层地完成bean的创建和注入,直到最后完成当前bean的创建。有了这个顶层bean的创建和对它属性依赖注入的完成,意味着和当前bean相关的整个依赖链的注入液完成了。
在bean创建和依赖注入完成以后,在ioc容器中建立起一系列依靠依赖关系联系起来的bean,这个bean已经不再是简单的java对象了。该bean系列以及bean之间的依赖关系建立完成之后,通过ioc的相关接口方法,就可以非常方便地供上层应用使用了。
2. lazy-init属性和预实例化
在前面的refresh方法中,我们可以看到调用了finishbeanfactoryinitialization来对配置了lazy-init的bean进行处理。
其实在这个方法中,封装了对lazy-init属性的处理,实际的处理是在defaultlistablebeanfactory这个基本容器的preinstantiatesingleton方法中完成的。该方法对单例bean完成预实例化,这个预实例化的完成巧妙地委托给容器来实现。如果需要预实例化,那么就直接在这里采用getbean去触发依赖注入,与正常依赖注入的触发相比,只有触发的时间和场合不同。在这里,依赖注入发生在容器执行refresh的过程中,即ioc容器初始化的过程中,而不像一般的依赖注入一样发生在ioc容器初始化完成以后,第一次通过getbean想容器索要bean的时候。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
PHP 在Swoole中使用双IoC容器实现无污染的依赖注入
-
springIOC容器依赖注入的原理解析
-
Spring 如何解决循环依赖的问题(IOC原理)
-
在Spring IoC中,依赖注入和依赖查找的数据来源一样吗?
-
Spring IOC DI依赖注入 IOC容器 Spring Bean的声明周期
-
Spring入门 IOC理论,第一个spring程序Di依赖注入,Bean的自动装配
-
spring-依赖注入(DI)&控制反转(Ioc)&Bean的三种装配方式
-
详解C#中的依赖注入和IoC容器
-
ASP.NET Core Web 应用程序系列(一)- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)
-
浅谈Spring IoC容器的依赖注入原理