前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring 自动装配Bean

Spring 自动装配Bean

作者头像
技术从心
发布2020-03-11 11:41:16
6780
发布2020-03-11 11:41:16
举报
文章被收录于专栏:技术从心

来源:https://mrbird.cc

为了简化XML配置,Spring提供了自动装配(autowiring)。

四种类型自动装配

byName自动装配

byName自动装配遵循约定:为属性自动装配ID与该属性的名字相同的Bean。例如,将先前的kenny例子:

代码语言:javascript
复制
<bean id="kenny" class="com.spring.entity.Instrumentalist">
    <property name="instrument" ref="saxophone"></property>
    <property name="song" value="May Rain"/>
</bean>

改为:

代码语言:javascript
复制
<bean id="kenny" class="com.spring.entity.Instrumentalist" autowire="byName">
    <property name="song" value="May Rain"/>
</bean>

通过autowire属性,Spring就可以利用此信息自动装配kenny的剩下的instrument属性了。

配置一个id为”instrument”的Bean:

代码语言:javascript
复制
<bean id="instrument" class="com.spring.entity.Saxophone"/>

这样,saxophone就自动装配给kenny的instrument属性了。当找不到时,则该属性不进行装配。

如果多个Instrumentalist Bean都被配置为byName自动装配,那他们将会演奏同一个乐器。

byType自动装配

byType自动装配通过寻找哪一个Bean的类型与属性的类型相匹配。如果找到多个与需要装配的属性类型相匹配的Bean,Spring会直接抛出异常。所以,应用只允许存在一个类型相匹配的Bean。但在实际中,XML中可能存在多个类型一样的Bean,为了解决这种情况,Spring提供了两种解决方法:

① 为自动装配标识一个首选Bean

使用<bean>元素的primary属性。如果只有一个自动装配的候选Bean的primary属性设置为true,那么其将被优先选择。比如设置saxophone为首选Bean:

代码语言:javascript
复制
<bean id="saxophone" class="com.spring.entity.Saxophone" primary="true"/>

也可以使用@Primary注解。② 取消某个Bean自动装配的候选资格

使用方法为设置Bean的autowire-candidate属性为false即可:

代码语言:javascript
复制
<bean id="saxophone" class="com.spring.entity.Saxophone" autowire-candidate="false"/>

constructor自动装配

如果通过构造器注入配置Bean,那么可以移除<constructor-arg>元素。如将先前的duke配置:

代码语言:javascript
复制
<bean id="duke" class="com.spring.entity.Juggler" autowire="constructor"/>

通过autowire="constructor"声明,Spring会去获取Juggler某个构造器的所有参数类型,然后再XML中寻找与其类型匹配的Bean。so,constructor自动装配与byType自动装配具有相同的局限性。

autodetect自动装配

detect 英[dɪˈtekt] 美[dɪˈtɛkt] vt. 查明,发现; 洞察; 侦察,侦查; [电子学] 检波

代码语言:javascript
复制
<bean id="duke" class="com.spring.entity.Juggler" autowire="autodetect"/>

通过该声明,Spring首次尝试使用constructor自动装配,失败的话再次尝试使用byType自动装配。

默认自动装配

通过配置<beans>元素上增加一个default-autowire属性:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:util="http://www.springframework.org/schema/util"  
	xmlns:jee="http://www.springframework.org/schema/jee" 
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa" 
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="
    	http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    	http://www.springframework.org/schema/context
    	http://www.springframework.org/schema/context/spring-context-3.2.xsd
    	http://www.springframework.org/schema/util
    	http://www.springframework.org/schema/util/spring-util-3.2.xsd
    	http://www.springframework.org/schema/jee
    	http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
    	http://www.springframework.org/schema/tx
    	http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
    	http://www.springframework.org/schema/data/jpa
    	http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
    	http://www.springframework.org/schema/mvc
    	http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd"
        default-autowire="byType">
    <!--Bean declarations go here -->
</beans>

这样的话,Spring配置文件里的所有Bean都将使用byType自动装配,除非Bean自己配置了autowire属性。

混合装配

一个Bean可以同时使用自动装配和显示装配,如:

代码语言:javascript
复制
<bean id="kenny" 
    class="com.spring.entity.Instrumentalist" autowire="byType">
    <property name="song" value="May Rain"/>
    <property name="instrument" ref="saxophone"></property>
</bean>

混合使用可以避免当自动装配失败的时候,使用显示装配覆盖自动装配。

使用constructor自动装配时,不能混合使用constructor自动装配策略和元素。

使用注解装配

代码语言:javascript
复制
<context:annotation-config/>

annotation 英[ˌænə’teɪʃn] 美[ˌænə’teɪʃn] n. 注释;

<context:annotation-config/>可以消除Spring中的<property><constructor-arg>元素。注意,我们还是得使用<bean>元素显示定义Bean。

@Autowired

例如,在Instrumentalist的setInstrument()方法进行标注:

代码语言:javascript
复制
//注入乐器
@Autowired
public void setInstrument(Instrument instrument) {
    this.instrument = instrument;
}

这样,我们可以移除用来定义Instrumentalist的instrument属性所对应的<property>元素了。通过@Autowired注解,Spring会通过byType自动装配。

假如@Autowired注解标注于属性,我们可以删除setter方法:

代码语言:javascript
复制
@Autowired
private Instrument instrument;

@Autowired也可以标注于构造器,这样XML文件中可以省去<constructor-arg>元素配置Bean:

代码语言:javascript
复制
@Autowired
public Instrumentalist(Instrument instrument) {
    this.instrument=instrument;
}

当多个构造器都通过@Autowired注解的时候,Spring就会从所有满足装配条件的构造器中选择出参数最多的那个。

可选的自动装配:

通过@Autowired标注的属性或者参数必须是可装配的。假如匹配失败,则抛出NoSuchBeanDefinitionException异常。假如属性不一定要装配,null值也可以接收的话,我们可以设置required=fasle来让自动装配变为可选:

代码语言:javascript
复制
@Autowired(required=false)
private Instrument instrument;

当使用构造器装配时,只有一个构造器可以将@Autowired的required属性设置为true,其余的只能设置为false。

限定歧义性依赖:

如果通过@Autowired注解匹配到好几个Bean,为了鉴别哪一个是我们需要的,我们可以在@Autowired注解下添加@Qualifier注解:

qualifier 英[ˈkwɒlɪfaɪə(r)] 美[ˈkwɑ:lɪfaɪə(r)] n. 合格者,已取得资格的人; [语] 修饰语; 预选赛,资格赛

代码语言:javascript
复制
@Autowired
@Qualifier("guitar")
private Instrument instrument;

如上所示,@Qualifier注解将尝试注入ID为”guitar”的Bean。

除了通过Bean的ID来匹配,我们还可以修改guitar Bean配置:

代码语言:javascript
复制
<bean class="com.spring.entity.Guitar">
    <qualifier value="Stringed"/>
</bean>

<qualifier>元素限定了guitar Bean是一个弦乐器(stringed)。这时候可以将上面的注解修改为:

代码语言:javascript
复制
@Autowired
@Qualifier("Stringed")
private Instrument instrument;

创建自定义的限定器:

首先,通过如下代码创建自定义的限定器:

代码语言:javascript
复制
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
 
@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface StringedInstrument {
 
}

这样,我们在guitar类上添加此限定器:

代码语言:javascript
复制
@StringedInstrument
public class Guitar implements Instrument{
    public void play() {
        System.out.println("弹奏吉他");
    }	
}

在自动装配的instrument属性进行限定:

代码语言:javascript
复制
@Autowired
@StringedInstrument
private Instrument instrument;

这样guitar就会被装配的instrument属性里!

假如匹配到多个Bean,需要进一步的缩小范围,继续定义自定义限定器即可!

@Inject

Maven依赖:

代码语言:javascript
复制
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

为了规范各种依赖注入框架的编程模型,JCP(Java Community Process)发布了Java依赖注入规范,简称为JCR-330。Spring 3.0开始兼容该依赖注入模型。@Inject注解几乎可以完全替代@Autowired。如:

代码语言:javascript
复制
@Inject
private Instrument instrument;

@Inject也可以标注于属性,方法和构造器,不过@Inject没有required属性,所以@Inject注解所标注的依赖关系必须存在,否则抛出异常。

限定@Inject所标注的属性

类似于前面的@Qualifier@Inject所对应的是@Named注解:

代码语言:javascript
复制
@Inject
@Named("piano")
private Instrument instrument;

创建自定义的JSR-330 Qualifier

通过下面的代码创建一个新的@NewStringedInstrument注解:

代码语言:javascript
复制
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
 
@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface NewStringedInstrument {
 
}

和前面的自定义限定器唯一的区别就是@Qualifier注解的导入声明。

在注解中使用SpEL表达式

Spring3.0 引入了@Value,其可以注解装配String类型和基本类型的值。比如,我们通过@Value注解传入一个String类型的值:

代码语言:javascript
复制
@Value("May Rain")
private String song;

这样”May Rain”就被注入到song属性中了。

我们还可以结合SpEL表达式:

代码语言:javascript
复制
@Value("#{systemProperties.myFavoriteSong}")
private String song;

@Resource

Maven依赖:

代码语言:javascript
复制
<!-- https://mvnrepository.com/artifact/javax.annotation/jsr250-api -->
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>jsr250-api</artifactId>
    <version>1.0</version>
</dependency>

@Resource注解是JSR-250发布的注解。与@Autowired@Inject不同的是,@Resource注解不能用于构造器!@Resource注解默认使用byName自动装配!

@Resource有两个中重要的属性:name和type ,而Spring将@Resource注解的name属性解析为bean的 名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用 byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。

byName:

代码语言:javascript
复制
@Resource(name="piano")
private Instrument instrument;

byType:

代码语言:javascript
复制
@Resource(type=Instrument.class)
private Instrument instrument;
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术从心 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 来源:https://mrbird.cc
  • 四种类型自动装配
    • byName自动装配
      • byType自动装配
        • constructor自动装配
          • autodetect自动装配
          • 默认自动装配
          • 混合装配
          • 使用注解装配
            • @Autowired
              • @Inject
                • @Resource
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档