在 Java 中,对象注入(依赖注入,Dependency Injection)是实现松耦合设计的重要方式,常见的有以下几种实现形式:
1. 构造器注入(Constructor Injection)
通过类的构造函数注入依赖对象。
特点:
-
依赖关系在对象创建时确定,不可变(
final修饰)。 -
强制要求依赖项非空,避免
NullPointerException。 -
适合必须依赖的场景。
示例:
public class UserService {private final UserRepository userRepository;// 通过构造器注入public UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}
Spring 中的使用:
-
XML 配置:
<constructor-arg> -
注解:
@Autowired(可省略,Spring 4.3+ 支持隐式构造器注入)
2. Setter 方法注入(Setter Injection)
通过 setter 方法注入依赖对象。
特点:
-
依赖关系可在对象创建后修改。
-
灵活性高,适合可选依赖。
-
需处理依赖可能为
null的情况。
示例:
public class UserService {private UserRepository userRepository;// 通过 setter 方法注入@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}
}
Spring 中的使用:
-
XML 配置:
<property> -
注解:
@Autowired标注在setter方法上。
3. 字段注入(Field Injection)
通过直接注入字段(无需构造器或 setter)。
特点:
-
代码简洁,但隐藏了依赖关系。
-
无法声明
final字段,依赖可能为null。 -
测试时需要依赖框架(如 Spring)或反射工具。
示例:
public class UserService {@Autowiredprivate UserRepository userRepository;
}
注意:字段注入虽然方便,但不符合面向对象设计原则(如封装性)。
4. 总结对比
| 注入方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 构造器注入 | 依赖不可变、强制非空、线程安全 | 参数较多时代码冗余 | 强依赖、核心组件 |
| Setter注入 | 灵活性高、支持可选依赖 | 依赖可能为 null、线程不安全 | 可选依赖、配置类 |
| 字段注入 | 代码简洁 | 破坏封装性、难以测试 | 快速开发、非核心逻辑 |