Spring(三)装配Bean:自动装配Bean

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

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


1、4种类型的自动装配

  • byName——把与Bean的属性具有相同名字(或者ID)的其他Bean自动装配到Bean的对应属性中。如果没有跟属性的名字相匹配的Bean,则该属性不进行装配。

  • byType——把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中。如果没有跟属性的名字相匹配的Bean,则该属性不进行装配。

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

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


byName自动装配

——为属性自动装配ID与该属性同名的Bean

例:

假设存在一个Instrumentalist类包含属性song、instrument,以下是手动装配Bean的方式。

<bean id="saxophone" class="com.roger.spring.beans.Saxophone" />

<bean id="kenny" class="com.roger.spring.beans.Instrumentalist">
    <property name="song" value="Jingle Bells" />
    <property name="instrument" ref="saxophone" />
</bean>

如果要利用byName自动装配,就需要在使用<bean>元素定义Saxophone的时候,将Bean的id设置为I和nstrumentalist属性instrument同名的字面值。 通过配置autowire属性就可以利用此信息自动装配 kenny 的 instrument 属性了。

<bean id="instrument" class="com.roger.spring.beans.Saxophone" />

<bean id="kenny" class="com.roger.spring.beans.Instrumentalist"
    autowire="byName">
    <property name="song" value="Jingle Bells" />
</bean>


byType自动装配

——Spring会寻找哪一个Bean的类型与属性的类型相同。

局限:如果Spring寻找到多个Bean,它们的类型与需要自动装配的属性的类型都相匹配,这时候,Spring不会猜测哪一个Bean更适合自动装配,而是选择抛出异常。所以,应用只允许存在一个Bean与需要自动装配的属性类型相匹配。

解决装配歧义的问题:可以为自动装配标识一个首选,或者取消某个Bean自动装配的候选资格。

  • 标识首选

        利用<bean>的primary属性, 默认为true,因此要达到标识首选的目的,需要将其他候选的primary属性都设为false。

  • 取消候选

        将<bean>的autowire-candidate属性设为false。


constructor自动装配

——在Bean声明中,不需要<constructor-arg>元素了

局限:a. 具有和byType自动装配相同的局限,当发现多个Bean匹配某个构造器入参时,Spring不会猜测哪个更适合;

          b. 如果一个类有多个构造器,它们都满足自动装配的条件时,Spring也会猜测哪个更适合。


默认自动装配

    利用<beans>属性default-autowire进行设置,默认为none,表示都不使用自动装配。可以利用<bean>元素的autowire属性来覆盖<beans>的默认自动装配策略。


2、使用注解装配Bean

  • 使用注解方式允许更细粒度的自动装配,可以选择性地标注某一个属性来对其应用自动装配。

  • Spring容器默认禁用注解装配

    xml配置中启用注解,利用context命名空间中<context:annotation-config>元素,如下所示:

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http:..www.springframework.org/schema/context
        http:..www.springframework.org/schema/context/spring-context.xsd">
    
    <context:annotation-config />
    
</beans>


Spring支持集中不同的用于自动装配的注解:

  • Spring自带的@Autowired注解

  • JSR-330的@Inject注解

  • JSR-250的@Resource注解

@Autowired 默认是通过byType方式进行自动装配的,通过结合@Qualifier注解可以通过匹配Bean的id进行自动装配。

如:

通过@Qualifier注解将范围缩小,尝试将id为"guita"的bean注入。

@Autowired
@Qualifier("guita")
private Instrument instrument;

 a、@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入;

 b、@Autowired默认是按照类型装配注入的,如果想按照名称来转配注入,则需要结合@Qualifier一起使用;

 c、@Resource注解是由J2EE提供,而@Autowired是由Spring提供,故减少系统对spring的依赖建议使用  

       @Resource的方式;

d、@Resource和@Autowired都可以书写标注在字段或者该字段的setter方法之上


3、自动检测Bean

    即使<context:annotation-config>元素有助于完全消除Spring配置中的<property>和<constructor-arg>元素,但是仍要使用<bean>元素显示定义Bean。

    因此,借助<context:component-scan>元素,除了完成与<context:annotation-config>一样的工作,还允许Spring自动检测Bean和定义Bean。中意味着不使用<bean>元素,Spring应用中的大多数(或所有)Bean都能够实现定义和装配。

    还可以通过<context:component-scan>元素的base-package属性标识<context:component-scan>元素会扫描指定的包及其所有子包。

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http:..www.springframework.org/schema/context
        http:..www.springframework.org/schema/context/spring-context.xsd">
    
    <context:component-scan
        base-package="com.roger.spring.beans">
    </context:component-scan>
    
</beans>

3.1、为自动检测标注Bean

    默认情况下,<context:component-scan>查找使用构造型(stereotype)注解所标注的类。

这些特殊注解如下:

  • @Component——通过的构造型注解,标识该类为Spring组件

  • @Controller——标识将该类定义为Spring MVC controller

  • @Repository——标识将该类定义为数据仓库

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

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


    Spring扫描发现@Component注解所标注的类,并自动地将它注册为Spring Bean,Bean的ID默认为无限定类名(如:Person Bean的id为person)。

    也可以使用@Component("Roger")方式来指定Bean的id。

3.2过滤组件扫描

    通过为<context:component-config>配置子元素<context:include-filter>或者<context:exclude-filter>来调整扫描行为。

    <context:include-filter>的type和expression属性一起来定义组件扫描策略。

过滤器类型 描述
annotation
过滤器扫描使用指定注解所标注的那些类,通过expression属性指定要扫描的注解
assignable 过滤器扫描派生于expression属性所指定类型的那些类
aspectj 过滤器扫描与expression属性所指定的AspectJ表达式所匹配的那些类
custom 使用自定义的org.springframework.core.type.TypeFilter实现类,该类由expression属性指定
regex 过滤器扫描类的名称与expression属性所指定的正则表达式所匹配的那些类

例如:

<context:component-scan
    base-package="com.roger.spring.beans">
    <context:include-filter type="assignable"
        expression="com.roger.spring.Address" />
</context:component-scan>


4、使用Spring基于java的配置

4.1、创建基于Java的配置

用极少量的xml来启用java配置:

<?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http:..www.springframework.org/schema/context
        http:..www.springframework.org/schema/context/spring-context.xsd">
    
    <context:component-scan
        base-package="com.roger.spring.beans">
    </context:component-scan>
    
</beans>

    <context:component-scan>自动注册那些使用某种构造型(stereotype)注解所标注的Bean。

    同时,也会自动加载使用@Configuration注解所标注的类。

4.2、定义一个配置类

  • 在基于java的配置里使用@Configuration注解的java类,等价于xml配置中的<beans>元素。

  • @Configuration注解作为一个标识告知Spring:这个类将包含一个或多个Spring Bean的定义。

  • 这些Bean的定义是使用@Bean注解所标注的方法。

例如:

有一个Person基类,Teacher类继承Person类,以下,声明一个简单的id为roger的Teacher Bean。

import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringConfig {
    //Bean declaration methods go here
    
    //声明一个简单的Bean
    @Bean
    public Person roger() {
        return new Teacher();
    }
}

    @Bean告知Spring这个方法将返回一个对象,该对象应该被注册为Spring应用上下文中的一个Bean,方法名作为Bean的id。

4.3、使用Spring基于java的配置进行注入

例如:

注入一个引用

import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringConfig {
    //Bean declaration methods go here
    
    @Bean
    public Address address() {
        return new Address();
    }
    
    @Bean
    public Person roger() {
        return new Teacher(address());
    }
}

注意:在Spring的java配置中,通过声明方法引用一个Bean并不等同于调用该方法。通过@Bean注解标注address()方法,要在其他Bean的声明方法中引用这个方法时,Spring都会拦截方法的调用,并尝试在应用上下文中查找该Bean,而不是让方法创建一个新的实例。

你可能感兴趣的:(Spring(三)装配Bean:自动装配Bean)