跳转到内容

Spring属性注入

来自代码酷


概述[编辑 | 编辑源代码]

Spring属性注入(Property Injection)是Spring IoC容器实现依赖注入(DI)的核心机制之一,指通过外部配置(XML/注解/JavaConfig)为Bean对象的成员变量动态赋值的过程。与构造器注入并列,是Spring解耦组件关系的两大主要方式。

属性注入的核心特点:

  • 通过setter方法或字段直接赋值
  • 支持简单类型(String/int等)和复杂对象(其他Bean)
  • 运行时由容器自动完成依赖装配
  • 符合"好莱坞原则"(不要调用我们,我们会调用你)

注入方式[编辑 | 编辑源代码]

1. XML配置注入[编辑 | 编辑源代码]

最传统的注入方式,通过<property>标签指定:

<!-- applicationContext.xml -->
<bean id="dataSource" class="com.example.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
    <property name="username" value="root"/>
    <property name="password" value="secret"/>
</bean>

等效的Java类定义:

public class BasicDataSource {
    private String driverClassName;
    private String url;
    private String username;
    private String password;
    
    // Setter方法必须存在
    public void setDriverClassName(String driver) {
        this.driverClassName = driver;
    }
    // 其他setter...
}

2. 注解注入[编辑 | 编辑源代码]

Spring 2.5+支持的现代方式:

@Component
public class OrderService {
    @Value("${order.max.retry}")  // 注入配置值
    private int maxRetry;
    
    @Autowired  // 按类型自动装配
    private PaymentGateway gateway;
    
    @Resource(name="emailService")  // 按名称装配
    private NotificationService notifier;
}

需配合注解扫描:

<context:component-scan base-package="com.example"/>
<context:property-placeholder location="classpath:app.properties"/>

3. JavaConfig注入[编辑 | 编辑源代码]

Spring 3.0+的纯Java配置方式:

@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/mydb");
        return ds;
    }
}

注入类型[编辑 | 编辑源代码]

pie title 属性注入类型占比 "简单值" : 35 "Bean引用" : 45 "集合类型" : 20

1. 简单值注入[编辑 | 编辑源代码]

支持所有基本类型及其包装类、String、Class等:

<property name="timeout" value="5000"/>  <!-- 自动转换为int -->
<property name="active" value="true"/>  <!-- boolean -->

2. Bean引用注入[编辑 | 编辑源代码]

注入容器中的其他Bean:

<bean id="userService" class="com.example.UserService">
    <property name="userDao" ref="jdbcUserDao"/>  <!-- ref指向其他bean -->
</bean>

3. 集合类型注入[编辑 | 编辑源代码]

复杂集合的配置示例:

<bean id="complexBean" class="com.example.CollectionBean">
    <property name="list">
        <list>
            <value>item1</value>
            <ref bean="specialService"/>
        </list>
    </property>
    <property name="map">
        <map>
            <entry key="config1" value="100"/>
            <entry key="service" value-ref="logService"/>
        </map>
    </property>
</bean>

高级特性[编辑 | 编辑源代码]

延迟注入[编辑 | 编辑源代码]

使用@Lazy注解延迟初始化:

@Component
public class HeavyResource {
    @Lazy
    @Autowired
    private ExpensiveToLoad externalService;
}

条件注入[编辑 | 编辑源代码]

Spring 4.0+的条件化装配:

@Bean
@Conditional(ProdEnvCondition.class)
public DataSource productionDataSource() {
    // 仅当条件满足时创建Bean
}

SpEL表达式[编辑 | 编辑源代码]

使用Spring表达式语言动态计算值:

<property name="defaultLocale" value="#{systemProperties['user.language']}"/>
<property name="randomNumber" value="#{T(java.lang.Math).random() * 100}"/>

最佳实践[编辑 | 编辑源代码]

1. 强制依赖推荐使用构造器注入,可选依赖使用属性注入 2. 避免混合使用多种注入方式(如同时使用XML和注解) 3. 对@Autowired添加@Qualifier消除歧义 4. 优先使用类型安全(type-safe)的JavaConfig方式

典型应用场景[编辑 | 编辑源代码]

电商系统库存服务示例

@Service
public class InventoryService {
    @Value("${inventory.threshold}")
    private int stockThreshold;
    
    @Autowired
    private WarehouseLocator locator;
    
    @Resource
    private List<InventoryValidator> validators;
    
    // 业务方法...
}
  • stockThreshold:从配置文件中注入
  • locator:自动装配主要仓库定位器
  • validators:收集所有实现InventoryValidator接口的Bean

常见问题[编辑 | 编辑源代码]

页面模块:Message box/ambox.css没有内容。

当BeanA依赖BeanB,同时BeanB又依赖BeanA时,解决方案:

  • 重构代码消除循环依赖
  • 使用@Lazy延迟初始化
  • 改用setter注入(而非构造器注入)

模板:Note 属性注入直接实例化由容器控制生命周期开发者手动管理易于配置修改需重新编译支持AOP等高级特性无容器服务

总结[编辑 | 编辑源代码]

Spring属性注入机制提供了灵活的依赖配置方式,通过本文介绍的多种实现形式和最佳实践,开发者可以构建松耦合、易测试的应用程序。随着Spring版本的演进,推荐逐步采用类型安全的JavaConfig结合注解的方式,以获得更好的开发体验和代码可维护性。