您的位置:首页 > 编程语言 > Java开发

Spring-处理自动装配的歧义性

2017-08-08 16:29 447 查看
转载自http://www.cnblogs.com/yw0219/p/5990642.html

自动装配可以对依赖注入提供很大帮助,因为它会减少装配应用程序组件时所需的显式装配的数量。

不过,仅有一个bean匹配所需的结果时,自动装配才是有效的。如果不仅有一个bean能够匹配的话,这种歧义性会阻碍Spring自动装配属性,构造器参数或方法参数。但是,当确实发生歧义性时,Spring提供了多种可选方案来解决这样的问题。你可以将可选bean中的某一个设为首选(primary)的bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean。

javaConfig模式:

隐式

1 @Component
2 @Primary
3 public class VCDPlayer implements MediaPlayer{...}


显式

1 public class MagicBean {
2     @Bean//显式声明一个bean,id默认为方法名
3     @Primary
4     public MagicBean magicBean(){
5         return new MagicBean();
6     }
7 }


xml模式:

<bean id="cDPlayer" class="soundSystem.CDPlayer" primary="true"></bean>


然而,如果有两个继承相同接口的类同时设置primary,则仍然会有歧义,因此引入Qualifier。Qualifier注解是使用限定符的主要方式,它可以与@AutoWired和@Inject协同使用,在注入的时候指定想要注入进去的是哪个bean。例如我们想要确保要将IceCream注入到SetDessert()中:

1 @AutoWired
2 @Qualifier("iceCream")
3 public void setDessert(Dessert dessert){
4       this.dessert =dessert;
5 }


这里所设置的参数就是想要注入bean的ID。所有使用@Component注解声明的类都会创建为bean,并且bean的ID为首字母变为小写的类名,因此@Qualifier("iceCream")指向的是组件扫描时所创建的bean并且这个bean是IceCream类的实例。

但是,字符串类型的参数是不安全的,如果修改类名,这里也会受到影响,所以我们需要创建自定义的限定符,所需要做的仅仅是在IceCream类上面添加@Qualifier("cold"):

1 @Component
2 @Qualifier("cold")
3 public class IceCream implements Dessert{...}


或者在显式模式中:

1 @Bean
2 @Qualifier("cold")
3 public Dessert iceCream(){
4         return new IceCream();
5 }


相应的setter方法上也将参数设置为cold即可。

可是,如果有另外一个bean也同样使用了cold限定符呢,还是会出现歧义,而java不允许同一个条目上重复出现相同类型的多个注解,否则编译器会报错,所以我们需要创建自定义的限定符注解,借助这样的注解来表达bean所希望限定的特性。

1 package com.myapp;
2
3 import java.lang.annotation.ElementType;
4 import java.lang.annotation.Retention;
5 import java.lang.annotation.RetentionPolicy;
6 import java.lang.annotation.Target;
7
8 import org.springframework.beans.factory.annotation.Qualifier;
9
10 @Target({ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
11 @Retention(RetentionPolicy.RUNTIME)
12 @Qualifier
13 public @interface Cold {}


这样我们就创建好了一个叫Cold的注解,在其类上添加,即可作为它的一个限定符注解:

1 @Component
2 @Cold
3 public class IceCream implements Dessert{...}


这样就可以多次添加限定条件,以使得最终限定到符合条件的bean只有一个。与此同时,相对于使用原始的@Qualifier并借助String类型来指定限定符,自定义的注解也更为类型安全。

场景二

有如下接口:

public interface EmployeeService {
public EmployeeDto getEmployeeById(Long id);
}


同时有下述两个实现类 EmployeeServiceImpl和EmployeeServiceImpl1:

@Service("service")
public class EmployeeServiceImpl implements EmployeeService {
public EmployeeDto getEmployeeById(Long id) {
return new EmployeeDto();
}
}

@Service("service1")
public class EmployeeServiceImpl1 implements EmployeeService {
public EmployeeDto getEmployeeById(Long id) {
return new EmployeeDto();
}
}


调用代码如下:

@Controller
@RequestMapping("/emplayee.do")
public class EmployeeInfoControl {

@Autowired
EmployeeService employeeService;

@RequestMapping(params = "method=showEmplayeeInfo")
public void showEmplayeeInfo(HttpServletRequest request, HttpServletResponse response, EmployeeDto dto) {
#略
}
}


在启动tomcat时报如下错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'employeeInfoControl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.test.service.EmployeeService com.test.controller.EmployeeInfoControl.employeeService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.test.service.EmployeeService] is defined: expected single matching bean but found 2: [service1, service2]


其实报错信息已经说得很明确了,在autoware时,由于有两个类实现了EmployeeService接口,所以Spring不知道应该绑定哪个实现类,所以抛出了如上错误。

这个时候就要用到@Qualifier注解了,qualifier的意思是合格者,通过这个标示,表明了哪个实现类才是我们所需要的,我们修改调用代码,添加@Qualifier注解,需要注意的是@Qualifier的参数名称必须为我们之前定义@Service注解的名称之一!

@Controller
@RequestMapping("/emplayee.do")
public class EmployeeInfoControl {

@Autowired
@Qualifier("service")
EmployeeService employeeService;

@RequestMapping(params = "method=showEmplayeeInfo")
public void showEmplayeeInfo(HttpServletRequest request, HttpServletResponse response, EmployeeDto dto) {
#略
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: