spring框架最核心的就是IOC和AOP,类的实例化、依赖关系等都交由Spring来处理,这样起到了解耦合、利于复用、利于测试的作用 现在常用的注入方式有三种:filed注入;构造函数注入;setter注入;(当然还有xml的方式注入但现在也不常用了吧)
1.filed 注入
就是使用注解的方式注入:
优点:
注入简单,只需在字段上添加@Autowired或@Resource
减少大量冗余代码,美观
新增Field时不需要过多代码修改
在一个类有多个实现的时候可以使用@Autowired配合@Qualifier或@Resource来指定特定实现类
缺点:
对于IOC容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。
使用field注入可能会导致循环依赖,即A类里面注入B类,在B类里面又注入A类:这样会照成启动的时候不会报错,在使用那个bean的时候才会报错
2.构造器注入
使用方式:
@RestController
public class TestController {
private final TestService testService;
@Autowired
public TestController(TestService testService) {
this.testService= testService;
}
}
这是srping4.x 推荐使用的注入方式;
直观可见这种方式代码繁重 相比于filed注入没有那份简洁
但是这种方式解决了filed注入的
1.循环依赖 : 这种方式在有循环依赖的时候,spring项目启动的时候就会抛出BeanCurrentlyInCreationException异常,而不是像filed那种在调用bean的时候抛异常。
2.如果使用field注入,对于IOC容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。调用就抛空指针异常
优点:
依赖不可变:加入了final来约束修饰Field
依赖不可为空:在实例化的时候会检查构造函数参数是否为空,如果为空(未找到改类型的实例对象)则会抛出异常
单一职责:当使用构造函数注入时,如果参数过多,你会发现当前类的职责过大,需要进行拆分。而使用Field注入时,你并不会意识到此问题
更利于单元测试:按照其他两种方式注入,当单元测试时需要初始化整个spring的环境,而采用构造方法注入时,只需要初始化需要的类即可,即可以直接实例化需要的类
避免IOC容器以外环境调用时潜在的空指针异常
避免循环依赖
保证返回客户端(调用)的代码的时候是完全初始化的状态
但是在一个类需要指定实现类的时候就需要使用filed注入方式
3.Setter注入
使用方式:
@RestController
public class TestController {
private TestService testService;
private Test1Service test1Service;
@Autowired
public void setTestService(TestService testService,Test1Service test1Service) {
this.testService= testService;
this.test1Service= test1Service;
}
}
这种方式是在spring3.x刚出来的时候推荐使用;
这种方式:
解决了构造器注入的笨重;
可以让类在之后重新配置或者重新注入。
看起来setter注入的方式比构造器注入方式好点 为啥在spring4.x就推荐构造器注入了呢?
依赖不可变:final关键字
依赖不为空:在实例化的时候会检查构造函数参数是否为空,如果为空(未找到改类型的实例对象)则会抛出异常
完全初始化的状态:这个可以跟上面的依赖不为空结合起来,向构造器传参之前,要确保注入的内容不为空,那么肯定要调用依赖组件的构造方法完成实例化。所以返回来的都是初始化之后的状态。
总的来说呢 根据情况来选择注入方式吧。