首页 > 代码库 > Spring实战笔记4---Spring的自定装配与自动检测

Spring实战笔记4---Spring的自定装配与自动检测

Spring的自动装配与自动检测是为了最小化Spring XML配置,如果我们有很多的Bean要装配到spring 容器中,那么我们的配置文件将会看起来很长很长,让人觉得头晕,适当的使用自动装配与自动检测,将有助于缓解以上提到的问题


*自动装配:(autowiring) 有助于减少甚至消除配置<property>元素和<constructor-arg>元素,让Spring自动识别如何装配Bean的依赖关系。

*自动检测:(autodiscovery) 比自动装配更进一步,让Spring能够自动识别哪些类需要被装配成SpringBean 从而减少对<bean> 元素的使用


自动装配

spring提供了四种自动装配的方式

* byName 把Bean的属性具有相同名字的的其他Bean自动装配到Bean的对应属性中

* byType 把与Bean的属性具有相同类型的的其他Bean 自动装配Bean的对应属性当中

* constructor 把与Bean 的构造器入参具有相同类型的其他Bean自动装配到构造器的对应入参中

*autodetect 首先尝试使用constructor进行自动装配,如果失败,再使用byType进行自动装配


byName

<bean id="kenny2" class="xxx.xxx.xxx">
  <property name="song" value=http://www.mamicode.com/"Jingle Bells"/>>


我们看看上下两种配置的方式的区别,属性instrument的值是一个已经再该上下文中定义的一个Bean,再引用的时候引用的是其id,第二种方式把该Bean的id改成了与引用它的Bean属性相同的名字,然后使用byName的方式来自动装配,可以看到再第二种装配中,我们没有显示的设置instrument的值,而是在第一次调用该bean的时候系统自动匹配与该属性同名的bean来自动装配,用此种方式来简化xml的配置。


byType 

<bean id="kenny" class="xxx.xxx.xxx" autowire="byType">
  <property name="song" value=http://www.mamicode.com/"Jingle Bells"/>>

只需要把autowire属性值改为byType就可以了,但是在应用上下文当中,如果有多个bean的类型与该bean的自动装配属性相匹配,那么就会出错,因为byType方式只允许匹配一个类型相同的Bean,如果应用上下文存在多个类型相同的bean怎么办呢,spring提供了另外两种选择,可以设置一个首选bean,或者排除一些bean。


<bean>元素的primary属性代表是否是首选bean,如果标注为true,那么该bean将成为首选bean,但是spring默认每个bean的primary属性都市true,所以如果需要设置首选bean需要将那些非首选bean的primary属性标注为false。

如果我们在自动装配的过程当中,想排除某些bean的时候,可是使用把autowire-candidate属性设置为false。

看如下代码

<bean id="kenny" class="xxx.xxx.xxx" autowire="byType" primary="false">
  <property name="song" value="Jingle Bells"/>
</bean><pre name="code" class="html"><bean id="kenny" class="xxx.xxx.xxx" autowire="byType" autowire-candidate="false">
  <property name="song" value=http://www.mamicode.com/"Jingle Bells"/>>

如上两个例子分别代表了以上描述的两种选择

constructor

<bean id="kenny" class="xxx.xxx.xxx" autowire="constructor">
  <property name="song" value=http://www.mamicode.com/"Jingle Bells"/>>构造器自动装配只需要把autowire属性设置为constructor就可以了,这样就免去了声明<constructor-arg>元素


最佳自动装配(autodetect)

<bean id="kenny" class="xxx.xxx.xxx" autowire="autodetect">
  <property name="song" value=http://www.mamicode.com/"Jingle Bells"/>>首先使用constructor如果失败,就是使用byType,使用方法跟以上介绍的都是一样的 ,这里不多说了


默认自动装配

如果在一个配置文件中,所有的装配都使用同一种自动配置方式的话, 要在每个bean声明的时候都加上一个autowire属性也是很麻烦的,为了避免这样的重复操作,可以使用默认自动装配。

使用默认自动装配的方法是在<beans>元素中添加一个default-autowire属性,添加了这个属性之后,该配置文件当中的自动装配方式将以默认的方式来装配,如果有某个个别的bean需要使用其他的方式,在该bean上直接设置autowire属性就可以了,会覆盖掉默认自动装配的配置,代码如下。

<beans ...
  default-autowire="byType">
</beans>


使用注解装配

在使用注解装配之前,首先要开启注解装配的方式,那就是在配置文件中加上下面这句话

<context:annotation-config>

当然前提是添加context命名空间

spring支持多种注解装配的方式,这里主要介绍spring自带的注解装配


使用@Autowired注解

该注解几乎可以用在任何方法上,只要该方法需要自动装配参数都可以,不一定非得是setter方法,但是一般都是使用在setter方法和构造器上的,看如下代码

@Autowired
public void setInstrument(Instrument instrument){
    this.instrument = instrument;
}
以上代码是把@Autowired注解放在setter方法上,在spring创建该类的bean的时候,就会自动寻找匹配的参数注入到该bean当中,当但参数需要同时在应用上下文中装配才可以,不然的话是找不到的。

@Autowired另外一个用法就是注解构造函数

@Autowired
public Instrumentalist(Instrument instrument){
    this.instrument = instrument;
}

@Autowired还有一种用法就是直接注解在属性上,从而去掉setter方法

@Autowired
private Instrument instrument;

注意:@Autowired使用的时候必须只有一个Bean适合装配到@Autowired注解所标注的属性或者参数中,否则的话,spring会抛出异常,如果在应用上下文当中找不到相应的bean去自动装配,那么spring也会抛出异常(NoSuchBeanDefinitionException),如果想避免这种情况发生,而且需要装配的属性也不是必须要装配的话,可以使用如下代码来使用注解

@Autowired(required=false)
private Instrument instrument;
在这里添加@Autowired的required属性,将这个属性设置为false,意思就是在创建bean的时候该属性不是必须的


@Qualifier注解

如果在同一个应用上下文当中出现了两个都必须存在的bean,然而自动装配只需要装配期中一个,这个时候可以使用@Qualifier注解指定一个Bean来装配,这样就不会报异常了

@Autowired
@Qualifier("guitar")
private Instrument instrument;
括号中的字符串标注的是需要自动装配进来的Bean的id



在注解注入中使用表达式

在使用注解自动装配的过程当中,如果想要自动装配基本类型的或者是字面值常量的参数的话,可以是用@Value注解

@Value("Eruption")
private String song;
在这里自动装配为一个String类型的属性装配了一个String类型的值,同样可以装配int,boolean等基本类型的属性。


在@Value注解中,我们可以使用表达式来动态的计算并装配属性的值比如使用spel表达式从系统属性中取得一个值

@Value("#{systemProperties.myFavoriteSong}")
private String song;


自动检测Bean

自动检测可以让Spring从指定的保重自动扫描需要被装配到容器当中的bean,但是在使用之前,需要先开启自动装配,这就需要在spring的配置文件当中配置如下的代码

<context:component-scan base-package="com.springinaction.springidol"></context:component-scan>
在这个配置下spring会自动检测com.springinaction.springidol保重的所有可以被注册为springbean的类,然后自动生成相应的bean。

可以使用如下注解来标识哪些类是可以自动注册为Springbean的类


* @Component 通用的构造型注解,标识该类为spring组件

* @Controller 标识将该类定义为spring MVC 控制器

* @Repository 标识将该类定义为数据仓库(在使用数据库的时候可以用到该注解)

* @Service 标识将该类定义为服务

* 使用@Component标注的任意自定义注解

@Component
public class Guitar implements Instrument{
    public void play(){
        System.out.println("......");
    }
}
在该场景下GuitarBean的id将被设置为默认的guitar


可以在@Component注解中指定Bean的id

@Component("eddie")
public class Guitar implements Instrument{
    public void play(){
        System.out.println("......");
    }
}
这样在spring容器中该类的Bean的id就变为了eddie


spring的自动检测还包含了一种不实用注解的自动检测规则,该规则在今后程序中用到的时候再来介绍,这里不过多介绍了


Spring实战笔记4---Spring的自定装配与自动检测