美文网首页SSM+shiro等Java专题程序员
《Spring实战》学习笔记-第三章:最小化SpringXML配

《Spring实战》学习笔记-第三章:最小化SpringXML配

作者: hoxis | 来源:发表于2016-01-12 20:03 被阅读651次

    Spring提供了几种技巧,可以减少XML的配置数量:

    • 自动装配(autowiring):可以减少<property><constructor-arg>元素,让Spring自动识别如何装配Bean的依赖关系;
    • 自动检测(autodiscovery):Spring能够自动识别哪些类需要被装配成Spring Bean,从而减少对<bean>的使用。

    自动装配Bean属性

    4种自动装配

    • byName:把与Bean属性具有相同名字(或id)的其他Bean自动装配到Bean的对应属性中;
    • byType:把与Bean属性具有相同类型的其他Bean自动装配到Bean的对应属性中;
    • constructor:把与Bean的构造函数的入参具有相同类型的其他Bean自动装配到Bean的构造函数对应的入参中;
    • autodetect:先尝试使用constructor,失败后再使用byType。

    byName

    为属性自动装配id与该属性的名字相同的Bean。使用方法:

    <bean id="kenny" class="com.springinaction.springidol.Instrumentalist" autowire="byName">
        <property name="song" value="Happy" />
    </bean>
    

    通过配置Bean Kenny的autowire="byName"属性,Spring就可以利用此信息自动装配Kenny的instrument属性了。

    缺点:需要假设Bean的名字(如instrument)与其他Bean的属性的名字一样,若其他多个Bean的属性都是instrument,那么让他们将使用同一个instrument。

    byType

    当Spring根据类型匹配到多个Bean时,会抛出异常,形如:
    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'kenny' defined in class path resource [spring-idol.xml]: Unsatisfied dependency expressed through bean property 'instrument': : No qualifying bean of type [com.springinaction.springidol.Instrument] is defined: expected single matching bean but found 2: saxphone,guitar;

    为了避免这种异常(expected single matching bean but found 2)的出现,Spring提供了两种方案:可以自动装配标识一个首选Bean,或者可以取消某个Bean的自动装配的候选资格。

    标识首选Bean:primary="true"

    可以使用primary属性将Bean设置为首选Bean,那么它将会得到优选被选择权:

    <bean id="saxphone" class="com.springinaction.springidol.Saxophone" />
    <bean id="guitar" class="com.springinaction.springidol.Guitar" primary="true"/>
    
    <bean id="kenny" class="com.springinaction.springidol.Instrumentalist"
        autowire="byType">
        <property name="song" value="Happy" />
    </bean>
    

    有两个Bean类型满足kenny的instrument属性,但是guitar设置了primary="true",因此会注入guitar。

    排除其他Bean: autowire-candidate="false"

    <bean id="saxphone" class="com.springinaction.springidol.Saxophone" autowire-candidate="false"/>
    <bean id="guitar" class="com.springinaction.springidol.Guitar"/>
    <bean id="kenny" class="com.springinaction.springidol.Instrumentalist"
        autowire="byType">
        <property name="song" value="Happy" />
    </bean>
    

    通过排除其他Bean的候选资格来达到和上面设置primary同样的效果。

    constructor

    当有多个Bean匹配某个构造函数的入参时,Spring同样会抛出异常。

    默认自动装配方式

    可以在根元素<beans>上添加default-autowire属性来设置该配置文件中的<bean>的自动装配方式。

    混用自动装配和显示装配

    显示装配会覆盖掉自动装配

    <bean id="saxphone" class="com.springinaction.springidol.Saxophone" autowire-candidate="false"/>
    <bean id="guitar" class="com.springinaction.springidol.Guitar"/>
    <bean id="kenny" class="com.springinaction.springidol.Instrumentalist"
        autowire="byType">
        <property name="song" value="Happy" />
        <property name="instrument" ref="saxphone"></property>
    </bean>
    

    虽然取消了saxphone的候选资格,但最终仍是saxphone注入到了kenny的属性中。

    注意
    当使用constructor自动装配时,就不能混合使用constructor自动装配和<constructor-arg>标签了。

    使用注解装配

    启用注解装配:<context:annotation-config />

    • Spring自带的@Autowired注解
    • JSR-330的@Inject注解
    • JSR-250的@Resource注解

    @Autowired

    使用方法:

    // 1、可以标注setter
    @Autowired
    public void setInstrument(Instrument instrument) {
    this.instrument = instrument;
    }
    
    // 2、标注其他方法
    @Autowired
    public void heresYourInstrument(Instrument instrument) {
    this.instrument = instrument;
    }
    
    // 3、标注构造器
    @Autowired
    public Instrumentalist(Instrument instrument) {
    this.instrument = instrument;
    }
    
    // 4、直接标注属性
    @Autowired
    private Instrument instrument;
    
    

    使用@Autowired进行自动装配时,在遇到多个匹配的Bean或者没有匹配的Bean也会出现问题。

    可选的自动装配

    通过设置@Autowired的required属性为false来配置可选。

    @Autowired(required=false)
    private Instrument instrument;
    

    这时,若没有找到匹配到的instrument Bean,应用也不会出现异常,instrument会被设置为null。

    注意
    当使用构造器装配时,只有一个构造器可以将@Autowired的required属性设置为true,其他使用@Autowired注解的required属性必须设置为false。此外,当使用@Autowired标注多个构造器时,Spring会从所有满足装配条件的构造器中选择入参最多的那个。

    限制歧义性的依赖

    当有多个Bean满足装配条件时,可以配合使用@Qualifier注解。

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

    @Qualifier注解缩小了自动装配候选Bean的范围。

    @Inject

    和@Autowired一样,@Inject可以装配 属性、方法和构造器;但是@Inject没有required属性,因此@Inject注解所依赖的bean是必须存在的,如果不存在就会抛出异常。

    使用@Inject注入一个Provider,从而可以实现Bean引用的延迟注入以及注入多个Bean实例的功能。

    private Set<Knife> knives;
    
    @Inject
    public KnifeJuggler(Provider<Knife> knifeProvider) {
        knives = new HashSet<Knife>();
        for (int i = 0; i < 5; i++) {
            knives.add(knifeProvider.get());
        }
    }
    

    KnifeJuggler类需要注入多个Knife实例,假设Knife Bean的作用域是prototype的,那么KnifeJuggler将获得一个Provider<Knife>,这时只有provider被注入;在调用provider的get()方法之前,实际的Knife对象没有被注入。

    限定@Inject所注入的属性:@Named

    @Inject
    @Named("guitar")
    private Instrument instrument;
    

    在注解中使用表达式:@Value

    可以使用@Value装配简单值:String类型和基本类型,如:

    @Value("Happy")
    private String song;
    

    @Value可以配合SpEL使用:

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

    自动检测Bean:<context:component-scan>

    <context:annotation-config> 可以减少<property>和<constructor-arg> 的使用,但仍需配置<bean>。
    使用<context:component-scan> 除了可以完成上述工作,还可以自动检测Bean和定义Bean,它会扫描指定的包及其所有子包,并查找出能够自动注册为Spring Bean的类,base-package标识了所要扫描的包:
    <context:component-scan base-package="com.springinaction.springidol"/>

    标注Bean

    • @Component:通用的构造型注解,标识该类为Spring组件
    • @Controller:标识该类为Spring MVC controller
    • @Repository:标识为数据仓库
    • @Service:标识为服务
    • @Component:标注为自定义注解。
    package com.springinaction.springidol;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Guitar implements Instrument {
        public void play() {
            System.out.println("Strum strum strum");
        }
    }
    

    Spring扫描com.springinaction.springidol包时,会发现使用@Component注解所标注的Guitar,会自动将它注册为Spring Bean,其id会是guitar。

    定义组件扫描策略

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

    以下配置实现了:自动注册所有实现了Instrument接口的类,并且排除使用自定义@SkipIt注解的类。

    <context:component-scan base-package="com.springinaction.springidol">
        <context:include-filter type="assignable"
            expression="com.springinaction.springidol.Instrument" />
        <context:exclude-filter type="annotation"
            expression="com.springinaction.springidol.SkipIt" />
    </context:component-scan>
    

    如果觉得有用,欢迎关注我的微信,有问题可以直接交流:

    你的关注是对我最大的鼓励!你的关注是对我最大的鼓励!

    相关文章

      网友评论

      本文标题:《Spring实战》学习笔记-第三章:最小化SpringXML配

      本文链接:https://www.haomeiwen.com/subject/wsdfkttx.html