一、@Autowired注解
首先要知道,@Autowired注解可以对类成员变量、方法以及构造函数进行注释,省略通常XML方式注入时繁琐的步骤和大量的代码,完成组件的自动装配。
使用@Autowired注解时,需要了解一些东西:
@Autowired
private ColorService colorService;
①:默认优先按照类型去容器中查找对应的组件 — byType
Map<String, ColorService> array = ac.getBeansOfType(ColorService.class)
// map 的key为组件的name,value为组件的实例
②:若按照类型查找的组件只有一个的话,就么就将该组件装配给使用@Autowired注解的属性
③:若按照类型查找出来的组件有多个的话,那么将使用@Autowired注解的属性的名称作为组件的id去容器中查找 — byName
Object ob = ac.getBean("colorService");
④:若最后查询的结果为空的话,就会报异常。不过@Autowired有一个required属性,将之设置为false就可以忽略异常了,只是这样使用@Autowired注解注入的属性会是null。
下面进行一些测试:
首先定义一个ColorService接口:
public interface ColorService {
void color();
}
再定义一个实现类:WhiteColorServiceImpl
@Service
public class WhiteColorServiceImpl implements ColorService {
public void color() {
System.out.println("WhiteColorServiceImpl...I'm White ...");
}
}
之后定义一个ColorController类,在类中有一个ColorService类型的成员变量
@Controller
public class ColorController {
@Autowired
private ColorService colorService;
public void color(){
colorService.color();
}
}
定义一个配置类,使之扫描到上述的service和controller类:
@Configuration
@ComponentScan({"com.baiding.controller","com.baiding.service.impl"})
public class AutowiredConfig {
// 无代码 单纯配置文件
}
测试类:
@Test
void test09(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutowiredConfig.class);
Map<String, ColorService> array = ac.getBeansOfType(ColorService.class);
System.out.println(array);
ColorController ob2 = (ColorController) ac.getBean("colorController");
ob2.color();
}
结果:
{whiteColorServiceImpl=com.baiding.service.impl.WhiteColorServiceImpl@291caca8}
WhiteColorServiceImpl...I'm White ...
从结果看出来,以类型查找出来的组件只有一个,Spring直接将这个组件注入到了属性中。
接下来再定义一个BlackColorServiceImpl类,同时实现ColorService接口:
@Service
public class BlackColorServiceImpl implements ColorService {
public void color() {
System.out.println("I'm Black ...");
}
}
使用@Service注解,组件默认id为类名首字母小写:blackColorServiceImpl
之后,改一下WhiteColorServiceImpl实现类的组件名称:colorService
@Service("colorService")
public class WhiteColorServiceImpl implements ColorService {
public void color() {
System.out.println("WhiteColorServiceImpl...I'm White ...");
}
}
之后再进行测试的话结果是:
{blackColorServiceImpl=com.baiding.service.impl.BlackColorServiceImpl@4c39bec8, colorService=com.baiding.service.impl.WhiteColorServiceImpl@f79e}
WhiteColorServiceImpl...I'm White ...
可以看出,ColorService类型的组件有两个,按类型查找出多个组件的话,我们可以按照名称去找,即将colorService(Controller类声明的成员属性名)作为组件的id去容器中查找,上面结果可以看到有一个colorService名称的组件,它的实例是WhiteColorServiceImpl,那么Controller类输出的结果就可知了。
二、@Qualifier注解
在上述的操作流程中,我们提供了一个ColorService接口,它的两个实现类分别是BlackColorServiceImpl以及WhiteColorServiceImpl,其中WhiteColorServiceImpl在使用@Service注解时为了实现@Autowired的自动装配效果,我们给它赋予了一个id为colorService(@Service(“colorService”))。
我们可以实验一下,若我们不赋予这个组件id的话,当我们测试的时候,会发现服务器报错:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'colorController': Unsatisfied dependency expressed through field 'colorService'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.baiding.service.ColorService' available: expected single matching bean but found : blackColorServiceImpl,whiteColorServiceImpl
错误日志提示的很清楚,在容器注入的时候,由于发现了两个ColorService的实现类,系统无法判断注入哪个才是正确的,所以报错。
这种情况下,我们就可以使用@Qualifier注解了,通过这个注解,我们可以实现在组件注入的时候我们自己手动注入哪一个组件。当然,前提是我们得知道要注入的组件的id。
好了,最后修改一下采用@Autowired 注解注入组件的地方:
@Controller
public class ColorController {
@Qualifier("blackColorServiceImpl")
@Autowired
private ColorService colorService;
public void color(){
colorService.color();
}
}
测试类不变,结果是:
{blackColorServiceImpl=com.baiding.service.impl.BlackColorServiceImpl@4c39bec8, whiteColorServiceImpl=com.baiding.service.impl.WhiteColorServiceImpl@f79e}
BlackColorServiceImpl... I'm Black ...