1、使用@Autowired注解自动装配
上一章提到使用@Value注解只能装配普通值,是不能装配对象的,所以这章我们来介绍使用注解自动装配对象,需要使用到@Autowired注解:
- @Autowired:它默认是按byType进行匹配,可以用于修饰类成员变量(字段)、Setter 方法、构造函数,甚至普通方法,但是前提是方法必须有至少一个参数。
我们在实际的开发中基本都会使用注解来对对象属性完成自动装配,因为这样可以减少配置的复杂度,所以@Autowired非常的重要!
①、作用于类的成员变量(字段)(最常用)
---User类:
@Component(value = "user") public class User { @Value(value = "2020") private int userId; @Value(value = "是菜逼唐") private String userName; @Value(value = "20") private int userAge; @Value(value = "123456") private String userPwd; @Value(value = "地球中国北京") private String userAddress; //这里使用@Autowired注解自动注入 @Autowired private GirlFriend girlFriend; //getter、setter、toString方法省略...... }
---GirlFriend类:
@Component public class GirlFriend { @Value("王美丽") private String girlName; @Value("18") private int girlAge; @Value("170") private String girlHeight; //getter、setter、toString方法省略...... }
---测试代码(扫描组件注解参考上一章):
/** * 测试代码 */ public class SpringTest1 { public static void main(String[] args) { //1.初始化Spring容器,通过注解加载 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PojoConfig.class); //2.通过容器获取实例 User user = applicationContext.getBean("user", User.class); //3.调用实例中的属性 System.out.println(user.getUserId()+"----"+ user.getUserName()+"----"+ user.getUserAge()+"----"+ user.getGirlFriend()); } }
---运行测试代码,查看控制台打印的结果:
②、作用于Setter方法和作用于构造函数。这两种方式实现的效果和上面的效果是一模一样的。
1)、作用于Setter方法
2)、作用于构造函数
注意:如果已经使用注解完成了初始化工作,那么则不能再创建该参数的构造方法了,比如我们使用了@Value注解初始化userName属性,那么则就不能再创建userName属性的构造方法了。
可以明显的分析,后面两种方式的可读性并不高,所以一般都推荐使用第一种方式,作用于类的成员变量。
补充1:@Autowired注解中有个属性required,这个属性是一个boolean类型,为true(默认)表示注入bean的时候该bean必须存在,不然就会注入失败,但程序不报错 。为 false 表示注入bean的时候如果bean存在,就注入成功,如果没有就忽略跳过,启动时不会报错!但是不能直接使用,因为bean为NULL!
例如我将GirlFriend类的@Component注解给注释掉,并且把User类中的@Autowired注解的属性required设置为false。
----------------------------------------
通过运行的结果可以发现注入失败了。
补充2:@Autowired注解并不是完全按照byType进行匹配。而是默认先按byType进行匹配,如果发现找到多个bean,则又按照byName方式进行匹配,如果还有多个,则报出异常。动手能力强的可以自己去实践一遍,我自己是去验证过的。
2、@Autowired自动装配的歧义性
由于@Autowired注解是根据类型来自动装配的,所以肯定会存在有多个相同类型的bean,而Spring IOC容器却不知要选择哪一个的情况,此时就产生了歧义性,那么我们怎么来解决呢?Spring中给我们提供了@Primary和@Qualifier这两个注解。
- @Primary:表示优先使用该注解标志的bean。实际开发中不实用,所以就不介绍了。
- @Qualifier:表示当容器中存在多个相同类型的bean时,使用这个注解可以根据bean的名字来选择注入哪个bean,推荐使用这种方式。
因为这里的代码不好举例,所以可以参考这个链接:https://blog.csdn.net/qq_36567005/article/details/80611139
3、与@Autowired类似的注解@Resource
@Resource 注解相当于@Autowired,它们两个都是用来实现依赖注入的。只是@AutoWried默认按byType自动注入,而@Resource默认按byName自动注入。而且@Resource只能处理setter注入(包括字段)。@Resource有两个重要属性,分别是name和type,其中name属性相当于@Qualifier,type相当于根据类型配置。Spring 将 name 属性解析为bean的名字,而type属性则被解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,如果使用type属性则使用byType的自动注入策略。如果都没有指定,则通过反射机制使用byName自动注入策略。表面上我们说@Resource默认按byName自动注入,其实如果按名称查找不到匹配的bean时,最后会按byType进行自动注入,@Resource依赖注入时查找bean的规则如下:
- 如果不指定name属性,也不指定type属性,则自动按byName方式进行查找。如果没有找到符合的bean,则回退为一个原始类型进行进行查找,如果找到就注入。
- 只是指定了@Resource注解的name属性,则只能按name后的名字去bean元素里查找有与之相等的name属性的bean,如果找不到则会抛出异常。
- 只指定@Resource注解的type属性,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常。
- 既指定了@Resource的name属性又指定了type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
补充:但是我好像听说这个注解在Java11中被删除了,也不知道是不是真的,如果是真的还是慎用!然后我去查了一下JDK11的官方文档,确实JDK11将javax.annotation这个包移除了,如果想继续使用可以通过maven或者其他方式导入。
<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
如果这个依赖无法使用,可以去maven仓库自行查找。
4、@Autowired和@Resource的区别
相同点:
- 二者均可以用来注入bean,都可以用在字段上或者方法上
不同点:
- @Autowired是属于Spring框架的,而@Resource属于J2EE。
- @Autowired默认按byType进行装配,可以结合@Qualifier使用按名称装配,如果发现找到多个bean,则又按照byName方式进行匹配,如果还有多个,则报出异常。
- @Resource默认按byName进行装配,名称可以通过name属性进行指定,如果没有指定name属性,则默认采用字段名进行查找,当找不到与名称匹配的bean时才按byType进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
小结:@Autowired是按照先按 byType 后按 byName 进行匹配,@Resources是按照先按 byName 后按 byType进行匹配。
5、@Named/@Inject(了解)
这两个注解的是JSR-330的一部分,而Spring 是支持JSR-330的。这些注解在使用上和Spring的注解一样,只是想要导入额外的相关jar包。如下:
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject --> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
- @Named 用来替代@Component 声明一个Bean
- @Inject 用来替代@Autowired来执行注入
实际上我们很少会使用这样的注解,使用知道有这个东西即可。
参考链接: