深入理解Spring4框架(八)——基于注解的容器配置



基于注解的配置比XML更好吗?这得看情况,XML解耦了配置和原代码,而注解则精简了配置。

    注解的注入会在XML之前,因此后者配置将会覆盖前者。可以将注解作为独立的Bean定义进行注册,也可以使用以下方式模糊注册。

<?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>

    以上方式注册的post-processors(参考深入理解Spring4框架(七)——容器扩展点)包含AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor和RequiredAnnotationBeanPostProcessor。

    <context:annotation-config/>仅查找同一个应用上下文中所定义的Bean。也就是说,如果将<context:annotation-config/>放到一个DispatcherServlet对应的WebApplicationContext中,它仅会检测控制器中加了@Autowired注解的类。

1. @Required

    @Required注解应用于Bean属性的setter方法,如下:

public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // ...
}

    这个表明Bean的属性值必须在配置中指定,可以通过显示的在Bean定义中指定,也可以使用自动注入。若没有为这个属性指定值,那么容器会抛出一个异常。

2. @Autowired

    正如所料,可以在普通setter方法上使用@Autowired注解。

public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // ...
}

    可以将注解应用到任意名称或参数的方法上:

public class MovieRecommender {
    private MovieCatalog movieCatalog;
    private CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public void prepare(MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }
    // ...
}

    可以将注解应用到构造器和字段上:

public class MovieRecommender {
    @Autowired
    private MovieCatalog movieCatalog;
    private CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }
    // ...
}

    也可以把指定类型的所有Bean提供给一个数组类型的变量:

public class MovieRecommender {
    @Autowired
    private MovieCatalog[] movieCatalogs;
    // ...
}

    指定类型的集合也同理:

public class MovieRecommender {
    private Set<MovieCatalog> movieCatalogs;
    @Autowired
    public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }
    // ...
}

    默认情况下,一旦找不到对应的Bean,自动注入就会失败。若要改变默认的策略,可以如下修改注解:

public class SimpleMovieLister {
    private MovieFinder movieFinder;
    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // ...
}

3. 使用@Primary调整基于注解的自动注入

    因为根据类型的自动注入可能会出现多个符合条件的Bean,那么很有必要在选择的流程上拥有更多的控制权。一种解决方式就是使用Spring的@Primary注解。@Primary表明这个Bean在被注入时拥有更高的优先级,也就是说,在自动注入时若找到多个符合条件的Bean,那么被@Primary注解的Bean将会最终被注入。

    看如下示例,将firstMovieCatalog定义为主要的MovieCatalog:

@Configuration
public class MovieConfiguration {
    @Bean
    @Primary
    public MovieCatalog firstMovieCatalog() { ... }
    @Bean
    public MovieCatalog secondMovieCatalog() { ... }
    // ...
}

    那么,下面的MovieRecommender将会把firstMovieCatalog注入:

public class MovieRecommender {
    @Autowired
    private MovieCatalog movieCatalog;
    // ...
}

4. 使用@Qualifier调整基于注解的自动注入

    在基于类型的自动注入中,若出现了多个实例Bean,@Primary是一个高效的方式来决定注入哪个示例。若想在选择Bean的过程中拥有更多的控制,可以使用Spring的@Qualifier注解。

    可以在指定参数上使用@Qualifier,可以缩小类型匹配的范围,更容易为参数找到指定的Bean。最简单的情况如下:

public class MovieRecommender {
    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;
    // ...
}

    也可以在独立的构造参数或方法参数上使用@Qualifier注解:

public class MovieRecommender {
    private MovieCatalog movieCatalog;
    private CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public void prepare(@Qualifier("main")MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }
    // ...
}

    对应的Bean定义如下所示。标识值为“main”的Bean将会被标记为@Qualifier(“main”)的参数所注入:

<?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/>
    <bean class="example.SimpleMovieCatalog">
        <qualifier value="main"/>
    </bean>
    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/>
    </bean>
    <bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>

    默认情况下,标识值就是Bean的名称,因此可以直接定义Bean的id为“main”来代替内部的<qualifier>元素。

    @Qualifier也可以作用于集合上,比如Set<MovieCatalog>,所有符合条件的元素都将会被注入到集合中。这就意味着,@Qualifier不必只能唯一标识一个元素。

5. 使用泛型作为自动注入的标识

    除了@Qualifier注解以外,也可以使用Java泛型作为一种模糊的标记格式。比如,假设有如下配置:

@Configuration
public class MyConfiguration {
    @Bean
    public StringStore stringStore() {
        return new StringStore();
    }
    @Bean
    public IntegerStore integerStore() {
        return new IntegerStore();
    }
}

    假如以上Bean各自实现了一个泛型接口,即Store<String>和Store<Integer>,可以自动注入Store接口,泛型就会被作为标志使用了:

@Autowired
private Store<String> s1; // <String>标志,注入stringStore
@Autowired
private Store<Integer> s2; // <Integer>标志,注入integerStore

    需要注意的是,这里会查找实现了Store<String>接口的stringStore以及实现了Store<Integer>接口的integerStore。

    当自动注入列表、Map和数组时,泛型也会生效:

//注入所有实现了Store<Integer>接口的Bean,实现了Store<String>的Bean不会被注入
@Autowired
private List<Store<Integer>> s;

6. CustomAutowireConfigurer

    CustomAutowireConfigurer是个BeanFactoryPostProcessor,即使没有使用Spring的@Qualifier标志,也可以注册自定义的标志注解类型。

<bean id="customAutowireConfigurer"
        class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
    <property name="customQualifierTypes">
        <set>
            <value>example.CustomQualifier</value>
        </set>
    </property>
</bean>

7. @Resource

    Spring也支持使用JSR-250的@Resource注解注入,它可以作用于字段或Bean属性的setter方法上。

    @Resource有个name属性,默认情况下,Spring把name的值作为Bean的名称进行Bean注入。若name值缺省,则使用自动生成的name属性。跟@Autowired类似,当找到多个候选Bean时,@Resource查找一个主要的类型进行匹配。

8. @PostConstruct和@PreDestroy

    CommonAnnotationBeanPostProcessor不仅可以识别@Resource注解,也可以识别JSR-250生命周期注解,请看电影缓存的例子:

public class CachingMovieLister {
    @PostConstruct
    public void populateMovieCache() {
        //初始化之前存入电影
    }
    @PreDestroy
    public void clearMovieCache() {
        //销毁之前删除电影
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值