Bean的装配可以理解为依赖关系注入,Bean的装配方式即Bean依赖注入的方式。Spring容器支持多种形式的Bean装配方式,如基于XML的装配、基于Annotation(注解)的装配和自动装配等。
Spring提供了两种基于XML的装配方式:设值注入(Setter Injection)和构造注入(Constructor Injection)。下面讲解如何在XML配置文件中使用这两种注入方式来实现基于XML的装配。在Spring实例化Bean的过程中,Spring首先会调用Bean的默认构造方法来实例化Bean对象,然后通过反射的方式调用setter()方法来注入属性值。因此,设值注入要求一个Bean必须满足以下两点要求:
使用设值注入时,在Spring配置文件中需要使用bean元素的子元素property来为每个属性注入值;
使用构造注入时,在配置文件中需要使用bean元素的子元素constructor-arg来定义构造方法的参数,可以使用其value属性(或子元素)来设置该参数的值。
【示例2-2】下面通过一个案例来演示基于XML方式的Bean的装配。
(1)在项目chapter02的src目录下创建一个com.ssm.assemble包,在该包中创建User类,并在类中定义userName、password和list集合3个属性及对应的setter()方法。
User.java
package com.ssm.assemble;
import java.util.List;
/**
* 功能描述
*
* @author: 衍生星球
* @date: 2023年04月14日 8:24
*/
public class User {
private String userName;
private String password;
private List<String> list;
/**
* 1.使用构造注入
* 1.1提供带所有参数的构造方法
*/
public User(String userName,String password,List<String> list) {
super();
this.userName = userName;
this.password = password1;
this.list = list;
}
@Override
public String toString () {
return "User[userName = " +userName+ ", password1 = "+password1+", list = "+list+"]";
}
/**
* 2.使用设值注入
* 2.1提供默认空参构造方法
* 2.2为所有属性提供setter()方法
*/
public User() {
super();
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setPassword(String password) {
this.password = password;
}
public void setList(List<String> list) {
this.list = list;
}
}
由于要使用构造注入,因此需要编写有参和无参的构造方法。
(2)在Spring的配置文件application.xml中,增加通过构造注入和设值注入的方法装配User实例的两个Bean。
<bean id="user1" class="com.ssm.assemble.User">
<constructor-arg index="0" value="zhangsan" />
<constructor-arg index="1" value="111111" />
<constructor-arg index="2">
<list>
<value>"constructorValue1"</value>
<value>"constructorValue2"</value>
</list>
</constructor-arg>
</bean>
<bean id="user2" class="com.ssm.assemble.User">
<property name="userName" value="lisi"></property>
<property name="password" value="222222"></property>
<property name="list">
<list>
<value>listValue1</value>
<value>listValue2</value>
</list>
</property>
</bean>
在上述代码中,constructor-arg元素用于定义构造方法的参数,其属性index表示其索引(从0开始),value属性用于设置注入的值,其子元素list为User类中对应的list集合属性注入值。
然后又使用设值注入方法装配User类的实例,其中property元素用于调用Bean实例中的setter()方法完成属性赋值,从而完成依赖注入,而其子元素list同样为User类中对应的list集合属性注入值。
(3)在com.ssm.assemble包中创建测试类XmlAssembleTest,在类中分别获取并输出配置文件中的user1和user2实例。
XmlAssembleTest.java
package com.ssm.assemble;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author: 衍生星球
* @date: 2023年04月14日 9:08
*/
public class XmlAssembleTest {
public static void main(String[] args) {
//1.初始化Spring容器,加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.输出获得的实例
System.out.println(applicationContext.getBean("user1"));
System.out.println(applicationContext.getBean("user2"));
}
}
执行程序后,控制台输出结果如下。可以看出,已经成功地使用基于XML装配的构造注入和设值注入两种方式装配了User实例。
在Spring中,尽管使用XML配置文件可以实现Bean的装配工作,但如果应用中有很多Bean,就会导致XML配置文件过于臃肿,给以后的维护和升级工作带来一定的困难。为此,Spring提供了对Annotation(注解)技术的全面支持。Spring中定义了一系列的注解,常用的注解如表所示。
注意:虽然@Repository、@Service和@Controller的功能与@Component注解的功能相同,但为了使标注类本身用途更加清晰,建议在实际开发中使用@Repository、@Service和@Controller分别对实现类进行标注。
【示例2-3】接下来,通过一个案例来演示如何通过这些注解来装配Bean。
(1)在chapter02项目的src目录下创建一个com.ssm.annotation包,在该包中创建接口UserDao,并在接口中定义一个save()方法。
UserDao.java
package com.ssm.annotation;
public interface UserDao {
public void save();
}
(2)在com.ssm.annotation包中创建UserDao接口的实现类UserDaoImpl,该类需要实现接口中的save()方法。
UserDaoImpl.java
package com.ssm.annotation;
import org.springframework.stereotype.Repository;
/**
* 功能描述
*
* @author: 衍生星球
* @date: 2023年04月14日 9:43
*/
//使用 @Repository 注解将 UserDaoImpl 类标识为 Spring 中的 Bean
@Repository("userDao")
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("userDao,save");
}
}
首先使用@Repository注解将UserDaoImpl类标识为Spring中的Bean,其写法相当于配置文件中
(4)在com.ssm.annotation包中创建UserService接口的实现类UserServiceImpl,该类需要实现接口中的save()方法。
UserServiceImpl.java
package com.ssm.annotation;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 功能描述
*
* @author: 衍生星球
* @date: 2023年04月14日 14:26
*/
//使用 @ 注解将 UserServiceImpl 类标识为 Spring 中的 Bean
@Service("userService")
public class UserServiceImpl implements UserService {
//使用 @Resource 注解注入
@Resource(name="userDao")
private UserDao userDao;
public void save() {
this.userDao.save();
System.out.println("执行userService.save()");
}
}
首先使用@Service注解将UserServiceImpl类标识为Spring中的Bean,这相当于配置文件中
的编写;
然后使用@Resource注解标注在属性userDao上,这相当于配置文件中
的写法;最后在该类的save()方法中调用userData中的save()方法,并输出一句话。
(5)在com.ssm.annotation包中创建控制器类UserController。
UserController.java
package com.ssm.annotation;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;
/**
* 功能描述
*
* @author: 衍生星球
* @date: 2023年04月14日 16:21
*/
//使用 @Controller 注解将 UserController 类标识为 Spring 中的 Bean
@Controller("UserController")
public class UserController {
//使用 @Resource 注解注入
@Resource(name = "UserService")
private UserService userService;
public void save() {
this.userService.save();
System.out.println("运行userService.save()");
}
}
首先使用@Controller注解标注了UserController类,这相当于在配置文件中编写
;
然后使用@Resource注解标注在userService属性上,这相当于在配置文件中编写
;最后在其save()方法中调用了userService中的save()方法,并输出一句话。
(6)创建配置文件beans1.xml,在配置文件中编写基于Annotation装配的代码。
beans1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 使用context命名空间在配置文件中 开启相应的注解处理器 -->
<context:annotation-config/>
<!-- 分别定义3个 bean 实例 -->
<bean id="UserDao" class="com.ssm.annotation.UserDaoImpl" />
<bean id="UserService" class="com.ssm.annotation.UserServiceImpl" />
<bean id="UserController" class="com.ssm.annotation.UserController" />
</beans>
在
元素中增加了包含context的约束信息;然后通过配置
来开启注解处理器;最后分别定义了3个Bean对应的3个实例。与XML配置方式有所不同的是,这里不再需要配置子元素
。上述Spring配置文件中的注解方式虽然较大程度地简化了XML文件中Bean的配置,但仍需在Spring配置文件中一一配置相应的Bean,为此Spring注解提供了另一种高效的注解配置方式(对包路径下的所有Bean文件进行扫描),其配置方式如下:
<context:component-scan base-package="Bean所在的包路径" />
代码进行如下替换:
<!-- 使用context命名空间通知 Spring 扫描指定包下所有的 Bean类,进行注解解析 -->
<context:component-scan base-package="com.ssm.annotation" />
(7)在com.ssm.annotation包中创建测试类AnnotationAssembleTest,在类中编写测试方法并定义配置文件的路径,然后通过Spring容器加载配置文件并获取UserController实例,最后调用实例中的save()方法。
AnnotationAssembleTest.java
package com.ssm.annotation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 功能描述
*
* @author: 衍生星球
* @date: 2023年04月14日 16:47
*/
public class AnnotationAssembleTest {
private static ApplicationContext applicationContext;
public static void main(String[] args) {
//1.定义配置文件路径
String xmlPath = "beans1.xml";
applicationContext = new ClassPathXmlApplicationContext("xmlPath");
//2.获取 UserController 实例
UserController userController = (UserController) applicationContext.getBean("UserController");
//3.调用 UserController中的save()方法
userController.save();
}
}
执行程序后,控制台的输出结果如图所示。从中可以看到,Spring容器已成功获取了UserController的实例,并通过调用实例中的方法执行了各层中的输出语句,这说明已成功实现了基于Annotation来装配Bean实例。
注意:上述案例中使用@Autowired注解替换@Resource注解也可以达到同样的效果。
虽然使用注解的方式装配Bean在一定程度上减少了配置文件中的代码量,但是也有企业项目中是没有使用注解方式开发的,那么有没有什么办法既可以减少代码量,又能够实现Bean的装配呢?
Spring的
元素中包含一个autowire属性,我们可以通过设置autowire的属性值来自动装配Bean。所谓自动装配,就是将一个Bean自动注入其他Bean的Property中。autowire属性有5个值,其值及说明如表所示。
【示例2-4】下面通过修改2.3.2节中的案例来演示如何使用自动装配。
(1)修改UserServiceImpl.java和UserController.java,分别在这两个文件中增加类属性的setter()方法。
(2)修改beans1.xml,将其修改成自动装配形式。
<!-- 使用bean元素的autowire属性完成自动装配 -->
<bean id="UserDao" class="com.ssm.annotation.UserDaoImpl" />
<bean id="UserService" class="com.ssm.annotation.UserServiceImpl" autowire="byName" />
<bean id="UserController" class="com.ssm.annotation.UserController" autowire="byName" />
在上述配置文件中,用于配置userService和userController的
元素中除了id和class属性外,还增加了autowire属性,并将其属性值设置为byName。在默认情况下,配置文件中需要通过ref来装配Bean,但设置了autowire="byName"
后,Spring会自动寻找userServiceBean中的属性,并将其属性名称与配置文件中定义的Bean做匹配。由于UserServiceImpl中定义了userDao属性及其setter()方法,这与配置文件中id为userDao的Bean相匹配,因此Spring会自动地将id为userDao的Bean装配到id为userService的Bean中。执行程序后,控制台的输出结果如图所示。