构造器注入
构造器注入是通过类的构造器来传递依赖对象。当创建一个类的实例时,所有必需的依赖都通过构造器传递进来。
优点: 对象初始化完成后便可获得可使用的对象。
缺点: 当需要注入的对象很多时,构造器参数列表将会很长; 不够灵活。
@Component
public class CarService {
private Engine engine;
@Autowired
public CarService(Engine engine) {
this.engine = engine; // 依赖通过构造器注入
}
public void start() {
engine.start();
}
}
@Component
public class Engine {
public void start() {
System.out.println("Engine started.");
}
}
@Configuration
@ComponentScan(basePackages = "com.example") // 替换为实际包名
public class AppConfig {
}
public class Main {
public static void main(String[] args) {
// 创建并配置Spring应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取CarService bean
CarService carService = context.getBean(CarService.class);
// 使用CarService
carService.start();
// 关闭上下文
context.close();
}
}
设置器注入(setter方法注入)
设置器注入通过类的公开设置方法(setter)来注入依赖。这允许在对象创建之后的任何时候设置依赖。
优点: 灵活。可以选择性地注入需要的对象。
缺点: 依赖对象初始化完成后由于尚未注入被依赖对象,因此还不能使用。
@Component
public class CarService {
private Engine engine;
@Autowired
public void setEngine(Engine engine) {
this.engine = engine; // 依赖通过设置器方法注入
}
public void start() {
engine.start();
}
}
@Component
public class Engine {
public void start() {
System.out.println("Engine started.");
}
}
@Configuration
@ComponentScan(basePackages = "com.example") // 替换为实际包名
public class AppConfig {
}
public class Main {
public static void main(String[] args) {
// 创建并配置Spring应用上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 获取CarService bean
CarService carService = context.getBean(CarService.class);
// 使用CarService
carService.start();
// 关闭上下文
context.close();
}
}
在这个例子中,CarService 使用一个设置器方法 setEngine 来接收 Engine 的依赖。Spring容器负责调用这个方法,并传入一个 Engine 实例。
构造器注入: 依赖对象在Bean实例化阶段通过构造器传递。
Setter方法注入: 依赖对象在Bean实例化之后,通过调用Setter方法注入。
自动执行的过程
Spring上下文初始化:
- 当Spring应用启动时,Spring容器会扫描配置中指定的包,寻找使用了@Component、@Service、@Repository、@Controller等注解标记的类,并将这些类实例化为Bean。
依赖注入:
- Spring容器在实例化Bean时,会查找Bean中使用@Autowired注解的字段、构造方法或setter方法。
- 对于使用@Autowired注解的setter方法,Spring容器会调用该方法,并自动注入需要的依赖。
执行setter方法:
- 当Spring容器创建并初始化Bean时,如果发现setter方法上有@Autowired注解,就会自动调用这个方法并传入相应的依赖。
字段注入(Field Injection)
字段注入是通过在类的字段上直接使用注解(如@Autowired)来注入依赖。这是最简单直接的一种方式。
优点:
- 编码简便:不需要编写构造器或设置器,只需在字段上添加注解即可完成注入,简化了代码。
- 快速开发:特别适合快速开发和原型设计,可以快速搭建应用。
缺点:
- 难以测试:字段注入使得在没有Spring容器的环境中进行单元测试变得更加困难,因为没有简单的方法来设置这些依赖。
- 过度依赖框架:使得代码与Spring框架高度耦合,并且依赖关系不显式,降低了代码的可移植性和可读性。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserService {
@Autowired
private UserRepository userRepository; // 直接在字段上注入依赖
public void performAction() {
userRepository.action();
}
}
@Component
public class UserRepository {
public void action() {
System.out.println("Performing user repository action");
}
}