前言
Spring
是我们平常开发中离不开的核心框架,每天开发都在使用 Spring
的功能。
还记得刚开始学习 Spring
的时候,那个时候 Spring
的版本还很低,大概是 Spring 3.X
的版本。那个时候 Spring
编程一切都离不开 XML
文件,所有 Bean
需要在 XML
中定义,也需要通过 XML
方式的注入。
后来,Spring
注解的方式开始火了,我们可以直接使用 @Component
等生成 Bean
,也可以直接通过 @Autowired
注解的方式注入 Bean
。
最近翻看 Spring
的文档,才发现原来 @Autowired
注解使用方式还有很多种,有些方式使用起来很有意思,巧加利用的话,可以非常节省我们的开发时间。
@Autowired 注解的注入规则
当Spring
在根据xml
文件加载bean
对应的类时发现@Autowired
注解时,将自动根据代码上下文的类名去xml
文件找到与其匹配(默认是类型匹配)的bean
,并自动注入到相应的地方去。
默认根据类型,匹配不到则根据
bean
名字
@Autowired
的(required=false
)选项
默认情况下,@Autowired
注解意味着依赖是必须的,它类似于 @Required
注解,然而,你可以使用 @Autowired
的 (required=false)
选项关闭默认行为。
@Autowired 字段
我们可以把 @Autowired
注解标注在类文件中的字段属性上,通过这种方式,Spring
容器启动的时候会查找相应的 Bean
,然后通过反射的方式注入到这个字段中。
例子如下:
@Controller
public class PayController {
@Autowired
PayService aliPayService;
}
这种方式使用起来非常方便,而且对于字段的要求也比较低,它可以是 public
,也可以是 private
范围。
日常编程中,我一般是直接使用这种方式,简洁又便利。
@Autowired 构造方法
第二种方式,我们可以使用类中的构造函数注入相应属性,例子如下:
@Controller
public class PayController {
PayService aliPayService;
@Autowired
public PayController(PayService aliPayService) {
this.aliPayService = aliPayService;
}
}
@Autowired
构造方法里的传参,可以是一个,也可以是多个。如果是多个参数,那 Spring
一起都注入进来。
@Controller
public class PayController {
PayService aliPayService;
OrderService orderService;
@Autowired
public PayController(PayService aliPayService, OrderService orderService) {
this.aliPayService = aliPayService;
this.orderService=orderService;
}
}
这种方式在注入多个属性的时候用起来还是比较方便的。
那其实有一种情况下,如果一个类不存在无参的构造函数,只存在有参的构造函数,那实际上我们即使不用 @Autowired
标注,Spring
也会帮我们注入相应的属性。
可以看到,上面的例子,我们没有在构造函数上使用 @Autowired
标注,但是 IDEA
依然显示我们成功注入相应的属性。
@Autowired 方法
第三种方式,我们可以通过方法注入相应属性,例子如下:
@Controller
public class PayController {
PayService aliPayService;
@Autowired
public void setAliPayService(PayService aliPayService) {
this.aliPayService = aliPayService;
}
}
那之前我一直以为这种方式只能使用 setxxx
才可以成功的注入属性 ,那其实是我理解错了,这个方法可以任意的命名。
那方法注入,其实跟构造方法一样,也可以同时有多个传参,Spring
将会把这些属性一起注入。
@Autowired 多个 Bean
最后一种方式,Spring
可以使用 @Autowired
标注 Array
(数组),Collections
(集合),甚至是 Map
(散列表),通过这种命方式注入多个相同类型的 Bean
。
比如这种方式,将 PayService
接口所有实现类注入到 Array
数组中。
也可以是这种方式,注入到 List
集合中。
上面的两个例子,数组与集合中的
Bean
的顺序是根据Spring
创建的顺序****。
如果你想指定里面排序的优先级,那你就需要使用 @Order
或者 @Priority
指定一下优先级,比如这样:
或者这样:
@Order/Priority
注解中值越小,那它的优先级就越高。
最后我们还可以将 PayService
接口所有实现类注入到 Map
中,其中里面的 key
就是Spring
的 Bean
的名字。
ps
: 使用@Autowired
注入属性到Map
中,key
必须是String
类型。
这也可以理解,你要是其他类型,Spring
都不知道去哪里给你找。。。
@Resource
@Resource
的作用相当于@Autowired
,只不过@Autowired
按byType
自动注入,而@Resource
默认按 byName
自动注入罢了。@Resource
有两个属性是比较重要的,分是name
和type
,Spring
将@Resource
注解的name
属性解析为bean
的名字,而type
属性则解析为bean
的类型。所以如果使用name
属性,则使用byName
的自动注入策略,而使用type
属性时则使用byType
自动注入策略。如果既不指定name
也不指定type
属性,这时将通过反射机制使用byName
自动注入策略。
直接写PayController .java
了:
@Controller
public class PayController {
@Resource(name = "aliPayService")
PayService aliPayService;
@Resource(type = OrderService .class)
OrderService orderService;
}
@Resource
的装配顺序:
- 如果同时指定了
name
和type,则从Spring
上下文中找到唯一匹配的bean
进行装配,找不到则 抛出异常 - 如果指定了
name
,则从上下文中查找名称(id
)匹配的bean
进行装配,找不到则抛出异常 - 如果指定了
type
,则从上下文中找到类型匹配的唯一bean
进行装配,找不到或者找到多个,都会抛出异常 - 如果既没有指定
name
,又没有指定type
,则自动按照byName
方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
总结
@Autowired与@Resource对比
@Autowired | @Resource |
---|---|
Spring定义的注解 | JSR-250定义的注解 |
一个参数:required(默认true),表示是否必须注入 | 七个参数:最重要的两个参数是name、type |
默认按类型自动装配 | 默认按名称自动装配 |
默认按类型自动装配如果要按名称自动装配,需要使用@Qualifier一起配合 | 默认按名称自动装配如果指定了name,则按名称自动装配;如果指定了type,则按类型自动装配 |
作用范围:构造器、方法、参数、成员变量、注解 | 作用范围:类、成员变量、方法 |
@Autowired装配流程
@Resource装配流程
@Autowired
@Autowired
注解可以把相应 Bean
注入到相关属性中,它的注入方式有很多种。
我们可以使用 @Autowired
直接标注类中的字段,快速使用。
我们也可以使用 @Autowired
标注构造方法/普通的方法,这样可以方便注入多个 Bean。
最后,我们还可以 @Autowired
标注 Array
(数组),Collections
(集合),甚至是 Map
(散列表),将所有匹配到的 Bean
注入进来。
那最后一种方式,其实在某些场景非常有用。比如说,我们通过 @Autowired
将所有匹配到 Bean
注入到 Map
中,利用这个特性,我们可以快速实现策略模式。