首页 > 其他分享 >spring 依赖注入

spring 依赖注入

时间:2022-11-06 22:59:02浏览次数:83  
标签:依赖 构造方法 Autowired spring Spring 注入 setter

1. 几种注入方式的对比

基于 field 注入的坏处

成也萧何败也萧何

基于 field 注入虽然简单,但是却会引发很多的问题。这些问题在我平常开发阅读项目代码的时候就经常遇见。

  • 容易违背了单一职责原则 使用这种基于 field 注入的方式,添加依赖是很简单的,就算你的类中有十几个依赖你可能都觉得没有什么问题,普通的开发者很可能会无意识地给一个类添加很多的依赖。但是当使用构造器方式注入,到了某个特定的点,构造器中的参数变得太多以至于很明显地发现 something is wrong。拥有太多的依赖通常意味着你的类要承担更多的责任,明显违背了单一职责原则(SRP:Single responsibility principle)。

  • 依赖注入与容器本身耦合依赖注入框架的核心思想之一就是受容器管理的类不应该去依赖容器所使用的依赖。换句话说,这个类应该是一个简单的 POJO(Plain Ordinary Java Object)能够被单独实例化并且你也能为它提供它所需的依赖。这个问题具体可以表现在:

    • 你的类不能绕过反射(例如单元测试的时候)进行实例化,必须通过依赖容器才能实例化,这更像是集成测试
    • 你的类和依赖容器强耦合,不能在容器外使用
    • 不能使用属性注入的方式构建不可变对象(final 修饰的变量)

Spring 开发团队的建议

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies.

简单来说,就是

  • 强制依赖就用构造器方式
  • 可选、可变的依赖就用 setter 注入当然你可以在同一个类中使用这两种方法。构造器注入更适合强制性的注入旨在不变性,Setter 注入更适合可变性的注入。

让我们看看 Spring 这样推荐的理由,首先是基于构造方法注入

❝The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.❞

Spring 团队提倡使用基于构造方法的注入,因为这样一方面可以将依赖注入到一个不可变的变量中 (注:final 修饰的变量),另一方面也可以保证这些变量的值不会是 null。此外,经过构造方法完成依赖注入的组件 (注:比如各个 service),在被调用时可以保证它们都完全准备好了。与此同时,从代码质量的角度来看,一个巨大的构造方法通常代表着出现了代码异味,这个类可能承担了过多的责任。

而对于基于 setter 的注入,他们是这么说的:

❝Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later.❞

基于 setter 的注入,则只应该被用于注入非必需的依赖,同时在类中应该对这个依赖提供一个合理的默认值。如果使用 setter 注入必需的依赖,那么将会有过多的 null 检查充斥在代码中。使用 setter 注入的一个优点是,这个依赖可以很方便的被改变或者重新注入。

Spring官方为什么建议构造器注入?

关键就是,field注入不建议,依赖对象可能为null而报空指针异常,setter注入适用于可变的属性注入,构造器更全面,可以保证属性不可变,但是如果构造属性过多,维护成本过高。

相关文档:
想用@Autowired注入static静态成员?官方不推荐你却还偏要这么做

Spring Beans and Dependency Injection

Spring选择哪种注入方式

2, 基于构造器注入

基于 constructor 注入
将各个必需的依赖全部放在带有注解构造方法的参数中,并在构造方法中完成对应变量的初始化,这种方式,就是基于构造方法的注入。比如:

private final Svc svc;

@Autowired
public HelpService(@Qualifier("svcB") Svc svc) {
    this.svc = svc;
}

在 Spring 4.3 及以后的版本中,如果这个类只有一个构造方法,那么这个构造方法上面也可以不写 @Autowired 注解。

If a bean has one constructor, you can omit the @Autowired, as shown in the following example:

@Service
public class DatabaseAccountService implements AccountService {

	private final RiskAssessor riskAssessor;

	public DatabaseAccountService(RiskAssessor riskAssessor) {
		this.riskAssessor = riskAssessor;
	}

	// ...

}

注意前提条件:只有一个构造方法的时候,@Autowired注解才能省略。

3.将bean注入到static field中(工具类场景)

一般spring中实现的工具类,如果要引入,都需要先注入,但是如果工具类做成static,那么可以避免大量的Autowired工具类的bean。

有两种方式,一种是用setter注入到static属性,一种是用构造方法设置到static属性。
示例:

@Component
public class EncryptUtils {
	private static final EncryptService encryptService;
	//setter注入
	@Autowired
	public void setEncryptService(EncryptService encryptService) {
		this.encryptService=encryptService;
	}
	
	//构造器注入,由于只有一个构造器,所以Autowired省略
	public EncryptUtils(EncryptService encryptService) {
			this.encryptService=encryptService;
	}

}

标签:依赖,构造方法,Autowired,spring,Spring,注入,setter
From: https://www.cnblogs.com/cord/p/16864521.html

相关文章

  • springboot
    1、HelloSpringbBoot创建maven项目引入依赖<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</......
  • SpringMVC源码-文件上传
    一、环境配置IndexController.java@GetMapping("/file")publicStringfile(){ return"fileUpload";}@PostMapping("/fileUpload")publicvoidfileUpload(Mul......
  • [springboot]字符串与Date互转
    @DatapublicclassxxxQuery{//字符串转Date@DateTimeFormat(pattern="<dateformate>")privateDatedate;} @DatapublicclassxxxVO{//......
  • YUM下载全量依赖
        在离线的内网环境下进行安装一些软件的时候会出现依赖不完整的情况,一般情况下会使用如下方式进行下载依赖包    查看依赖包可以使用yum deplist进行查找[roo......
  • Spring事务
    传播特性REQUIRED当前方法存在事务时,子方法加入该事务。此时父子方法共用一个事务,无论父子方法哪个发生异常回滚,整个事务都回滚。即使父方法捕捉了异常,也是会回滚。而当......
  • GraalVM & Spring Boot初体验
    前言这两天封在家里,一直在琢磨想去把这个博客项目改成微服务的形式。不过就目前而言我的服务器内存放好几个Java进程是吃不消的,原因在于一个独立的JVM所占用的内存资源太......
  • Maven项目中pom.xml全部报红,依赖导入不成功,jar包不下载等类似问题,迄今为止所有解决方
    参考声明:https://blog.csdn.net/Avril___/article/details/104603345相信大家在导入新的项目时候会遇到pom文件报红,或者右侧依赖报红等类似情况,博主将这种错误的所有解......
  • Spring Security安全控制之快速入门
    在SpringCloud之服务注册中心搭建EurekaServer服务注册中⼼-池塘里洗澡的鸭子-博客园(cnblogs.com)中,一旦启动了Eureka服务器,就可以直接Eureka服务器管理界面—......
  • SpringBootJPA多表多条件查询(参数可能为空)语句
    @Query(value="SELECTc.bynameasbyname,c.cartascart,c.phoneasphone,c.surnameassurname,c.idasid,c.update_timeasupdateTime,c.head_imgasheadImg,c.i......
  • 使用idea将springboot打包成war包
    一、pom文件的配置:1.war打包方式设置为war。(不属于关键步骤)这里可以设置打包后的war包名。也是访问的时候的工程名。注:(打成war包访问的时候要加工程名),访问时如果忘记......