小菜使用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生成的代理子类;有参构造方法是为了完成注入。
好啦,小菜的分享到此结束~~
水平有限,高手勿喷
相关推荐
### Spring IoC与注解依赖注入详解 #### 一、Spring框架简介 Spring框架是由Rod Johnson创建的一个开源项目,最初是为了解决企业级应用开发中的复杂性问题而诞生的。Spring框架的核心特性包括IoC(Inversion of ...
Spring的核心特性之一就是它的Inversion of Control(IoC,控制反转)容器,也被称为Dependency Injection(DI,依赖注入)。这个概念是Spring框架使应用程序组件之间解耦的关键。让我们深入探讨一下Spring的IoC和...
Spring依赖注入(Dependency Injection,简称DI)是Java应用开发中常用的设计模式,它极大地提高了代码的可测试性和可维护性。在Spring框架中,依赖注入是核心特性之一,通过控制反转(Inversion of Control,IoC)...
- **Spring.NET**:Spring.NET是.NET平台上的Spring框架,它提供了一整套企业级开发所需的工具和框架,包括依赖注入支持。 - **Unity**:Unity是一个由Microsoft开发的轻量级IoC Container,支持多种依赖注入模式,...
在传统的软件设计中,对象的创建和依赖关系的维护通常由代码自身来完成,而在Spring Ioc中,这些控制权被反转给了Spring容器,使得对象的生命周期管理和依赖注入变得更为灵活和可扩展。 **一、控制反转(IoC)概念*...
DI(Dependency Injection,依赖注入)是IOC的一种实现方式,通过配置或编程的方式,将对象之间的依赖关系在运行时动态注入,而不是由对象自己去查找和创建依赖。 在Spring IOC中,主要的注入方式有以下几种: 1. ...
在传统的程序设计中,我们通常手动创建对象并管理它们之间的依赖关系,而在Spring中,这些任务由IOC容器来处理,实现了从依赖管理到依赖注入的转变。 控制反转(IOC)意味着应用程序不再直接创建对象,而是将对象的...
【Spring依赖注入详解】 在Java开发中,Spring框架以其强大的依赖注入(Dependency Injection,简称DI)功能而闻名。依赖注入是一种设计模式,它允许我们解耦组件,使我们的应用程序更加灵活,易于测试和维护。本篇...
Spring框架是Java开发中不可或缺的一部分,它以IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)为核心,极大地简化了应用程序的复杂性。在本教程中,我们将深入探讨如何通过XML配置在...
在这个名为“Spring依赖注入使用setter设注入demo”的示例中,我们将深入探讨如何通过setter方法实现Spring的依赖注入。 首先,理解依赖注入的基本思想:对象之间的依赖关系不是由对象自身管理,而是由外部容器(在...
本资料包"SpringIOC_泛型依赖注入.zip"主要关注的是Spring如何通过泛型进行依赖注入,这是一种更加灵活且类型安全的注入方式。 在Java编程中,泛型是一种强大的特性,允许我们在类、接口和方法中使用类型参数,从而...
依赖注入则是将这种耦合关系反转,由外部容器(如Spring IoC容器)负责创建对象并管理它们的依赖关系,使得对象可以在不知道依赖的具体实现的情况下工作,降低了代码的复杂性。 Spring框架的IoC(Inversion of ...
Spring框架是Java后端开发中的一个关键组件,尤其在依赖注入(Dependency Injection,简称DI)和控制反转(Inversion of Control,简称IOC)领域,它扮演着至关重要的角色。Spring 5.2.9版本是该框架的一个稳定版本...
Spring 框架的核心特性之一就是依赖注入(Dependency Injection,简称DI),也常被称为控制反转(Inversion of Control,IoC)。它是一种设计模式,可以减少代码之间的耦合,提高系统的可测试性和可维护性。在Spring...
**Spring 框架中的控制反转 (IoC) 和依赖注入 (DI)** 在软件开发中,控制反转(Inversion of Control,简称IoC)是一种设计原则,它将对象的创建和管理权从代码中剥离出来,转交给一个外部容器(如Spring框架)。...
浅谈Spring IoC容器的依赖注入原理 Spring IoC容器的依赖注入原理是Spring框架的核心机制之一,负责将服务对象(Bean)实例化并将其提供给客户端使用。依赖注入原理可以分为两个阶段:IoC容器初始化和Bean实例化。 ...
Spring IOC,全称为Inversion of Control,中文常译为“控制反转”或Dependency Injection(依赖注入)。它是Spring框架的核心特性,旨在减少代码间的耦合,提高软件组件的可复用性和可测试性。通过IOC,应用程序的...
Spring 三种依赖注入方式 Spring 框架中提供了多种依赖注入方式,其中最常用的三种依赖注入方式分别是接口注入、设值注入和构造函数注入。下面,我们将分别对这三种依赖注入方式进行详细的介绍和分析。 一、接口...
在IT行业中,Spring框架是Java开发中的一个基石,尤其在控制反转(IoC)和依赖注入(DI)方面。依赖注入是一种设计模式,它允许我们解耦组件,提高代码的可测试性和可维护性。Spring框架通过IoC容器来实现DI,让我们...