介绍
在Spring框架中,依赖注入(Dependency Injection, DI)是实现控制反转(Inversion of Control, IoC)的核心机制。
除了通过XML配置的注入方式(已逐渐被淘汰),Spring还支持多种基于注解和Java配置的注入方式。以下是常见的注入方式:
构造方法注入(Constructor Injection)
-
描述:通过构造方法将依赖注入到Bean中。
-
优点:
-
强制依赖,确保Bean在创建时就拥有所有必需的依赖。
-
适合不可变对象(属性可以声明为
final
)。 -
线程安全。
-
-
使用场景:推荐用于强依赖的场景。
-
示例:
java">@Component public class DemoService {private final DemoRepository repository;// 从Spring 4.3开始,如果只有一个构造方法,可以省略@Autowired@Autowired public DemoService(DemoRepository repository) {this.repository = repository;} }
Setter方法注入(Setter Injection)
-
描述:通过Setter方法将依赖注入到Bean中。
-
优点:
-
灵活性高,可以在对象创建后动态修改依赖。
-
适合可选依赖。
-
-
使用场景:适合依赖是可选的或需要动态修改的场景。
-
示例:
java">@Component
public class DemoService {private DemoRepository repository;@Autowiredpublic void setRepository(DemoRepository repository) {this.repository = repository;}
}
字段注入(Field Injection)
-
描述:直接在字段上使用
@Autowired
注解注入依赖。 -
优点:
-
代码简洁,无需编写构造方法或Setter方法。
-
-
缺点:
-
依赖关系不明确,难以测试(无法通过构造方法或Setter方法注入Mock对象)。
-
违反了单一职责原则,隐藏了类的依赖关系。
-
-
使用场景:适合简单的场景,但不推荐在生产代码中使用。
-
示例:
java">@Component
public class DemoService {@Autowiredprivate DemoRepository repository;
}
方法注入(Method Injection)
-
描述:通过任意方法注入依赖,方法可以是普通方法或Bean生命周期回调方法(如
@PostConstruct
)。 -
优点:
-
灵活性高,可以在方法中执行额外的逻辑。
-
-
使用场景:适合需要在注入时执行额外逻辑的场景。
-
示例:
java">@Component
public class DemoService {private DemoRepository repository;@Autowiredpublic void setupRepository(DemoRepository repository) {this.repository = repository;// 可以在这里执行其他逻辑}
}
接口注入(Interface Injection)
-
描述:通过实现特定接口来注入依赖。Spring本身并不直接支持这种方式,但可以通过自定义接口和AOP实现。
-
优点:
-
高度灵活,适合需要动态注入的场景。
-
-
缺点:
-
实现复杂,代码侵入性强。
-
-
使用场景:适合需要高度自定义注入逻辑的场景。
-
示例:
java">public interface RepositoryAware {void setRepository(DemoRepository repository);
}@Component
public class DemoService implements RepositoryAware {private DemoRepository repository;@Overridepublic void setRepository(DemoRepository repository) {this.repository = repository;}
}
注解注入(Annotation-based Injection)
-
描述:通过注解(如
@Autowired
、@Resource
、@Inject
)实现依赖注入。 -
优点:
-
代码简洁,易于使用。
-
支持多种注入方式(构造方法、Setter方法、字段等)。
-
-
使用场景:适合大多数基于注解的依赖注入场景。
-
示例:
java">@Component
public class DemoService {@Autowiredprivate DemoRepository repository;}
Java配置注入(Java Configuration Injection)
-
描述:通过
@Configuration
类和@Bean
方法显式配置依赖注入。 -
优点:
-
完全基于Java代码,无需XML配置。
-
适合需要复杂逻辑的依赖配置。
-
-
使用场景:适合需要显式控制Bean创建和依赖注入的场景。
-
示例:
java">@Configuration
public class DemoConfig {@Beanpublic DemoRepository demoRepository() {return new DemoRepository();}@Beanpublic DemoService demoService() {return new DemoService(demoRepository());}
}
Lookup方法注入(Lookup Method Injection)
-
描述:通过
@Lookup
注解或<lookup-method>
标签实现方法级别的依赖注入,通常用于注入原型(Prototype)Bean到单例(Singleton)Bean中。 -
优点:
-
解决单例Bean中注入原型Bean的问题。
-
-
使用场景:适合需要每次调用方法时返回不同实例的场景。
-
示例:
java">@Component
public abstract class DemoService {@Lookuppublic abstract DemoPrototypeBean getPrototypeBean();public void doSomething() {DemoPrototypeBean bean = getPrototypeBean();// 使用bean}}
总结
Spring提供了多种依赖注入方式,每种方式都有其适用场景和优缺点。以下是推荐的使用方式:
-
推荐:构造方法注入(强制依赖、线程安全、不可变性)。
-
可选:Setter方法注入(适合可选依赖或动态修改依赖)。
-
不推荐:字段注入(代码简洁但隐藏依赖关系,难以测试)。
-
特殊场景:方法注入、接口注入、Lookup方法注入等适合特定需求。