依赖自动装配(Dependency Autowiring)是 Spring 框架中非常重要的一个特性,它可以在无需显式配置 Bean 之间关系的情况下自动将相互依赖的 Bean 注入到目标对象中,从而简化了配置文件的编写和维护工作。
1、根据属性名称自动装配(byName 自动装配)
原理是通过比较目标 Bean 中各个属性的名称和配置文件中 Bean 的 ID,如果匹配则将对应的 Bean 实例注入到目标属性中。例如:
public class User {
private Address address;
public void setAddress(Address address) {
this.address = address;
}
// ...
}
<bean id="address" class="com.example.Address"/>
<bean id="user" class="com.example.User" autowire="byName">
<property name="address" value="address"/>
</bean>
在上述示例中,<bean> 元素中的 autowire 属性设置为 byName,表示使用根据属性名称自动装配的方式进行依赖注入。同时,在 property 元素中,name 属性的值与 Bean 的 ID 相同,使得 Spring 可以从容器中查找对应的实例并将其注入到 User 类的 address 属性中。
需要注意的是,当 Bean 中存在多个属性与容器中的 Bean ID 匹配时,Spring 将会注入名称最匹配的 Bean。可以通过在 property 元素中设置 ref 属性来强制指定某个 Bean 实例。例如:
public class User {
private Address homeAddress;
private Address workAddress;
public void setHomeAddress(Address homeAddress) {
this.homeAddress = homeAddress;
}
public void setWorkAddress(Address workAddress) {
this.workAddress = workAddress;
}
// ...
}
<bean id="homeAddress" class="com.example.Address"/>
<bean id="workAddress" class="com.example.Address"/>
<bean id="user" class="com.example.User" autowire="byName">
<property name="homeAddress" ref="homeAddress"/>
<property name="workAddress" ref="workAddress"/>
</bean>
在上述示例中,通过在 property 元素中设置 ref 属性显式地指定目标 Bean 应当注入哪个 Bean 实例,避免了自动装配出现歧义的情况。
2、根据类型自动装配(byType 自动装配)
原理是通过比较目标 Bean 中各个属性的类型和配置文件中 Bean 的类型,如果匹配则将对应的 Bean 实例注入到目标属性中。例如:
public class BlogService {
private BlogDao blogDao;
public void setBlogDao(BlogDao blogDao) {
this.blogDao = blogDao;
}
// ...
}
如果在 Spring 的配置文件中只有一个类型为 BlogDao 的 Bean,那么 Spring 就会自动将该 Bean 注入到 BlogService 类的 blogDao 属性中。
<bean id="blogDao" class="com.example.BlogDao"/>
<bean id="blogService" class="com.example.BlogService" autowire="byType"/>
在上述示例中,<bean> 元素中的 autowire 属性设置为 byType,表示使用根据属性类型自动装配的方式进行依赖注入。
需要注意的是,当容器中存在多个类型相同的 Bean 时,Spring 将会抛出异常,因为无法确定应该将哪个 Bean 注入到目标属性中。在这种情况下,可以通过在属性上添加 @Qualifier 注解或者在 <bean> 元素中添加 qualifier 属性来指定具体的 Bean。例如:
public class BlogService {
@Autowired
@Qualifier("blogDao1")
private BlogDao blogDao;
// ...
}
<bean id="blogDao1" class="com.example.BlogDao"/>
<bean id="blogDao2" class="com.example.BlogDao"/>
<bean id="blogService" class="com.example.BlogService" autowire="byType">
<qualifier value="blogDao1"/>
</bean>
在上述示例中,@Qualifier 注解指定了具体的 Bean 名称,而在 <bean> 元素中的 qualifier 属性也可以达到同样的效果。
3、根据构造方法自动装配(byConstructor 自动装配)
原理是通过比较目标 Bean 在构造方法中的参数类型和配置文件中 Bean 的类型,如果匹配则将对应的 Bean 实例注入到构造方法中。
public class BlogService {
private BlogDao blogDao;
public BlogService(BlogDao blogDao) {
this.blogDao = blogDao;
}
// ...
}
如果在 Spring 的配置文件中只有一个类型为 BlogDao 的 Bean,那么 Spring 就会自动将该 Bean 注入到 BlogService 类的构造方法中。
<bean id="blogDao" class="com.example.BlogDao"/>
<bean id="blogService" class="com.example.BlogService" autowire="constructor"/>
在上述示例中,<bean> 元素中的 autowire 属性设置为 constructor,表示使用根据构造方法自动装配的方式进行依赖注入。
需要注意的是,当容器中存在多个类型相同的 Bean 时,Spring 将会抛出异常,因为无法确定应该将哪个 Bean 注入到构造方法中。在这种情况下,可以通过在构造方法中添加 @Qualifier 注解或者在 <bean> 元素中添加 qualifier 属性来指定具体的 Bean。例如:
public class BlogService {
private BlogDao blogDao;
private BlogCommentDao commentDao;
public BlogService(BlogDao blogDao, @Qualifier("commentDao1") BlogCommentDao commentDao) {
this.blogDao = blogDao;
this.commentDao = commentDao;
}
// ...
}
<bean id="blogDao" class="com.example.BlogDao"/>
<bean id="commentDao1" class="com.example.BlogCommentDao"/>
<bean id="commentDao2" class="com.example.BlogCommentDao"/>
<bean id="blogService" class="com.example.BlogService" autowire="constructor">
<constructor-arg ref="blogDao"/>
<constructor-arg name="commentDao" ref="commentDao1"/>
</bean>
在上述示例中,@Qualifier 注解指定了具体的 Bean 名称,而在 <bean> 元素中的 constructor-arg 元素的 name 属性也可以达到同样的效果。