依赖注入是 Spring 框架的核心机制之一,通过将对象的依赖关系外部化,实现松耦合设计。Spring 支持三种注入方式:
@Autowired
等注解直接注入到字段。本文将深入探讨以下 DI 高级特性:
Spring 解析依赖时遵循以下策略:
@Qualifier
注解明确指定 Bean。// 接口定义
public interface PaymentService {
void processPayment(double amount);
}
// 实现类1
@Service("alipayService")
public class AlipayServiceImpl implements PaymentService { ... }
// 实现类2
@Service("wechatPayService")
public class WechatPayServiceImpl implements PaymentService { ... }
// 依赖注入
@Service
public class OrderService {
// 方式1:通过 @Qualifier 指定
@Autowired
@Qualifier("alipayService")
private PaymentService paymentService;
// 方式2:通过字段名匹配
@Autowired
private PaymentService wechatPayService;
}
@Qualifier
用于在多个同类型 Bean 中明确指定要注入的 Bean:
@Service
public class ShoppingCartService {
@Autowired
@Qualifier("promotionPriceCalculator")
private PriceCalculator priceCalculator;
}
通过元注解 @Qualifier
创建自定义注解,简化依赖注入:
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Promotion {
// 自定义属性
String value() default "";
}
// 使用自定义注解
@Service
@Promotion
public class PromotionPriceCalculator implements PriceCalculator { ... }
// 注入时直接使用自定义注解
@Service
public class CheckoutService {
@Autowired
@Promotion
private PriceCalculator priceCalculator;
}
当依赖的 Bean 作用域与当前 Bean 不一致时,使用作用域代理解决依赖冲突。
// Request 作用域 Bean
@Service
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
private String userId;
// getter/setter
}
// Singleton Bean 注入 Request 作用域 Bean
@Service
public class OrderService {
@Autowired
private UserSession userSession; // 实际注入的是代理对象
public void createOrder() {
String userId = userSession.getUserId(); // 运行时动态代理到当前请求
}
}
ScopedProxyMode.TARGET_CLASS
:基于 CGLIB 的类代理。ScopedProxyMode.INTERFACES
:基于接口的 JDK 动态代理。通过 @Lazy
注解延迟 Bean 的初始化,直到首次使用时才创建。
// 方式1:类级别注解
@Service
@Lazy
public class ExpensiveService {
public ExpensiveService() {
System.out.println("ExpensiveService initialized");
}
}
// 方式2:注入点注解
@Service
public class ClientService {
@Autowired
@Lazy
private ExpensiveService expensiveService;
}
使用 @Conditional
及其派生注解,根据条件决定是否创建 Bean。
注解 | 作用 |
---|---|
@ConditionalOnBean |
当指定 Bean 存在时创建 |
@ConditionalOnMissingBean |
当指定 Bean 不存在时创建 |
@ConditionalOnProperty |
当配置属性满足条件时创建 |
@ConditionalOnClass |
当指定类存在于类路径时创建 |
@ConditionalOnMissingClass |
当指定类不存在于类路径时创建 |
public class OnProductionEnvironmentCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
return "production".equals(env.getProperty("spring.profiles.active"));
}
}
// 使用自定义条件
@Configuration
public class AppConfig {
@Bean
@Conditional(OnProductionEnvironmentCondition.class)
public DataSource productionDataSource() {
// 创建生产环境数据源
}
}
Spring 在依赖注入时会自动处理 AOP 代理,确保增强逻辑生效。
@Service
@Transactional
public class ProductService {
public void updateStock(String productId, int quantity) {
// 业务逻辑
}
}
// 注入时自动获取代理对象
@Service
public class OrderProcessingService {
@Autowired
private ProductService productService; // 实际注入的是事务代理对象
}
InitializingBean
:在属性设置后执行初始化逻辑。DisposableBean
:在 Bean 销毁前执行清理逻辑。@Service
public class DatabaseConnection {
// 自定义初始化方法
@PostConstruct
public void init() {
// 初始化连接
}
// 自定义销毁方法
@PreDestroy
public void cleanup() {
// 关闭连接
}
}
通过实现 BeanPostProcessor
接口,在 Bean 初始化前后进行自定义处理:
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 初始化前处理
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 初始化后处理(如创建代理)
return bean;
}
}
NullPointerException
,支持不可变对象。@Qualifier
或自定义注解。@Lazy
。@Lazy
打破循环。Spring 的依赖注入高级特性提供了强大而灵活的对象管理能力,通过限定符、作用域代理、条件注入等机制,开发者可以更精细地控制 Bean 的创建和依赖关系。理解这些特性有助于构建更高效、更具扩展性的 Spring 应用,同时避免常见的依赖注入陷阱。