本文小编为大家详细介绍“Spring依赖注入的方式有哪些及原理是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring依赖注入的方式有哪些及原理是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。在Spring中提供了三种实现依赖注入的方式:字段注入、构造器注入、Setter方法注入
。首先我们先创建一个Service层的接口以及对应的实现类,基于以下实现类来实现依赖注入的方式:Spring中通过@Autowired注解,可以完成注入。字段注入是三种注入方式最简单、最常用的一种方式,但是也是最需要避免使用的一种方式。那为什么要避免使用呢?接下来进行分析一下。在ClientService
类中,我们定义了一个私有化的变量userService
来注入该接口的实例,但是这个实例只能在ClientService
类中访问到,脱离容器环境无法访问到。如上图执行结果抛出NullPointerException
空指针异常,原因很简单无法在ClientService 类的外部实例化UserService 对象。采用字段注入的话,类与容器的耦合度较高,无法脱离容器使用目标对象。这就得出了避免使用字段注入的第一个原因:对象的外部可见性较差。避免使用字段注入第二个原因:可能导致潜在的循环依赖。循环依赖指的是两个类之间互相进行注入。代码如下如上代码显然,ClassA和ClassB发生循环依赖。在Spring启动的时候不会发生错误,但是在使用具体的某个类时会报错。构造器注入就是使用类的构造函数来完成对象的注入。通过构造器注入可以解决对象的外部可见性的问题,因为userService
是通过ClientService
构造函数进行注入的。基于构造器注入,回顾一下之前循环依赖的问题。代码如下在Spring项目启动的时候,会抛出循环依赖异常,可以提醒开发者避免使用循环依赖。但是构造器注入也是有问题的,当构造函数中存在较多的依赖对象时,大量的构造函数参数回访代码出现冗余。接下来就引入Setter方法注入。Setter方法注入代码如下Setter注入相比于构造器注入可读性更强,可以将多个实例对象通过多个Setter方法逐一进行注入。回顾之前的循环依赖问题。代码如下在ClassA 和ClassB 作用域都为单例bean的前提下,代码正常执行。总结:Setter适合可选对象的注入;构造方法适合强制对象的注入;字段注入避免使用。前面介绍完依赖注入的三种实现方式,接下来结合Spring源码深入的了解下依赖注入的原理,通过Bean 注册和Bean 实例化两个模块进行阐述。在Spring中我们往往通过一个应用的上下文(ApplicationContext
)对象来操作各种Bean。xxxApplicationContext
接口在Spring中就代表一个Spring IOC 容器,Spring中存在大量的ApplicationContext
接口的实现类。如果基于注解的配置方式,就使用AnnotationConfigApplicationContext
来初始化上下文容器对象。接下来进入AnnotationConfigApplicationContext
的源码,查看其构造函数如下:通过以上两个构造函数可以看出,一个是根据注解配置类注册Bean,另一个通过包路径扫描Bean。点击进入register
方法:Notethat{@link#refresh()}mustbecalledinorderforthecontext
*tofullyprocessthenewclasses.
*@paramcomponentClassesoneormorecomponentclasses—forexample,
*{@linkConfiguration@Configuration}classes
*@see#scan(String…)
*@see#refresh()
*/
@Override
publicvoidregister(Class>…componentClasses){
Assert.notEmpty(componentClasses,”Atleastonecomponentclassmustbespecified”);
this.reader.register(componentClasses);
}通过this.reader.register(componentClasses);
可以看出,调用当前对象reader
里面的register
方法,而reader
实际上是AnnotatedBeanDefinitionReader
工具类来完成Bean的注册。继续点进register方法:Callsto{@coderegister}areidempotent;addingthesame
*componentclassmorethanoncehasnoadditionaleffect.
*@paramcomponentClassesoneormorecomponentclasses,
*e.g.{@linkConfiguration@Configuration}classes
*/
publicvoidregister(Class>…componentClasses){
for(Class>componentClass:componentClasses){
registerBean(componentClass);
}
}
/**
*Registerabeanfromthegivenbeanclass,derivingitsmetadatafrom
*class-declaredannotations.
*@parambeanClasstheclassofthebean
*/
publicvoidregisterBean(Class>beanClass){
doRegisterBean(beanClass,null,null,null,null);
}AnnotatedBeanDefinitionReader
会遍历所有的componentClasses
组件类,通过registerBean
方法中的doRegisterBean
方法完成Bean的注册。进入doRegisterBean
:总的来看:① 首先需要构造描述bean实例化信息的BeanDefinition
对象,需要将注解配置类信息转化为AnnotatedGenericBeanDefinition
类型,此处的AnnotatedGenericBeanDefinition
就是一种BeanDefinition
类型,包含了Bean的构造函数参数,属性值以及添加的注解信息。
② 设置BeanDefinition
属性,完成对@Scope、@Lazy、@Primary
等注解的处理
③ 最后通过registerBeanDefinition()
方法完成Bean的注册。现在Spring IOC容器对Bean的创建过程并没有完成,目前只是将Bean的定义加载到了容器中,但是可能容器本身已经存在这些Bean的定义,所以需要使用refresh()方法刷新容器,回到最开始进入AnnotationConfigApplicationContext
的源码,查看其构造函数如下:接下来分析refresh
方法,点击进入:可以看出obtainFreshBeanFactory
完成对Bean的注册返回一个BeanFactory
。而finishBeanFactoryInitialization
方法真正完成Bean实例化的入口。真正完成实例化的方法为DefaultListableBeanFactory
类中的preInstantiateSingletons
方法,进入此方法:进入到getBean
()方法:Bean的初始化过程就在这个方法中。在当前的抽象类AbstractBeanFactory
中有一个抽象方法createBean
如下:在Spring中实现这个抽象方法的唯一BeanFactory是AbstractAutowireCapableBeanFactory
,真正完成Bean创建是在doCreateBean
:最后进入到doCreateBean
如下:总的来看:①createBeanInstance
方法用于根据配置生成具体的Bean,最终通过反射方法实现,执行完后Bean已经被创建,但是不完整,没有属性的注入。
②populateBean
方法用于实现属性的自动注入,包含byName、byType、@Autowired、@Value属性的设置,执行完之后Bean就是完整的。
③i免费云主机域名nitializeBean
方法是一种扩展性的机制,用于Bean初始化完成后的一些定制化操作。读到这里,这篇“Spring依赖注入的方式有哪些及原理是什么”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注百云主机行业资讯频道。
这篇文章主要介绍“vue引入jssdk的方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue引入jssdk的方法是什么”文章能帮助大家解决问题。1.首先,在vue-cli中创建一个vue.js项目;vue c…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。