在 XML 配置和直接注解式配置之外还有一种有趣的选择方式 -JavaConfig,java config 是指基于 java 配置的 spring。传统的 Spring 一般都是基本 xml 配置的,后来 spring3.0 新增了许多 java config 的注解,特别是 spring boot,基本都是清一色的 java config。下面用一段简单的程序来演示.
使用 IDEA 创建一个 Maven 项目
在 pom.xml 中引用依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
项目结构图
代码说明和实现
Dao 层和 Service 层不赘述了, 简单实现一个 add() 方法
完整代码已上传 github:GitHub
AppConfig 配置类
用 @Configuration 注解该类,等价 与 XML 中配置 beans;用 @Bean 标注方法等价于 XML 中配置 bean, 被注解的类内部包含有一个或多个被 @Bean 注解的方法 UserDaoNormal
@Configuration
public class AppConfig {
@Bean
public UserDao userDaoNormal(){
System.out.println(“ 创建 UserDaoNormal 对象 ”);
return new UserDaoNormal();
@Bean
public UserDao userDaoCache() {
System.out.println(“ 创建 UserDaoCache 对象 ”);
return new UserDaoCache();
}
@Bean
public UserService userServiceNormal(UserDao userDao){
System.out.println(“ 创建一个 UserService 对象 ”);
return new UserServiceNormal(userDao);
}
}
UserServiceTest 测试类 @RunWith(SpringJUnit4ClassRunner.class), 让测试运行于 Spring 测试环境 @ContextConfiguration Spring 整合 JUnit4 测试时,使用注解引入多个配置文件多个配置文件:@ContextConfiguration(locations = { “classpath:/spring1.xml”, “classpath:/spring2.xml”})
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void addTest(){
userService.add();
}
}
运行后却报异常出错!
问题是出现了依赖注入的歧义性,UserDao 不能够进行自动装配. 简单来说, 在 spring 容器中找到了一个以上的 UserDao 类型的对象, 所以不知道到底要哪个, 我在 UserDao 接口写了两个实现 add() 方法的类, 有一个 UserDaoNormal 对象和一个 UserDaoCache 对象, 所以无法正常进行依赖注入. 解决的办法有几个:
1.@primary 注解在 AppConfig 配置文件里根据需要在两个对象方法上在其中一个添加 @primary 注解, 说明这个对象是依赖注入的首选 bean.
2.@Qualifier 注解 Qualifier 的意思是合格者,通过这个标示,表明了哪个实现类才是我们所需要的,添加 @Qualifier 注解,需要注意的是 @Qualifier 的参数名称为我们之前定义 @Qualifier 注解的名称之一。代码如下
@Configuration
public class AppConfig {
@Bean
@Qualifier(“normal”)
public UserDao userDaoNormal(){
System.out.println(“ 创建 UserDaoNormal 对象 ”);
return new UserDaoNormal();
}
@Bean
@Qualifier(“cache”)
public UserDao userDaoCache() {
System.out.println(“ 创建 UserDaoCache 对象 ”);
return new UserDaoCache();
}
@Bean
public UserService userServiceNormal(@Qualifier(“normal”) UserDao userDao){
System.out.println(“ 创建一个 UserService 对象 ”);
return new UserServiceNormal(userDao);
}
}
3.@Qualifier 注解和 bean id 同样的,@Qualifier 的参数名称为我们之前定义 @bean 注解的名称之一。代码如下:
@Bean(“normal”)
public UserDao userDaoNormal(){
System.out.println(“ 创建 UserDaoNormal 对象 ”);
return new UserDaoNormal();
}
@Bean(“cache”)
public UserDao userDaoCache() {
System.out.println(“ 创建 UserDaoCache 对象 ”);
return new UserDaoCache();
}
@Bean
public UserService userServiceNormal(@Qualifier(“normal”) UserDao userDao){
System.out.println(“ 创建一个 UserService 对象 ”);
return new UserServiceNormal(userDao);
如果我们不给 bean 起一个约定的 id, 会有一个默认的 id, 实际上就是 @bean 所在的方法的方法名.@Qualifier 的参数名称为 @bean 所在的方法的方法名的名称之一。代码如下:
@Bean
public UserDao userDaoNormal(){
System.out.println(“ 创建 UserDaoNormal 对象 ”);
return new UserDaoNormal();
}
@Bean
public UserDao userDaoCache() {
System.out.println(“ 创建 UserDaoCache 对象 ”);
return new UserDaoCache();
}
@Bean
public UserService userServiceNormal(@Qualifier(“userDaoCache”) UserDao userDao){
System.out.println(“ 创建一个 UserService 对象 ”);
return new UserServiceNormal(userDao);
}
4. 运行后的两种结果