三 Spring 注解 第3.2 之 @Autowire 和 @Resource
三 Spring 注解
第3.2 之 @Autowire 和 @Resource
@Autowired 或 @Resource 可修饰变量\方法\构造函数,用于完成自动装配(将需要的外部资源注入)
@Autowired Class_A a : 默认按照类型byType
Qualifier和Autowired配合使用,可以指定bean的byname
只包含一个:required,默认true开启自动准入,依赖对象必须存在,若要允许null值,改为flase
用在 构造器、方法、参数、成员变量和注解上
spring定义的注解
AutoWiredAnnotationBeanPostProcessor是处理@AutoWired注解的
@Resource Class_A a: 默认用来指定名称byname注入
包含七个参数,其中最重要的两个参数是:name 和 type。
用在:类、成员变量和方法上
@Resource是JDK定义的注解
CommonAnnotationBeanPostProcessor是处理@ReSource注解的
@Resource的匹配逻辑为byName -> byType -> byName
有多个bean时,可以在Class_A 上增加@Primary 优先装配A,来避免匹配失败
3.2.1 @Autowire
-
@Autowired装配失败,装配的对象还是null
原因:
① 类上面忘了加@Component(@Service、@Repository @Controller) @Configuration等注解,spring就无法完成自动装配的功能
② 注解未被@ComponentScan扫描 ,或者@ComponentScan注解扫描的路径不对
③ 注入Filter或Listener
(web应用启动的顺序是:listener->filter->servlet)
springmvc的启动是在DisptachServlet里面做的,而它是在listener和filter之后执行。若在listener和filter里面
@Autowired某个bean时bean还没有初始化,无法自动装配 -
作用范围 成员变量\构造器\set 方法\构造器入参\非静态方法入参
基于变量依赖注入使用最广泛,但是缺点 :
无法在启动时对注入的属性进行安检:
1. 只有业务使用时才能拿到类,注入对象的为null,暴露晚
2. 配置信息错误,测试执行阶段才知道
别的类想重新设置下你的某个注入属性,没法处理(当然反射可以做到).spring 推荐 基于构造函数和基于setter的依赖注入.: ( 小白视角: 写的很冗余,用字段方便简洁多了) 基于构造函数的注入 : 对必需的依赖项以使它们成为不可变的,并防止它们为null。 对于可选的依赖项,建议使用基于Setter的注入
1 成员变量在成员变量上使用Autowired注解:
@Service
public class UserService {
@Autowired
private IUser user;
}这种方式可能是平时用得最多的。4.2 构造器在构造器上使用Autowired注解:@Service
public class UserService {
private IUser user;
@Autowired
public UserService(IUser user) {
this.user = user;
System.out.println("user:" + user);
}
}注意,在构造器上加Autowired注解,实际上还是使用了Autowired装配方式,并非构造器装配。4.3 方法在普通方法上加Autowired注解:@Service
public class UserService {
@Autowired
public void test(IUser user) {
user.say();
}
}spring会在项目启动的过程中,自动调用一次加了@Autowired注解的方法,我们可以在该方法做一些初始化的工作。也可以在setter方法上Autowired注解:
@Service
public class UserService {
private IUser user;
@Autowired
public void setUser(IUser user) {
this.user = user;
}
}4.4 参数可以在构造器的入参上加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.say();
}
}
4.5 用在注解上
4.6 自动装配默认都是单个实例
Autowired 实现自动装配多个实例
UserService方法调整一下,用一个List集合接收IUser类型的参数:
@Service
public class UserService {
@Autowired
private List<IUser> userList;
@Autowired
private Set<IUser> userSet;
@Autowired
private Map<String, IUser> userMap;
public void test() {
System.out.println("userList:" + userList);
System.out.println("userSet:" + userSet);
System.out.println("userMap:" + userMap);
}
}增加一个controller:@RequestMapping("/u")
@RestController
public class UController {
@Autowired
private UserService userService;
@RequestMapping("/test")
public String test() {
userService.test();
return "success";
}
}
3.2.2 @Resource
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;推荐使用@Resource注解在字段上,这样就不用写setter方法了.并且这个注解是属于J2EE的,减少了与Spring的耦合,这样代码看起就比较优雅 。