说到 @Resource 大家肯定会想到 @Autowired, 至于两者的区别:
@Autowired 是按 byType 自动注入
@Resource 默认按 byName 自动注入,而且还提供了 name 和 type 两个属性,其含义也容易理解,分别按 byName 和 byType 注入。
如果两个属性都没有提供的话,则根据属性名称注入,我理解的是 byName,还有地方说是通过反射机制使用 byName自动注入。
在实现类单一的情况下,@Resource @Autowire 没有区别, 都可以使用;
一旦一个接口多个实现类, 可能会出问题, 如果实例结果不唯一,那么@Autowired将会抛出异常
举例:
前提: MyTestService 有两个实现类, myTestServiceImpl1,myTestServiceImpl2
场景1: 使用@Autowire 使用byType(默认)
public class MyTest extends SpringTest {
@Autowired
private MyTestService myTestService;
@Test
void testAutowire() {
myTestService.print();
}
}
结论: 报错❌
分析:@Autowired 是按 byType 自动注入, byType 即按照MyTestService, 但代码中myTestServiceImpl1,myTestServiceImpl2 都实现自MyTestService ,类型都是MyTestService, 所以会找到两个myTestServiceImpl1,myTestServiceImpl2,无法注入;
场景2: @Autowire 使用byName
public class MyTest extends SpringTest {
@Autowired
private MyTestService myTestServiceImpl2;
@Test
void testAutowire() {
myTestServiceImpl2.print();
}
}
结论: 成功
分析: 默认按 byType 注入,发现多个时,会尝试按 byName 注入,即按找到 myTestServiceImpl2 进行注入, 找到了name 为 myTestServiceImpl2 的 Bean。成功执行。
场景三: @Autowire + @Qualifier("name")
public class MyTest extends SpringTest {
@Autowired
@Qualifier("myTestServiceImpl2")
private MyTestService myTestService;
@Test
void testAutowire() {
myTestService.print();
}
}
结论: 成功
分析: @Autowire + @Qualifier("name"), 会先按byType查找, 没有则按byName查找, 效果相当于@resource, 所以按byName查找, 找到了name 为 myTestServiceImpl2 的 Bean。成功执行。
场景4: @Resource 指定的是接口类的名称
public class MyTest extends SpringTest {
@Resource
private MyTestService myTestService;
@Test
void testAutowire() {
myTestService.print();
}
}
结论: 错误
分析: @Resource 按byName查找, 因为没有myTestService的 Bean, 所以找不到name 为 myTestService的 Bean。成功错误。
场景5: @Resource 指定 具体实现类的name
public class MyTest extends SpringTest {
@Resource
private MyTestService myTestServiceImpl1;
@Test
void testAutowire() {
myTestServiceImpl1.print();
}
}
结论:正常
分析: @Resource 按byName查找, 找到了name 为 myTestServiceImpl1 的 Bean。成功执行。
场景6: @Resource 没指定name属性,且默认属性名匹配不上,但只匹配上一个实现类
将MyTestServiceImpl2删除, 此时MyTestService 只有一个实现类MyTestServiceImpl1
还是使用场景4的测试代码: 指定的是接口类的名称, 或者 指定为name不存在的随意一个名字
public class MyTest extends SpringTest {
@Resource
private MyTestService myTestService; //或者随便起个名字如,myTestSSSS
@Test
void testAutowire() {
myTestService.print();
}
}
结论: 正常
分析: 当 @Resource 没有提供 name 和 type 属性的时候,如果 byName 没有找到对应的 Bean 时,则会根据依赖属性的类型去 Spring 容器中查找是否有提供了其他类型相同的 Bean,如果有则自动注入,如果没有则报错。当然如果根据 byName 找到了则直接注入。接下来,我们再来看看,name 和 type 的情况。
场景7: Resource 指定name属性,但属性名不匹配
同样将MyTestServiceImpl2删除, 此时MyTestService 只有一个实现类MyTestServiceImpl1
public class MyTest extends SpringTest {
@Resource(name="myTestServiceImpl2")
private MyTestService myTestService;
@Test
void testAutowire() {
myTestService.print();
}
}
结论: 报错
分析: @Resource(name="myTestServiceImpl2") 指定名称按照myTestServiceImpl2查找, 但是不存在myTestServiceImpl2(因为刚才删除了), 所以在使用 name 属性查找时,无法找到对应的 Bean,所以直接报错,没有再次去通过类型到 Spring 容器中查找
总结:
1、@Autowired
@Autowired默认byType自动注入,如果发现多个类型相同的Bean,再根据byName装配Bean,如果找到了则装配成功,找不到则装配失败。
@Autowired可与@Qualifier("beanName")搭配使用,注入指定bean。
@Autowired
@Qualifier("baseDao")
private BaseDao baseDao;
如,同一个接口,两个实现类,就可以使用该方式指定注入。
@Autowired(required=false)表示如果spring上下文中没有找到该类型的bean ,将会使用
new SoftPMServiceImpl();
private ISoftPMService softPMService = new SoftPMServiceImpl();
3、@Resource
@Resource默认按byName自动注入
但是@Resource有两个属性是比较重要的,分别是name和type;
如果使用name属性,则使用byName的自动注入策略; .
而使用type属性时则使用byType自动注入策略;
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
使用方式如下:
@Resource(name="dataSource");
@Resource(type="DataSource.class");
@Resource
private DataSource dataSource;
我一般习惯使用@Autowire + @Qulifier