@Autowired和@Resource都是用来自动装配bean的。
spring:
main:
allow-bean-definition-overriding: true
allow-bean-definition-overriding属性用于配置出现相同名称bean的情况如何处理:
下文会提到按类型装配,那么什么是同一类型呢?
@Autowired是Spring提供的注解,用于自动装配。
AutowiredAnnotationBeanPostProcessor类是Autowired注解的注解处理器。
关于注解处理器可参考文章:https://blog.csdn.net/JokerLJG/article/details/123548694
@Autowired的作用范围:成员变量、构造器、方法、参数、注解。
@Service
public class UserService {
@Autowired
private IUser user;
}
使用最多的方式。
@Service
public class UserService {
private IUser user;
@Autowired
public UserService(IUser user) {
this.user = user;
}
}
构造器上使用Autowired注解,实际上还是使用了成员变量装配的方式,并非构造器装配。
@Service
public class UserService {
@Autowired
public void test(IUser user) {
user.test();
}
}
Spring会在项目启动的过程中,自动调用一次加了@Autowired注解的方法,我们可以在该方法做一些初始化的工作。
在构造器的入参上加Autowired注解
@Service
public class UserService {
private IUser user;
public UserService(@Autowired IUser user) {
this.user = user;
System.out.println("user:" + user);
}
}
在非静态方法的入参上加Autowired注解
@Service
public class UserService {
public void test(@Autowired IUser user) {
user.test();
}
}
略。
当按类型装配时,如果该类型的bean不止一个时,会直接报错。举例说明:
接口:
public interface IUser {
void test();
}
实现类1:
@Service
public class User1 implements IUser{
@Override
public void test() {
}
}
实现类2:
@Service
public class User2 implements IUser{
@Override
public void test() {
}
}
自动装配:
@Service
public class UserService {
@Autowired
private IUser user;
}
启动时的错误信息:
Field userService in com.joker.controller.UserController required a single bean, but 2 were found:
- userServiceImpl1: defined in file [D:\work\my\springboot\target\classes\com\joker\controller\UserServiceImpl1.class]
- userServiceImpl2: defined in file [D:\work\my\springboot\target\classes\com\joker\controller\UserServiceImpl2.class]
@Primary注解可以解决上述问题(按类型装配时,如果该类型的bean不止一个时,会报错)。
当我们使用自动配置的方式装配Bean时,如果这个Bean有多个候选者,假如其中一个候选者具有@Primary注解修饰,该候选者会被选中,作为自动装配的bean。
在上面代码不变的情况下,只需在User1或User2上加@Primary注解,此时@Autowired自动装配会成功,并且自动装配的是加了@Primary注解的这个类对应的bean。
User1类加@Primary注解
@Service
@Primary
public class User1 implements IUser{
@Override
public void test() {
}
}
通过@Autowired和@Qualifier的结合使用可以按名称装配。
@Service
public class UserService {
@Autowired
@Qualifier("user1")
private IUser user;
}
自动装配名称为user1的bean(注意:bean的类型也必须要满足为IUser类型)。
我们一般使用的都是用@Autowired自动装配单个实例,但其实它也可以用来装配多个实例。可以通过List、Set、Map来装配多个实例,如下:
@Service
public class UserService {
@Autowired
private List<IUser> userList;
@Autowired
private Set<IUser> userSet;
@Autowired
private Map<String, IUser> userMap;
}
上面的装配方式会吧IUser类型的多个实例bean都装配的List、Set、Map中。
下面列举常见@Autowired装配未生效的情况:
@Autowired所在类未加@Controller、@Service、@Component、@Repository等注解,或者或者一些其它情况(如直接new对象的到实例)。这些情况会导致该类的bean并没有交给spring容器去管理,spring就无法完成自动装配的功能。
public class UserService {
@Autowired
private IUser user;
public void test() {
user.say();
}
}
注解未被@ComponentScan扫描到。
@Resource是JDK自带的注解,用于自动装配。
CommonAnnotationBeanPostProcessor类是Resource的注解处理器。
@Resource默认按照名称自动注入。
既没指定name,也没指定type,自动按照名称装配(当注解写在字段上时,默认取字段名,当注解写在setter方法上时,默认取属性名进行装配。);如果没有匹配,则退而按照类型装配,找不到则抛出异常。
如果没有指定 name 属性,
如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
Resource注解的主要属性:
@Resource的作用范围:类、成员变量、方法。
@Service
public class UserService {
@Resource
private IUser user;
}
@Service
public class UserService {
@Resource
public void test(IUser user) {
user.test();
}
}
略。
@Autowired | @Resource |
---|---|
Spring定义的注解 | JSR-250定义的注解 |
默认按类型自动装配 | 默认按名称自动装配 |
一个参数:required(默认true),表示是否必须注入 | 七个参数:最重要的两个参数是name、type |
默认按类型自动装配 如果要按名称自动装配,需要使用@Qualifier一起配合 |
默认按名称自动装配 如果指定了name,则按名称自动装配;如果指定了type,则按类型自动装配 |
作用范围:构造器、方法、参数、成员变量、注解 | 作用范围:类、成员变量、方法 |