美文网首页Spring FrameWork Core Tech
The IoC Container 1.9.2 Using @A

The IoC Container 1.9.2 Using @A

作者: 小鲍比大爷 | 来源:发表于2019-02-18 22:51 被阅读0次

1.9. Annotation-based Container Configuration

Spring提供了基于注解的配置方式,可以用来替代xml的配置方式。基于注解的配置方式是配置在java代码中来生效。
于是,在Spring提供了注解方式后,引起了两种配置方式优劣的讨论。往简单了说,具体使用需要视情况而定。往复杂了说,各有优劣,通常由开发者决定到底哪种配置方式适合自己。基于注解的方式配置更简洁,而且在配置处有上下文,这样用户更容易理解。xml的自动装配方式优点是不跟代码耦合,只需要修改xml配置,不需要重新编译代码。一些开发者更喜欢注解方式是因为贴近代码,但是也有开发者更喜欢xml配置方式:他们认为注解的类已经不是POJO,而且注解方式还使得配置分散,难以管控。
不管怎样,Spring可以支持这两种配置方式,甚至支持两种方式混合配置。最后值得一提是:通过JavaConfig方式可以有效的将bean定义分离出来,减少与目标代码的耦合,支持注解配置方式做到非侵入式配置。

基于xml配置的优先级要高于基于注解的优先级:

Annotation injection is performed before XML injection. Thus, the XML configuration overrides the annotations for properties wired through both approaches.

The IoC Container 1.8讲述了BeanPostProcessor接口的作用,而Spring是通过实现一系列BeanPostProcessor支持了基于注解的配置方式:

(The implicitly registered post-processors include AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, PersistenceAnnotationBeanPostProcessor, and the aforementioned RequiredAnnotationBeanPostProcessor.)

我们可以通过在xml配置中定义这些bean来引入基于注解配置的功能,不过Spring提供给了我们简化的方式来引入该功能:

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

通过配置context:annotation-config,相当于引入了上述几个BeanPostProcessor的实现到Spring Container中。到这里我们可以深刻体会到,Spring的基础设施不仅可以供用户定义普通的bean,也可以供Spring社区的开发者定义服务于Spring Container的bean(BeanPostProcessor相当于作用于其他bean的bean),这些开放出的接口使得Spring的扩展能力相当强悍。
下面的配置相当重要,这个配置的是组件扫描路径,必须配置相应包名(要使用注解的类所在的包),基于注解的方法才能生效。如果有多个需要扫描的包,则可以用逗号空格等分隔符隔开。

<context:component-scan base-package="examples"/>

1.9.1. @Required

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Required
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

@Required注解在setter方法上,用来强制movieFinder的初始化。
Spring在现有版本已经将该注解标识为@Deprecated,不再推荐使用。Spring建议使用构造函数初始化的方式来替代setter方法初始化,而不是将相应setter方法标注为@Required。

1.9.2. Using @Autowired

JSR 300中的注解@Inject可以用来替代@Autowired:

JSR 330’s @Inject annotation can be used in place of Spring’s @Autowired annotation in the examples included in this section

@Autowired的作用在于可以实现自动装配,在初始化Spring Container的过程中将符合条件的类实例化,然后装配到相应的类中,实现对象的组装。

@Autowired用于构造函数:

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

从4.3版本开始,指定构造函数时,@Autowired已经不是必须添加的注解,Spring会在只有一个构造函数时自动处理,如果构造函数多于一个,那么需要指定其中一个:

As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with. However, if several constructors are available, at least one must be annotated to teach the container which one to use.

@Autowired用于setter方法:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

@Autowired还支持注解到拥有任意名称的方法:

public class MovieRecommender {

    private MovieCatalog movieCatalog;

    private CustomerPreferenceDao customerPreferenceDao;

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

    // ...
}

@Autowire混合使用:

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

@Autowired用于字段,类型为数组,用于自动装配数组:

public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;

    // ...
}

@Autowired用于setter方法,用于自动装配集合对象:

public class MovieRecommender {

    private Set<MovieCatalog> movieCatalogs;

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

    // ...
}

@Autowired用于装配map对象,key值为bean的name:

public class MovieRecommender {

    private Map<String, MovieCatalog> movieCatalogs;

    @Autowired
    public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
        this.movieCatalogs = movieCatalogs;
    }

    // ...
}

默认情况下,如果找不到相应的bean类型进行自动装配,会报错,可以通过将required设置为false,那么便不会强行要求必须装配该字段了:

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...
}

还有一种方式可以用来表示非强制注入的,就是java8的Optional(Optional的特点:non-required nature):

public class SimpleMovieLister {

    @Autowired
    public void setMovieFinder(Optional<MovieFinder> movieFinder) {
        ...
    }
}

Spring Framework 5.0提供的@Nullable注解,也可以用来表示非强制注入:

public class SimpleMovieLister {

    @Autowired
    public void setMovieFinder(@Nullable MovieFinder movieFinder) {
        ...
    }
}

@Autowired还可以用于装配Spring内置的接口,比如BeanFactory, ApplicationContext, Environment, ResourceLoader, ApplicationEventPublisher, and MessageSource。也可以装配这些接口的继承接口,比如ConfigurableApplicationContext或者ResourcePatternResolver。自动装配ApplicationContext的示例如下:

public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...
}

@Autowired, @Inject, @Resource和@Value注解是由BeanPostProcessor的实现处理的,所以自然不能将这些注解用于自定义的BeanPostProcessor或BeanFactoryPostProcessor上,如果要实现BeanPostProcessor或BeanFactoryPostProcessor的自动装配,可以显示使用xml方式或者@Bean注解的方式:

The @Autowired, @Inject, @Resource, and @Value annotations are handled by Spring BeanPostProcessor implementations. This means that you cannot apply these annotations within your own BeanPostProcessor or BeanFactoryPostProcessor types (if any). These types must be 'wired up' explicitly by using XML or a Spring @Bean method.

总结:本章主要讲述了如何使用@Autowired注解实现自动装配功能,@Autowired可以用于构造函数、字段、setter方法,甚至任意方法上,@Autowired可以用来注入多种类型的数据,甚至包括数组、集合等类型。

相关文章

网友评论

    本文标题:The IoC Container 1.9.2 Using @A

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