Spring依赖注入以及使用建议

简介: Spring依赖注入以及使用建议

Spring支持的注入方式

1.字段注入

 @Autowired
 private UserDao userDao;

2.构造器注入

@Component
public class UserService {
 
    private UserDao userDao;
 
    @Autowired
    public UserService(UserDao userDao) {
        this.userDao = userDao;
 
    }
 
}

3.setter注入

@Component
public class UserService {
 
    private UserDao userDao;
 
 
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
 
}

使用构造器注入存在的问题

如果我们的两个Bean循环依赖,就会抛出该异常

Error creating bean with name 'beanOne': Requested bean is currently in creation: ls there an
unresolvable circular reference?

@Component
public class UserService {
    private OrderService orderService;
 
 
    @Autowired
    public UserService(OrderService orderService){
        this.orderService=orderService;
    }
}
@Component
public class OrderService {
 
    private UserService userService;
 
 
    @Autowired
    public OrderService(UserService userService){
        this.userService=userService;
    }
 
}

如果出现两个类循环引用彼此,说明代码的设计存在问题,如果临时无法解决可以使用以下两种解决方法:

1.使用@Lazy注解设置为懒加载,令其中一个类延迟初始化,使得它在首次使用时才进行初始化,OrderService在初始化时可以不需要UserService的实例,避免了循环依赖的问题

@Component
@Lazy
public class UserService {
    private OrderService orderService;
 
    @Autowired
    public UserService(@Lazy OrderService orderService) {
        this.orderService = orderService;
    }
}
 
@Component
public class OrderService {
    private UserService userService;
 
    @Autowired
    public OrderService(UserService userService) {
        this.userService = userService;
    }
}

2.使用setter注入,将构造器注入修改为setter注入,这样可以确保构造函数的参数已经被完全初始化,避免了循环依赖的问题。

@Component
public class UserService {
    private OrderService orderService;
 
    public UserService() {}
 
    @Autowired
    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }
}
@Component
public class OrderService {
    private UserService userService;
 
    public OrderService() {}
 
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}

Spring为何不建议使用基于字段的依赖注入

当你使用字段注入IDEA会给你如下警告

spring官网文档也指出强制依赖使用构造函数注入,可选依赖使用setter注入

官网文档地址:

使用字段注入会带来如下问题:

1.单一职责问题

我们都知道,根据SOLID设计原则来进,一个类的设计应该符合单一职责原则,就是一个类只能做一件功能,当我们使用基于字段注入的时候,随着业务的暴增,字段越来越多,我们是很难发现我们已经默默中违背了单一职责原则的。

但是如果我们使用基于构造器注入的方式,因为构造器注入的写法比较臃肿,所以它就在间接提醒我们违背了单一职责原则,该做重构了

//基于字段注入
@Component
public class OrderService {
 
    @Autowired
    private UserService userService;
    @Autowired
    private GoodsService goodsService;
 
}
//基于构造器的注入
@Component
public class OrderService {
    
    private UserService userService;
    private GoodsService goodsService;
    
    @Autowired
    public OrderService(UserService userService ,GoodsService goodsService){
        this.userService=userService;
        this.goodsService=goodsService;
    }
}

2.可能产生NPE空指针异常

对于一个bean来说,它的初始化顺序为:静态变量或静态语句块 ->实例变量或初始化语句块 -> 构造方法 -> @Autowired。

所以,在静态语句块,初始化语句块,构造方法中使用Autowired表明的字段,都会引起NPE问题

@Component
public class OrderService {
    @Autowired
    private UserService userService;
  
    private String orderId;
 
 
 
    public OrderService(){
        //此时的OrderService还未初始化,会抛出空指针异常
        this.orderId= userService.getUserId();
    }
}

相反的,用构造器的依赖注入,就会实例化对象,在使用的过程中字段一定不为空

3.隐藏依赖

对于一个正常的使用依赖注入的Bean来说,它应该“显式”的通知容器,自己需要哪些Bean,可以通过构造器通知,public的setter方法通知,这些设计都是没问题的。

外部容器不应该感知到Bean内部私有字段(如上例中的private UserService)的存在,私有字段对外部应该是不可见的。由于私有字段不可见,所以在设计层面,我们不应该通过字段注入的方式将依赖注入到私有字段中。这样会破坏封装性。

所以,当我们对字段做注入的时候,Spring就需要关心一个本来被我们封装到一个bean中的私有成员变量,这就和他的封装性违背了。因为我们应该通过setter或者构造函数来修改一个字段的值。

4.不利于测试

很明显,使用了Autowired注解,说明这个类依赖了Spring容器,这让我们在进行UT的时候必须要启动个Spring容器才可以测试这个类,显然太麻烦,这种测试方式非常重,对于大型项目来说,往往启动一个容器就要好几分钟,这样非常耽误时间。

不过,如果使用构造器的依赖注入就不会有这种问题,或者,我们可以使用Resource注解(@Resource是Java EE提供的注解,更加通用且符合J2EE标准,可以在不同的Java EE容器中使用)也可以解决上述问题。

目录
相关文章
|
1月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
1月前
|
Java 数据库 数据安全/隐私保护
轻松掌握Spring依赖注入:打造你的登录验证系统
本文以轻松活泼的风格,带领读者走进Spring框架中的依赖注入和登录验证的世界。通过详细的步骤和代码示例,我们从DAO层的创建到Service层的实现,再到Spring配置文件的编写,最后通过测试类验证功能,一步步构建了一个简单的登录验证系统。文章不仅提供了实用的技术指导,还以口语化和生动的语言,让学习变得不再枯燥。
49 2
|
6月前
|
XML Java 测试技术
Spring Boot中的依赖注入和控制反转
Spring Boot中的依赖注入和控制反转
|
8月前
|
XML Java 程序员
Spring6框架中依赖注入的多种方式(推荐构造器注入)
依赖注入(DI)是一种过程,对象通过构造函数参数、工厂方法的参数或在对象实例构建后设置的属性来定义它们的依赖关系(即与其一起工作的其他对象)。
141 3
|
8月前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
75 0
|
5月前
|
设计模式 自然语言处理 Java
简单了解下Spring中的各种Aware接口实现依赖注入
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
53 2
|
5月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
78 0
|
5月前
|
自然语言处理 Java 开发者
简单了解下Spring中的各种Aware接口实现依赖注入
【8月更文挑战第21天】在Spring框架中,Aware接口系列是一种特殊的机制,它允许Bean在初始化过程中获取到Spring容器或容器中的特定资源,从而实现了更加灵活和强大的依赖注入方式。本文将围绕Spring中的各种Aware接口,详细探讨它们如何帮助开发者在工作和学习中更好地实现依赖注入。
145 0
|
6月前
|
缓存 Java Spring
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
|
7月前
|
设计模式 Java 测试技术
Spring Boot中的依赖注入详解
Spring Boot中的依赖注入详解