【Spring】Spring中8种常见依赖注入使用示例
在 Spring 中,IoC 注入可以通过多种方式实现,涵盖不同场景的依赖管理。以下是 8 种常见场景的详细示例及说明,结合 XML、注解和 Java 配置类三种方式。
1. 构造器注入(推荐方式)
通过构造器传递依赖,确保对象不可变且依赖完整。
注解方式:
@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...");}
}
XML 方式:
<bean id="paymentService" class="com.example.PaymentService"/><bean id="orderService" class="com.example.OrderService"><constructor-arg ref="paymentService"/>
</bean>
Java 配置类:
@Configuration
public class AppConfig {@Beanpublic PaymentService paymentService() {return new PaymentService();}@Beanpublic OrderService orderService() {return new OrderService(paymentService());}
}
2. Setter 注入
通过 Setter 方法注入依赖,适合可选依赖或需要动态变更的场景。
注解方式:
@Service
public class ProductService {private InventoryService inventoryService;@Autowiredpublic void setInventoryService(InventoryService inventoryService) {this.inventoryService = inventoryService;}
}@Component
public class InventoryService {public void checkStock() {System.out.println("Checking stock...");}
}
XML 方式:
<bean id="inventoryService" class="com.example.InventoryService"/><bean id="productService" class="com.example.ProductService"><property name="inventoryService" ref="inventoryService"/>
</bean>
3. 字段注入(不推荐,但常见)
直接通过字段注入依赖,简洁但隐藏依赖关系。
@Service
public class CartService {@Autowiredprivate DiscountService discountService;
}@Component
public class DiscountService {public void applyDiscount() {System.out.println("Applying discount...");}
}
4. 集合注入(多个同类型 Bean)
注入多个相同接口/父类的实现类。
示例代码:
public interface NotificationSender {void send(String message);
}@Component
public class EmailSender implements NotificationSender {@Overridepublic void send(String message) {System.out.println("Email: " + message);}
}@Component
public class SmsSender implements NotificationSender {@Overridepublic void send(String message) {System.out.println("SMS: " + message);}
}
注入方式:
@Service
public class NotificationService {private final List<NotificationSender> senders;@Autowiredpublic NotificationService(List<NotificationSender> senders) {this.senders = senders;}public void broadcast(String message) {senders.forEach(sender -> sender.send(message));}
}
5. 条件注入(@Qualifier 或 @Primary)
解决多个同类型 Bean 的歧义性问题。
使用 @Qualifier
:
public interface DataSource {void connect();
}@Component("mysqlDataSource")
public class MySqlDataSource implements DataSource {@Overridepublic void connect() {System.out.println("MySQL connected");}
}@Component("oracleDataSource")
public class OracleDataSource implements DataSource {@Overridepublic void connect() {System.out.println("Oracle connected");}
}@Service
public class ReportService {private final DataSource dataSource;@Autowiredpublic ReportService(@Qualifier("mysqlDataSource") DataSource dataSource) {this.dataSource = dataSource;}
}
使用 @Primary
:
@Configuration
public class AppConfig {@Bean@Primary // 默认优先选择public DataSource mysqlDataSource() {return new MySqlDataSource();}@Beanpublic DataSource oracleDataSource() {return new OracleDataSource();}
}
6. 外部化配置注入(@Value)
注入配置文件(如 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
}
7. 循环依赖处理
构造器注入无法解决循环依赖,需改用 Setter 注入。
示例代码:
@Service
public class ServiceA {private ServiceB serviceB;@Autowiredpublic void setServiceB(ServiceB serviceB) {this.serviceB = serviceB;}
}@Service
public class ServiceB {private ServiceA serviceA;@Autowiredpublic void setServiceA(ServiceA serviceA) {this.serviceA = serviceA;}
}
8. 条件化 Bean 注入(@Profile 或 @Conditional)
根据环境或条件动态选择 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 {@Overridepublic 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();}
}
总结
- 构造器注入:推荐用于强制依赖,确保对象不可变。
- Setter/字段注入:适合可选依赖或需要灵活性的场景。
- 集合注入:处理多实现类的统一管理。
- 条件注入:通过
@Qualifier
、@Primary
或@Profile
解决歧义。 - 循环依赖:优先通过设计避免,或改用 Setter 注入。
- 外部化配置:结合
@Value
动态注入属性值。 - 条件化 Bean:根据环境或业务规则动态装配。
具体选择取决于项目需求,Spring Boot 进一步简化了配置(如自动配置、@ConditionalOnProperty
)。