【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 {
    @Bean
    public PaymentService paymentService() {
        return new PaymentService();
    }

    @Bean
    public OrderService orderService() {
        return new OrderService(paymentService());
    }
}

2. Setter 注入

通过 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...");
    }
}
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 {
    @Autowired
    private 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 {
    @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));
    }
}

5. 条件注入(@Qualifier 或 @Primary)

解决多个同类型 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();
    }
}

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;

    @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;
    }
}

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 {
    @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();
    }
}

总结

  • 构造器注入:推荐用于强制依赖,确保对象不可变。
  • Setter/字段注入:适合可选依赖或需要灵活性的场景。
  • 集合注入:处理多实现类的统一管理。
  • 条件注入:通过 @Qualifier@Primary@Profile 解决歧义。
  • 循环依赖:优先通过设计避免,或改用 Setter 注入。
  • 外部化配置:结合 @Value 动态注入属性值。
  • 条件化 Bean:根据环境或业务规则动态装配。

具体选择取决于项目需求,Spring Boot 进一步简化了配置(如自动配置、@ConditionalOnProperty)。

你可能感兴趣的:(Java,spring,java,后端)