在 Spring 中,IoC 注入可以通过多种方式实现,涵盖不同场景的依赖管理。以下是 8 种常见场景的详细示例及说明,结合 XML、注解和 Java 配置类三种方式。
通过构造器传递依赖,确保对象不可变且依赖完整。
@Service
public class OrderService {
private final PaymentService paymentService;
@Autowired // Spring 4.3+ 可省略(单构造器时)
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
@Component
public class PaymentService {
public void process() {
System.out.println("Processing payment...");
}
}
<bean id="paymentService" class="com.example.PaymentService"/>
<bean id="orderService" class="com.example.OrderService">
<constructor-arg ref="paymentService"/>
bean>
@Configuration
public class AppConfig {
@Bean
public PaymentService paymentService() {
return new PaymentService();
}
@Bean
public OrderService orderService() {
return new OrderService(paymentService());
}
}
通过 Setter 方法注入依赖,适合可选依赖或需要动态变更的场景。
@Service
public class ProductService {
private InventoryService inventoryService;
@Autowired
public void setInventoryService(InventoryService inventoryService) {
this.inventoryService = inventoryService;
}
}
@Component
public class InventoryService {
public void checkStock() {
System.out.println("Checking stock...");
}
}
<bean id="inventoryService" class="com.example.InventoryService"/>
<bean id="productService" class="com.example.ProductService">
<property name="inventoryService" ref="inventoryService"/>
bean>
直接通过字段注入依赖,简洁但隐藏依赖关系。
@Service
public class CartService {
@Autowired
private DiscountService discountService;
}
@Component
public class DiscountService {
public void applyDiscount() {
System.out.println("Applying discount...");
}
}
注入多个相同接口/父类的实现类。
public interface NotificationSender {
void send(String message);
}
@Component
public class EmailSender implements NotificationSender {
@Override
public void send(String message) {
System.out.println("Email: " + message);
}
}
@Component
public class SmsSender implements NotificationSender {
@Override
public void send(String message) {
System.out.println("SMS: " + message);
}
}
@Service
public class NotificationService {
private final List<NotificationSender> senders;
@Autowired
public NotificationService(List<NotificationSender> senders) {
this.senders = senders;
}
public void broadcast(String message) {
senders.forEach(sender -> sender.send(message));
}
}
解决多个同类型 Bean 的歧义性问题。
@Qualifier
:public interface DataSource {
void connect();
}
@Component("mysqlDataSource")
public class MySqlDataSource implements DataSource {
@Override
public void connect() {
System.out.println("MySQL connected");
}
}
@Component("oracleDataSource")
public class OracleDataSource implements DataSource {
@Override
public void connect() {
System.out.println("Oracle connected");
}
}
@Service
public class ReportService {
private final DataSource dataSource;
@Autowired
public ReportService(@Qualifier("mysqlDataSource") DataSource dataSource) {
this.dataSource = dataSource;
}
}
@Primary
:@Configuration
public class AppConfig {
@Bean
@Primary // 默认优先选择
public DataSource mysqlDataSource() {
return new MySqlDataSource();
}
@Bean
public DataSource oracleDataSource() {
return new OracleDataSource();
}
}
注入配置文件(如 application.properties
)中的值。
app.name=MySpringApp
app.max.connections=10
@Component
public class AppConfigBean {
@Value("${app.name}")
private String appName;
@Value("${app.max.connections}")
private int maxConnections;
// Getter/Setter
}
构造器注入无法解决循环依赖,需改用 Setter 注入。
@Service
public class ServiceA {
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Service
public class ServiceB {
private ServiceA serviceA;
@Autowired
public void setServiceA(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
根据环境或条件动态选择 Bean。
@Profile
:@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
return new H2DataSource();
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
return new MySqlDataSource();
}
}
@Conditional
:public class MongoDBCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return "true".equals(context.getEnvironment().getProperty("enable.mongo"));
}
}
@Configuration
public class DatabaseConfig {
@Bean
@Conditional(MongoDBCondition.class)
public DataSource mongoDataSource() {
return new MongoDataSource();
}
}
@Qualifier
、@Primary
或 @Profile
解决歧义。@Value
动态注入属性值。具体选择取决于项目需求,Spring Boot 进一步简化了配置(如自动配置、@ConditionalOnProperty
)。