依赖注入的本质是一种设计模式,最终目的还是为了实现松耦合(并非完全不需要类之间的耦合关系,而是降低耦合)
传统的耦合问题
class Car {
private Engine engine = new Engine(); // Car 类负责创建 Engine 实例
public void start() {
engine.start();
System.out.println("Car is running.");
}
}
class Engine {
public void start() {
System.out.println("Engine started.");
}
}
从上面的代码我们可以看到,如果Car
要调用Engine
的功能,就需要在内部创建一个Engine
的实例来对其进行调用,如果我们要更换Engine
的实现,就需要连带着Car
这里的代码也一起修改。
依赖注入的解决方案
class Car {
private Engine engine;
public Car(Engine engine) { // 通过构造器注入 Engine
this.engine = engine;
}
public void start() {
engine.start();
System.out.println("Car is running.");
}
}
interface Engine { // 定义 Engine 接口
void start();
}
class GasEngine implements Engine {
@Override
public void start() {
System.out.println("Gas Engine started.");
}
}
class ElectricEngine implements Engine {
@Override
public void start() {
System.out.println("Electric Engine started.");
}
}
Engine
对象的创建并不由Car
负责,同时Engine
对象可以有多种实现,至于具体传进去的则是由Car
之外的构造器来考虑。
同时,在Spring容器中,Car与Engine是这样配置的:
<bean id="gasEngine" class="GasEngine"/>
<bean id="electricEngine" class="ElectricEngine"/>
<bean id="car" class="Car">
<constructor-arg ref="gasEngine"/>
</bean>
也就是说如果我们要将油动改为电动,只需要更改ref
中引用的目标就好了.
在Spring中,依赖注入是通过注解的方式来实现的。
以下是四种与依赖注入有关的注解(generated by Google Gemini 2.0)
1. @Component
通用组件注解:
@Component
是一个通用的注解,用于标识一个类为 Spring 容器管理的组件(Bean)。它可以应用于任何类,表示这个类会被 Spring 容器自动扫描并注册为一个 Bean。基本功能: 相当于 XML 配置中的
<bean>
标签,负责将类实例化并放入 IoC 容器中管理其生命周期。示例:
@Component public class MyComponent { // ... }
2. @Service
服务层组件注解:
@Service
是@Component
的一个特化版本,用于标识服务层(Service Layer)的组件。语义化: 它在语义上更清晰地表明了该类扮演的角色是业务逻辑的处理者。
无额外功能(通常): 在 Spring 框架的核心功能上,
@Service
和@Component
并没有本质区别,它们都将类注册为 Bean。但在某些情况下,Spring 或第三方库可能会基于@Service
添加一些特定的功能,例如事务管理等。最佳实践: 建议使用
@Service
标识服务层组件,提高代码的可读性和可维护性。示例:
@Service public class MyService { // ... }
3. @Repository
持久层组件注解:
@Repository
也是@Component
的一个特化版本,用于标识数据访问层(Data Access Layer/Persistence Layer)的组件,例如 DAO(Data Access Object)。异常转换:
@Repository
最重要的作用是提供异常转换功能。当数据访问过程中发生异常时,@Repository
注解会将底层的特定异常(例如 JDBC 异常、JPA 异常)转换为 Spring 的DataAccessException
及其子类,从而提供一致的异常处理机制,并隐藏底层的技术细节。示例:
@Repository public class MyRepository { // ... }
4. @Autowired
依赖注入注解:
@Autowired
用于自动装配(注入)Bean。它可以用于构造器、Setter 方法、字段上。自动查找: Spring 容器会根据类型(Type)自动查找匹配的 Bean,并将其注入到目标对象中。如果存在多个匹配的 Bean,可以使用
@Qualifier
注解指定 Bean 的名称。简化配置:
@Autowired
大大简化了依赖注入的配置,减少了 XML 配置或 Java 配置的代码量。示例:
@Service public class MyService { @Autowired // 自动注入 MyRepository private MyRepository myRepository; // ... }
总结:
导出到 Google 表格
联系:
@Service
和 @Repository
本质上都是 @Component
的特例,它们都使用 @Component
的功能将类注册为 Bean。而 @Autowired
则用于将这些 Bean 注入到其他 Bean 中,实现依赖注入。
示例代码整合:
@Repository
public class MyRepository {
public void saveData() {
// ...
}
}
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
public void doSomething() {
myRepository.saveData();
}
}
@Component
public class MyComponent {
@Autowired
private MyService myService;
public void execute() {
myService.doSomething();
}
}
在这个例子中,MyRepository
、MyService
和 MyComponent
都被 Spring 容器管理,并且通过 @Autowired
实现了依赖注入。