依赖注入(Dependency Injection) 是Spring框架的一大特色。咱们可以把它想象成是一种“自动传递东西”的方式,就像你坐电梯不需要自己操作按钮,电梯会帮你到达目的地一样。在程序中,当一个类需要用到另一个类的功能时,不需要自己去创建,而是由Spring自动帮你注入所需的对象。这样做有点像你在做披萨,需要的配料自己不用操心,厨师会给你加好。
对象装配(Object Assembly) 则是Spring中的一个步骤,就像你把积木拼在一起一样。它是通过配置文件或者注解来告诉Spring如何把不同的类组合在一起,形成一个完整的程序。就像你组装一辆汽车,需要把引擎、轮子、座位等组件组合在一起,Spring帮你把各个类组装成一个强大的系统。
首先,我们需要创建一些类,就像你在搭积木,每个类都有自己的功能。然后,在Spring的配置中,你会告诉Spring这些类之间的关系,以及谁需要谁的功能。Spring会在需要的时候,自动把这些类创建并组装起来,就像你玩乐高积木,把各种小块搭建成一个酷炫的模型。
举个例子吧!假设你要开发一个图书管理系统。你有一个 Book
类表示图书,还有一个 Library
类表示图书馆。在Spring中,你可以通过依赖注入,让图书馆知道它需要用到图书,然后Spring会自动给它注入图书的实例。就像你在图书馆借书,不需要自己找,图书管理员会把书递给你一样。
配置这些关系可以通过XML配置文件,也可以使用注解。你可以告诉Spring哪些类需要注入,哪些属性需要赋值,就像你在指挥乐团,把每个乐器的音符安排得和谐动听。
Spring的依赖注入和对象装配让你的代码更加整洁、灵活,让你可以更专注于解决实际问题,而不用纠结于类与类之间的繁琐连接。
Spring提供了多种方法来帮助你将不同的类连接在一起,实现依赖注入。以下是一些常见的依赖注入方式:
属性注入是我们最熟悉,也是日常开发中使用最多的一种注入方式。通过类的属性来注入依赖。这通常需要提供一个设置方法(setter)来设置依赖。就像你在乐高积木上插入一个小块一样,将依赖的类通过属性赋值进来。
@Controller
public class UserController {
// 从 spring 容器中获取 UserService 对象
/**
* 1.属性注入@Autowired 自动装配
*/
@Autowired
private UserService userService;
public void sayHello() {
System.out.println("Hello ");
userService.doService();
}
}
这里的UserService对象就像属性一样直接能被UserController调用,所有叫属性注入。
优点
属性注入最大的优点就是实现简单、使用简单,只需要给变量上添加一个注解(@Autowired),直接获得注入的对象了,所以它的优点就是使用简单。
缺点
Setter 注入 是通过设置方法(setter)来实现依赖注入的方式。这种方法允许你在类中定义一个或多个设置方法,用于注入依赖对象。
/**
* 2.setter注入
*/
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void sayHello() {
System.out.println("Hello ");
userService.doService();
}
优点
完全符合单一职责的设计原则,每一个 Setter 只针对一个对象
缺点
通过构造函数,你可以在创建一个类的实例时传入它所依赖的其他类的实例。就像你在组装一个模型,每个积木块都是构造函数的一个参数,将它们组合在一起就形成了完整的模型。
/**
* 3.构造器注入
*/
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
public void sayHello() {
System.out.println("Hello ");
userService.doService();
}
优点
构造方法注入相比于前两种注入方法,它可以注入不可变对象,并且它只会执行一次,也不存在像 Setter 注入那样,被注入的对象随时被修改的情况,它的优点有以下 4 个:
缺点
构造函数可以有多个参数,当有多个参数时,不符合单一设计原则。
Spring 4.2 之前推荐的注入用法是 Setter,Spring 4.2 之后推荐使用构造方法注入
在进⾏类注⼊时,除了可以使⽤ @Autowired 关键字之外,我们还可以使⽤ @Resource 进⾏注⼊。
与@Autowired的区别
当出现以下多个 Bean,返回同⼀对象类型时程序会报错,如下:
@Component
public class Users {
@Bean
public User user1() {
User user = new User();
user.setName("fyd");
user.setAge(18);
return user;
}
@Bean
public User user2() {
User user = new User();
user.setName("fyd2");
user.setAge(19);
return user;
}
}
获取User对象,如下:
@Controller
public class UserController {
@Resource
private User user;
public User getUser() {
return user;
}
}
程序报错如下:
没有 "com.fyd.User "类型的符合条件的 Bean:预期只有一个匹配的 Bean,但发现了 2 个:user1,user2
这里我们有两个一样类型的Bean对象,所以我们直接注入程序分不清是要注入哪一个。
当谈论软件设计时,“单一设计原则”(Single Responsibility Principle,简称 SRP)是面向对象编程中的一个重要原则之一。它强调一个类应该只有一个引起它变化的原因,也就是说,一个类应该只负责一项职责。
这个原则的核心思想是,将一个类的功能限制在一个明确的范围内,使得该类的修改只会因为这个范围内的需求变化,而不会受到其他无关功能的影响。这有助于代码的可维护性、可读性和可扩展性,因为当一个类只关注一项职责时,它的代码更加清晰,容易理解和修改。
举个例子来解释单一设计原则:假设你正在开发一个图书馆管理系统,你可能会有一个 Book 类负责表示图书的信息,另一个 Library 类负责管理图书的借阅和归还。按照单一设计原则,Book 类只需要关注图书本身的属性和方法,而 Library 类只需要关注图书的管理,这样两个类的职责得到了明确的划分。
然而,当一个类承担了过多的职责时,代码可能变得混乱,难以维护。如果在上述例子中,你让 Book 类既负责图书信息又负责图书管理,那么当图书信息或图书管理的需求变化时,就可能需要同时修改 Book 类的多个部分,增加了代码变更的风险和复杂性。
单一设计原则的目标是使每个类都变得更加聚焦和专注,减少类之间的耦合,提高代码的可维护性和灵活性。通过将不同的职责分开,你可以更容易地修改、测试和扩展每个类,从而更好地满足软件的需求。
在这篇博客中,我们学习到了spring依赖注入的三种常见的方式,并且了解了它们的优缺点,还了解了依赖注入的两个重要的关键字:@Autowired、@Resource,并了解了两者的区别。还知道了如何解决同一类型Bean注入的报错问题和了解了软件设计中的单一设计原则。