Spring依赖注入(IOC)那些事
小菜使用Spring有几个月了,但是对于它的内部原理,却是一头雾水,这次借着工作中遇到的一个小问题,来总结一下Spring。
Spring依赖注入的思想,就是把对象交由Spring容器管理,使用者只需声明什么时候需要对象 ,这个可以说是常识,在这就不多说啦。
小菜的项目中,为了提高代码运行效率,需要在类实例化的时候初始化一个列表,避免重复查询,于是小菜想当然的写了如下代码:
@Component
public class ApplyStatusHandler{
@Autowired
private DictMgr dictMgr;
@Autowired
private ApplyMgr applyMgr; public ApplyStatusHandler(){
//这里初始化列表,使用了dictMgr、applyMgr
}
}
但实际测时,发现列表是空的。。。小菜刚开始还以为是构造方法没有执行,但通过异常捕获发现原来是出现了空指针。
接下来分析一下为啥会出现空指针。
@Component注解,意思大致就是告诉Spring,要把ApplyStatusHandler类的对象放到容器里,以后可以方便的使用@Autowired进行注入。
@Autowired注解,有以下两个重要特点:
+可以对成员变量、方法和构造函数进行标注,来完成自动注入。
+是根据类型进行自动注入的,如果spring配置文件中存在多个相同类型的bean时,或者不存在指定类型的bean,都会抛出异常。
其中,对成员变量的注解,就如上例所示,可以直接从Spring容器中拿到此类型的对象,注入到成员变量中。
对方法的注解,小菜的理解就是对方法的参数进行初始化。例如:
@Autowired
public void initXXXX(DictMgr dictMgr){
//这里可以拿到DictMgr类的对象dictMgr
}
此方法因为有@Autowired标识,所以Spring会自动执行此方法,并且在执行的时候,去自己的容器找寻找和该方法参数类型一致的对象,进行注入,这样在方法中就可以拿到需要的对象了,其实和成员变量的注解大同小异,只不过把变量换了一个地方而已。
对于以上两种方法,有一个必要的前提:对象必须是存在的(ApplyStatusHandler类的对象)!
很容易理解,无论是对成员变量的注入,还是对方法参数的注入,都必须保证变量所在的对象是存在的,否则无从注入。
到这,读者应该能明白为什么会出现空指针,因为Spring先调用的构造方法,此时还没有进行注入。
幸好还有构造方法注入(和方法注入一样的道理),既然是构造方法注入,那么在Spring调用构造方法时,应该就可以拿到对象,然后再使用,就不会出现空指针,于是小菜把代码改成如下形式:
@Component
public class ApplyStatusHandler{ private DictMgr dictMgr;
private ApplyMgr applyMgr; @Autowired
public ApplyStatusHandler(DictMgr dictMgr,ApplyMgr applyMgr){
this.dictMgr=dictMgr;
this.applyMgr=applyMgr; //这里初始化列表,使用了dictMgr、applyMgr
} }
小菜满怀信心的启动项目,的确是没报空指针异常,但却报了很多Spring内部的异常。。。
经过一番搜索,原来是由于小菜声明了一个带参数的构造方法,导致默认的无参数构造方法被抹掉,而这种情况下Spring实例化ApplyStatusHandler类,必须要有无参数的构造方法,因此加上即可(方法中可以什么也不做,但必须要有):
public ApplyStatusHandler(){}
这下再启动项目,完美运行,说明对象已经成功注入到了构造方法中。
如果我们不继续思考,事情可能就到此结束了,但是:既然这个无参构造方法是必须的,就说明Spring必然要调用这个方法,但调用了无参的构造方法,小菜写的有参构造方法是怎么调用的呢?总不会同时调用两个吧?
其实,这和Spring底层的实例化方式有关。
读者可能非常了解什么依赖注入,交由Spring容器管理,但底层究竟是怎么实现的呢?
据小菜不完全了解,应该是有两种实现方式:JDK动态代理和Cglib动态代理。
JDK动态代理,需要实现InvocationHandler 接口,也就是说如果想使用这种代理方式创建对象,需要让类先实现InvocationHandler 接口才行,最终创建的对象是一个新类的对象。
Cglib动态代理,采用的是继承方式,它会在底层创建一个类,来继承原有的类,但是这个子类所有的方法都是直接调用父类去实现,相当于父类的一个代理、封装(封装的目的是支持事务处理),实际上我们在程序中使用的是这个子类的对象,并不是ApplyStatusHandler的对象。
通过这两种代理方式,才让Spring可以支持事务、管理对象。
本例中,小菜的这个类并没有实现InvocationHandler 接口,也就是说,不会使用JDK动态代理,而是使用Cglib动态代理来实例化对象,因此Spring会创建一个类来继承ApplyStatusHandler,然后根据ApplyStatusHandler类的构造方法实例化ApplyStatusHandler,再把子类实例化,让子类持有这个父类的引用,最终注入到变量中的是子类。
由此可以看出,我们通过在构造方法上使用@Autowired注入对象是正确的,ApplyStatusHandler类能成功实例化,但由于有子类需要继承ApplyStatusHandler,因此ApplyStatusHandler中必须有一个空的构造方法,否则子类是无法实例化的(java基础。。。)。
总之,ApplyStatusHandler类中的无参构造方法,是用来实例化Cglib生成的代理子类;有参构造方法是为了完成注入。
好啦,小菜的分享到此结束~~
水平有限,高手勿喷
为了方便读者研究,小菜贴出一些链接供读者参考:
+java 动态代理proxy VS cglib的动态代理的区别
+能不能在spring中首先用构造函数方式注入,然后再用setter注入
Spring依赖注入(IOC)那些事的更多相关文章
- Helloworld之Spring依赖注入/控制反转(DI/IoC)版
Helloworld之Spring依赖注入/控制反转(DI/IoC)版 作者:雨水, 日期:2014-10-29 摘要:本文主要用于培训刚開始学习的人理解Spring中的依赖注入的基本概念. 先介绍依 ...
- 1.4 Spring 依赖注入(DI)和控制反转(IOC)详解
自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html 1.1 Spring 依赖注 ...
- Spring依赖注入原理分析
在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ...
- java后端开发三年!你还不了解Spring 依赖注入,凭什么给你涨薪
前言 前两天和一个同学吃饭的时候同学跟我说了一件事,说他公司有个做了两年的人向他提出要涨薪资,他就顺口问了一个问题关于spring依赖注入的,那个要求涨薪的同学居然被问懵了...事后回家想了想这一块确 ...
- Spring依赖注入三种方式详解
在讲解Spring依赖注入之前的准备工作: 下载包含Spring的工具jar包的压缩包 解压缩下载下来的Spring压缩包文件 解压缩之后我们会看到libs文件夹下有许多jar包,而我们只需要其中的c ...
- Spring依赖注入 --- 简单使用说明
Spring依赖注入 --- 简单使用说明 本文将对spring依赖注入的使用做简单的说明,enjoy your time! 1.使用Spring提供的依赖注入 对spring依赖注入的实现方法感兴趣 ...
- Spring依赖注入 --- 模拟实现
Spring依赖注入 --- 模拟实现 面向接口编程,又称面向抽象编程, 数据库如果发生更改,对应的数据访问层也应该改变多写几个实现,需要用谁的时候在service里new谁就可以了面向抽象编程的好处 ...
- Spring依赖注入的三种方式
看过几篇关于Spring依赖注入的文章,自己简单总结了一下,大概有三种方式: 1.自动装配 通过配置applicationContext.xml中的标签的default-autowire属性,或者标签 ...
- 二十7天 春雨滋润着无形 —Spring依赖注入
6月11日,明确."夏条绿已密,朱萼缀明鲜.炎炎日正午,灼灼火俱燃." IT人习惯把详细的事物加工成的形状一致的类.正是这种一致,加上合适的规范.才干彰显对象筋道的牙感和bean清 ...
随机推荐
- 京东B2B的4种供销模式
B2B的4种供销模式,以京东商城为例: FBP 京东给商家一个独立操作的后台, 商家五地入库(北京,上海,广州,成都,武汉),从仓储 到配送 到客服都是京东来操作, 京东本身自营的产品所有能享 ...
- MFC中控制COMBOBOX控件的下拉框高度
这是使用Visual Stiduo的小技巧哦.今天上网找来的.在界面设计面板上,点击ComboBox的下拉箭头,会另外出现一个虚边框.可以调整其大小.这个就是实现运行的时候下拉边框的默认值啦.
- DIOCP之获取在线用户列表
通过获取tcpserver.getonlinecontextlist来得到在线列表 procedure TfrmMain.btn_refreshClick(Sender: TObject);var l ...
- Android菜鸟成长记5-ADB和sqllite
Android开发环境中,ADB是我们进行Android开发经常要用的调试工具,它的使用当然是我们Android开发者必须要掌握的. ADB概述 Android Debug Bridge,Androi ...
- Redis和Memcached对比
Redis和Memcached对比 这两年 Redis火得可以,Redis也常常被当作 Memcached的挑战者被提到桌面上来.关于Redis与Memcached的比较更是比比皆是.然而,Redis ...
- DrawerLayout学习,抽屉效果
第一节: 注意事项 *主视图一定要是DrawerLayout的第一子视图 *主视图宽度和高度匹配父视图,因为当你显示主视图时,要铺满整个屏幕,用户体验度较高 *必须显示指定的抽屉视图的android: ...
- linux磁盘与文件系统的管理
本文涉及命令:dumpe2fs.df.du.fdisk.mkfs.mke2fs.fsck.badblocks.mount.umount.e2label.tune2fs.hdparm.parted 概念 ...
- 算法与数据结构实验题 5.2 Missile
1.题目: 2.解题思路: 把每个点对应的两条半径求出,之后对d1进行升序排序,对应d2也改变位置.其中一个圆心的半径r1确定之后,除去第一个圆包围的点,在其余点中找到另外一个圆的最长的半径r2,此时 ...
- Eclipse+Mingw+Boost 环境搭建
一.安装CDT插件 Eclipse是用Java的swt开发的,所以需要java虚拟机才能运行,jdk的配置方法网上一大堆,这里就不细说了.安装CDT的方法简单提一下,到Help->Eclipse ...
- 10 个强大的开源 Web 流量分析工具(转帖)
Web 流量分析工具多不胜数,从 WebTrends 这样专业而昂贵的,到 Google Analytics 这样强大而免费的,从需要在服务器端单独部署的,到可以从前端集成的,不一而足.本文收集并介绍 ...