这篇文章主要介绍了Spring当中的依赖注入(DI),以及他的简单实现原理,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
什么是依赖注入?
- Dependency Injection。它是 spring 框架核心 ioc 的具体实现。
- 我们的程序在编写时,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。通过容器只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。
- 那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
依赖注入的原理
所谓的依赖注入其实就是通过反射给成员变量赋值,这里的成员变量就是我们所说的依赖。比如TestController当中有个TestService对象,他需要依赖TestService对象当中的方法,那么TestService就是TestController的依赖。
这里就考验到了通过反射我们有几种方式可以给TestService赋值,一共有如下三种:
- 通过构造器给变量赋值
- 通过set方法给变量赋值
- 直接给属性赋值
下面我们直接通过案例来理解:
下面是正常的一个controller调用service的过程,一般我们在TestService这里都会使用一个@Autowired或者@Resource注解,表示由spring进行注入,Spring扫描注解的时候就知道这个变量需要注入,于是他便会去容器当中寻找该对象的实例,然后通过反射将其注入到变量当中。
public class TestController {
private TestService testService;
public TestController() {
System.out.println("TestController初始化了");
}
public TestController(TestService testService) {
this.testService = testService;
}
public void setTestService(TestService testService) {
this.testService = testService;
}
public void method1() {
testService.method1();
}
}
然后service代码如下:
public class TestService {
public TestService() {
System.out.println("TestService初始化了");
}
public void method1() {
System.out.println("method1方法执行了");
}
}
(1)通过构造器给变量赋值:
@Test
public void test5() throws Exception {
Class cls = Class.forName("com.gzl.cn.controller.TestController");
Constructor constructor = cls.getConstructor(TestService.class);
TestController testController = (TestController)constructor.newInstance(new TestService());
testController.method1();
}
运行结果:

(2)通过set方法给变量赋值:
public static void main(String[] args) throws Exception{
Class cls = Class.forName("com.gzl.cn.controller.TestController");
// 根据方法名和参数类型找到对应的set方法
Method mtd = cls.getMethod("setTestService", TestService.class);
// 创建TestController的实例
TestController testController = (TestController)cls.newInstance();
执行TestController实例的这个方法,正常来说TestService不是new的,他会看看容器有没有,有的话取容器的
TestService testService = new TestService();
mtd.invoke(testController, testService);
这时候已经完成属性的注入了
testController.method1();
}
运行结果:

(3)直接给属性赋值:
@Test
public void test6() throws Exception {
Class cls = Class.forName("com.gzl.cn.controller.TestController");
TestController testController = (TestController) cls.newInstance();
// 这时候假如直接访问,会异常,因为testService属性此刻还为空
//testController.method1();
// 这里注意要使用getDeclaredField,不要用getField,因为testService属性并不是public
Field testServiceField = cls.getDeclaredField("testService");
// 这里要设置true,不然修改private修饰符的属性会异常
testServiceField.setAccessible(true);
testServiceField.set(testController, new TestService());
testController.method1();
}
运行结果:

依赖注入本质上就是基于这三种反射注入的方式进行的注入的,只不过给我们提供了相应的注解,方便我们使用,并且他还能够很好的结合IOC容器来使用!