方法一:标示首选的bean
接口1:
package com.spring.ambiguity;
/**
* 一个光盘接口
*/
public interface CompactDisc {
void sing();//光盘的sing功能
}
接口1的第一个实现
package com.spring.ambiguity;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
/**
* CompactDisc实现类
*/
@Component
//@Primary
public class SgtPeppers implements CompactDisc {
public void sing() {
System.out.println("sgtPeppers的sing方法");
}
}
接口1的第二个实现:加入了@Primary,标记成首选bean
package com.spring.ambiguity;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
/**
* CompactDisc实现类
*/
@Component
@Primary
public class OtherSgtPeppers implements CompactDisc {
public void sing() {
System.out.println("OtherSgtPeppers的sing方法");
}
}
接口1 的第三个实现
package com.spring.ambiguity;
import org.springframework.stereotype.Component;
/**
* CompactDisc实现类
*/
@Component
public class AnotherSgtPeppers implements CompactDisc {
public void sing() {
System.out.println("AnotherSgtPeppers的sing方法");
}
}
接口2
package com.spring.ambiguity;
/**
* 媒体播放器
*/
public interface MediaPlayer {
void play(); //一个播放方法
}
接口2的实现
package com.spring.ambiguity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;
@Autowired
public CDPlayer(CompactDisc compactDisc){
this.compactDisc = compactDisc;
}
public void play() {
System.out.println("CDPlayer");
compactDisc.sing();
}
}
测试
package com.spring.ambiguity;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AmbiguityConfig.class)
public class AmbiguityConfigTest {
@Autowired
private CompactDisc compactDisc;
@Autowired
private MediaPlayer mediaPlayer;
@Test
public void testProfiles(){
mediaPlayer.play();
}
}
测试结果:注入的是标志为首选Bean的OtherSgtPeppers
WARNING: All illegal access operations will be denied in a future release
CDPlayer
OtherSgtPeppers的sing方法
也可以通过xml来标志首选bean【不推荐,自动装配还是用注解吧,这样有点乱】
<?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 http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.spring.ambiguity.xmlAmbiguity"/>
<bean id="sgtPeppers" class="com.spring.ambiguity.xmlAmbiguity.SgtPeppers"/>
<bean id="otherSgtPeppers" class="com.spring.ambiguity.xmlAmbiguity.OtherSgtPeppers" primary="true"/>
<bean id="anotherSgtPeppers" class="com.spring.ambiguity.xmlAmbiguity.AnotherSgtPeppers"/>
</beans>
方式二:限定自动装配的bean
接下来的自动装配只考虑一种情况,所有bean都用@Component标示,配置类中启动组件扫描
直接通过@Qualifier("bean id") 与@Autowired 组合使用,找到对应的bean id进行注入
package com.spring.ambiguity.quaifier;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = QuaifierConfig.class)
public class QuaifierConfigTest {
@Autowired
@Qualifier("anotherSgtPeppers")
private CompactDisc compactDisc;
@Autowired
private MediaPlayer mediaPlayer;
@Test
public void testProfiles(){
compactDisc.sing();
}
}
方式三:自定义限定符
通过@Component 与 @Qualifier连用,为bean 创建自定义限定符名称
@Component
@Qualifier("oks")
public class AnotherSgtPeppers implements CompactDisc {
public void sing() {
System.out.println("AnotherSgtPeppers的sing方法");
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = QuaifierConfig.class)
public class QuaifierConfigTest {
@Autowired
// @Qualifier("anotherSgtPeppers")
@Qualifier("oks")
private CompactDisc compactDisc;
@Autowired
private MediaPlayer mediaPlayer;
@Test
public void testProfiles(){
compactDisc.sing();
}
}
方式四:自定义一个注解
有点,当需要为一个bean定义多个限定符时,又不能使用多个@Qulifier(同名注解只能存在一个),所以自定义一个注解并使其拥有@Qulifier功能,完美解决这个问题
自定义方式如下
package com.spring.ambiguity.quaifier;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Okss {
}
使用这个注解
/**
* CompactDisc实现类
*/
@Component
//@Qualifier("oks")
@Okss
public class AnotherSgtPeppers implements CompactDisc {
public void sing() {
System.out.println("AnotherSgtPeppers的sing方法");
}
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = QuaifierConfig.class)
public class QuaifierConfigTest {
@Autowired
// @Qualifier("anotherSgtPeppers")
@Okss
private CompactDisc compactDisc;
@Autowired
private MediaPlayer mediaPlayer;
@Test
public void testProfiles(){
compactDisc.sing();
}
}
补充:bean中的自动装配bean
package com.spring.ambiguity.quaifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;
@Autowired
public CDPlayer(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
public void play() {
System.out.println("CDPlayer");
compactDisc.sing();
}
}
CDPlayer中自动装配CompactDisc再这里是存在歧义。怎么解决,第一个想到的就是@Qualifier方法来指定bean,但是!显示@Qualifier不能用在构造器方法上。
所以,这个方法不行,那么,通过setter方法注入呢
先添加了一个setter方法,并使用@Qualifier标注注入bean id为anotherSgtPeppers的bean,同时注释了构造方法上的@Autowired
package com.spring.ambiguity.quaifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;
@Autowired
@Qualifier("anotherSgtPeppers")
public void setCompactDisc(CompactDisc compactDisc) {
System.out.println("进入了setter方法");
this.compactDisc = compactDisc;
}
// @Autowired
public CDPlayer(CompactDisc compactDisc) {
this.compactDisc = compactDisc;
}
public void play() {
System.out.println("CDPlayer");
compactDisc.sing();
}
}
测试下,结果报错,错误的原因是错误的创建CDPlayer bean,NoUniqueBeanDefinitionException: No qualifying bean of
type 'com.spring.ambiguity.quaifier.CompactDisc':没有限定CompactDisc。
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating
bean with name 'CDPlayer' defined in file [D:\更改的路径\Desktop\临时
\14\SpringAction\target\classes\com\spring\ambiguity\quaifier\CDPlayer.class]: Unsatisfied
dependency expressed through constructor parameter 0; nested exception is
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of
type 'com.spring.ambiguity.quaifier.CompactDisc' available: expected single matching bean
but found 3: anotherSgtPeppers,otherSgtPeppers,sgtPeppers
接下来试着把构造器给注释掉,然后添加一个无参的构造器
package com.spring.ambiguity.quaifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;
@Autowired
@Qualifier("anotherSgtPeppers")
public void setCompactDisc(CompactDisc compactDisc) {
System.out.println("进入了setter方法");
this.compactDisc = compactDisc;
}
public CDPlayer() {
System.out.println("进入了构造器");
}
// @Autowired
// public CDPlayer(CompactDisc compactDisc) {
// this.compactDisc = compactDisc;
// }
public void play() {
System.out.println("CDPlayer");
compactDisc.sing();
}
}
测试结果,结果发现,就算没有@Autowire,也会进入构造器【创建bean实例当然需要构造器。。。】
这下就解释了,一开始的有参构造器,因为CompactDIsc有3个bean可以注入,所以测试结果会出错
进入了构造器
进入了setter方法
CDPlayer
AnotherSgtPeppers的sing方法
所以,第一种办法就是,不要提供有参构造器,然后再setter里面通过@Autowrie和@Qualifier来限定bean
那么,就想用构造器怎么办,试试看自定义注释
package com.spring.ambiguity.quaifier;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc compactDisc;
// @Autowired
// @Qualifier("anotherSgtPeppers")
// public void setCompactDisc(CompactDisc compactDisc) {
// System.out.println("进入了setter方法");
// this.compactDisc = compactDisc;
// }
// public CDPlayer() {
// System.out.println("进入了构造器");
// }
@Okss
public CDPlayer(CompactDisc compactDisc) {
System.out.println("进入了有参构造器");
this.compactDisc = compactDisc;
}
public void play() {
System.out.println("CDPlayer");
compactDisc.sing();
}
}
测试:结果可行!
进入了有参构造器
CDPlayer
AnotherSgtPeppers的sing方法
得出的结论就是
(1)任何bean的产生,都需要一个构造参数
(2)一个bean作为另一个bean的参数,即使不用@Autowire,也会自动注入
(3)如果想要再方法里注入bean,那么就必须要@Autowire了