依赖注入 DI(Dependecy Injection)
一个Java对象依赖别的对象,一种依赖关系,如service依赖dao,只声明对象不赋值均为null,通过注入自动装配对象实例
控制反转 IoC(Inversion of Control)
不需要控制所有依赖和装配的进行,有容器会自动进行装配
下面的案例,简单的实现IoC容器,可帮助理解依赖注入和控制反转
(在这个demo中是基于maven搭建的,使用了springframework的Autowired,但不重要,自己生成一个注解替换即可)
简单的讲讲实现的流程
- 在
resource
目录下新建一个properties
配置文件,用来配置需要自动装配的bean服务和对应限定全类名,它可能长这样: - 在需要自动装配的对象使用对应的注解,
如在UserService
类中依赖了UserDao
对象,添加一个@Autowired
注解(是不是Autowired
不重要,注解可自行替换)
1 | java复制代码public class UserService { |
- (以下代码贴在最后)启动容器时,用
new Properties("[你的配置文件路径]")
读取配置文件的内容,获取到的是配置的服务名和其限定全类名 - 声明一个
Map
用于存储即将要通过反射生成的对象实例,遍历properties
对象,通过Class.forName("全类名").getConstructor().newInstance()
获取对象实例,再通过map.put(服务名,对象实例)
存储 - 遍历
Map
,获取反射生成的对象的class
对象,调用其getDeclaredFields()
方法拿到全部字段,筛选出字段含有@Autowired
注解的字段,并返回一个Field
对象数组 - 遍历这个Field对象数组,拿到字段的名字,并将
private
的属性设置成可访问状态,调用field.setAccessible(true)
后,调用field.set()
传入字段对应的对象实例和要赋值的对象,要赋值的对象从Map.get(fieldName)
获取 - 依赖注入的过程到此结束
- 可以通过暴漏一个Api叫
getBean
的方法,传入bean
的名字,返回Map.get([name])
来获取Bean
实例
(需要通过约束属性名的方式进行注入,即属性名要和配置文件中的一致,否则注入时会找不到Map中对应的实例,属性也会为null)
核心代码
UserService中依赖UserDao,使用注解标识
1 | java复制代码public class UserService { |
UserDao
1 | java复制代码public class UserDao { |
容器代码
1 | java复制代码import org.springframework.beans.factory.annotation.Autowired; |
UserService中,只声明了userDao属性而没赋值,通过打断点,可以观察到userDao对象成功注入了,如果有多个地方的userDao使用注解注入,则可在调试中观察到得到的是同一个对象实例
userDao的方法也正常执行,打印输出并会返回一个mock的User对象
Spring的核心实现会比这个复杂的多,但本质上都是通过配置-反射-自动装配的流程处理程序,并不是要手写出一个Spring框架,而是通过手写类似的模式来加深对Spring的理解。
本文转载自: 掘金