码农小汪-spring框架学习之6-spring基于注解的容器配置 @Qualifier @Autowired @Resouce @PostConstruct @PreDestroy

注解这个东西真的很方便,我们使用起来也是特别的简单,和XML配合使用就是更是非常的舒服。就是具体的逻辑引用看起来不是特别的明显。但是使用注解已经是一个框架发展的趋势吧。大家都在往这个方面上去靠。没得办法的!必须的学会。你说哈。如果以前的老的项目我们也是必须的懂XML,开发新的项目还是得学着去使用这些东西。

注解比 XML 好么,简单的说得看情况。详细的说,各有优缺点。因为定义的方式,注解在声明处提供了大量的上下文信息,所以注解配置要更简洁。然而,XML 擅长在不接触源码或者无需反编译的情况下组装组件。

注解注入在 XML 注入之前执行,因此同时使用这两种方式注入时, XML
配置会覆盖注解配置

同样的 Spring 风格,就像特别的 bean 定义那样注册他们,但是也能像下面这样隐式注册(注意包含 context namespace 上下文命名空间)

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

(隐式注册后处理器包括AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor, 以及前面提到的RequiredAnnotationBeanPostProcessor)。

Note:
< context:annotation-config/> only looks for annotations on beans in the same application context in which it is defined. This means that, if you put < context:annotation-config/> in a WebApplicationContext for a DispatcherServlet, it only checks for @Autowired beans in your controllers, and not your services.
仅会检索它所在的应用 context 上下文中bean 上的注解。并不会检查 service。

@Required 强制要求注入,没有注入会出现异常

public class SimpleMovieLister {

    private MovieFinder movieFinder;

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

    // ...

}

这个注解意思是受到影响的 bean 属性在配置时必须赋值,在 bean 定义中明确定其属性值或者通过自动注入。若该属性未指定值,容器会抛异常。这导致及时明确的失败,避免 NullPointerExceptions 或者晚一些时候才发现。

@ autowired 自动装载这个属性我们之前好像说过的,也是可以用到很多的地方的

  • you can apply the @Autowired annotation to “traditional” setter methods:
  • ou can also apply the annotation to methods with arbitrary(adj.乱;随意的,任性的,随心所欲的;主观的,武断的;霸道的,专制的,专横的,独断独行的;) names and/or multiple arguments: 意思就是参数有多个的情况!
  • You can apply @Autowired to constructors and fields: 也可以放在我们的构造函数中
  • adding the annotation to a field or method that expects an array of that type:
这个是对于一个数组属性
public class MovieRecommender {

    @Autowired
    private MovieCatalog[] movieCatalogs;

    // ...

}

也可以是一个集合
public class MovieRecommender {

    private Set<MovieCatalog> movieCatalogs;

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

    // ...

}

Tip:Your beans can implement the org.springframework.core.Ordered interface or use the the @Ordered annotation if you want items in the array or list to be sorted into a specific order.如果你想指定数组元素或者集合元素的次序,那么可以通过以下方式:bean 实现 org.springframework.core.Ordered 接口,或者使用 @Order 注解

@order,使用注解方式使bean的加载顺序得到控制
@order(value=1)
@order(value=2)
值越小,越先被加载。

构造函数有多个的时候,我们选择其中的一个区定义为必须,其他的不说强制的
每个类中只有一个被注解的构造函数能被标记为required,但是其他构造函数也能被注解。这种情况下,每个构造函数都会在候
选者之间被考虑, Spring 使用贪婪模式选取构造函数,也就是拥有最多数量构造参数的那一个。 推荐使用@Autowired 的 required 属性覆盖@Required注解。 required 属性表名那个属性对于自动注入可能不需要,如果不能被装配则属性将会被忽略。 Required,另一方面,更加强调的是,强制执行设置属性,可以通过容器提供的任何手段。

可以使用@Autowired 注入常见的 Spring API 的依赖

解耦哦~
BeanFactory, ApplicationContext ,Environment ,ResourceLoader ,ApplicationEventPublisher, MessageSource。这些接口和他们的子类及实现类都可以比如,ConfigurableApplicationContext,ResourcePatternResolver 都可以自动解析,无需
特别设置。
例子如下:

public class MovieRecommender {

    @Autowired
    private ApplicationContext context;

    public MovieRecommender() {
    }

    // ...

}

Note

这个很重要啊,我们的这些注解都是后处理器,就像Struct2中的拦截器类似的一样,我们不能使用他们注解在后处理器上
@Autowired, @Inject, @Resource, and @Value annotations are handled by a Spring BeanPostProcessor (不能处理Spring的后处理器)implementations which in turn means that you cannot apply these annotations within your own BeanPostProcessor or BeanFactoryPostProcessor types (if any). These types must be wired up explicitly via XML or using a Spring @Bean method.你只能使用XML和@Bean这种机制去处理啦!

使用限定符,因为我们面向接口编程,可能会出现多个何时的对象,自动注解就会面临选择的余地,我们去选择什么作为我们的注入着呢?这个很重要哦!限定一下~ 比如你说我是贵州人 贵州有很多地方比如遵义啊,凤岗啊 就是在一个大的集合下进行筛选!

qualifiers(n.合格者,已取得资格的人( qualifier的名词复数 );修饰语;)

public class MovieRecommender {

    @Autowired
    @Qualifier("main") 必须是为main的那种筛选
    private MovieCatalog movieCatalog;

    // ...

}

@Qualifier 注解也可以在构造参数或者方法参数上使用: 非常见的

public class MovieRecommender {

    private MovieCatalog movieCatalog;

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

    // ...

}

下面看看相应的 bean 定义, Qualifier(“main”)的 bean 是如何定义的,也就是如何制定 bean 的 Qualifier:

<?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"/>//因为这个仅仅是一个限定,并不需要唯一的标识符

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier value="action"/>

        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

bean 的 name 会作为备用 qualifier 值。因此你可以定义 bean 的 id 为 main 替代内嵌的 qualifier 元素,这将同样会匹配上。晓得什么意思?如果我没有定义< qualifier value=”main”/> 这个属性,让id=main也是可以匹配上的!但是@Autowired 是基于类型驱动注入,qualifiers 只是可选项。这就意味着 qualifier 值,甚至是 bean 的 name 作为备选项,只是为了缩小类型匹
配的范围;他们并不能作为引用的 bean 的唯一标示符。好的 qualifier 值是main,EMEA,persistent,能表达具体的组件的特性,这些 qualifier 独立于 bean 的id。

这种定义方式好高级

限定符 Qualifiers 也能应用于集合,就像上面讨论的那样,举个栗子,设置Set< MovieCtalog>。这个场景中,根据声明的限定符 qualifiers 所匹配的 bean 都会被注入到集合内。这意味着限定符 qualifiers 并不是唯一的;它们更像是简单的分类。比如,定义多个 beanMovieCatalog,使用相同的限定符 qulifier 值action;这些 bean 都将被注入到带有@Qualifier(“action”)注解的
Set< MovieCatalog>中。集合可以哦,这种类型的东西!

若要通过 name 名字来驱动注解注入,唯一的标识一个Bean

若要通过 name 名字来驱动注解注入,首先不能使用@Autowired,甚至不能使用@Qualifier 来表示引用 bean。而是通过 Resource 注解,该注解能在语法上标识出目标组件的唯一标识,匹配时将会忽略声明 bean 的类型。@Autowired 应用于域 field,构造函数,和多参数方法,允许在参数上使用 qualifier 限定符注解缩小取值范围。作为对比, @Resouce 仅支持域 field 和 bean 属性的 setter 方法,该方法只能有一个参数。因此,如果你注入的目标是构造函数或者是多参数方法,你得使用 qualifiers 限定符。

自定义自己的@Qualifier 注解而已,会玩的! 可以去看我之前写过的

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Genre {

    String value();
}

我们就可以使用啦

public class MovieRecommender {

    @Autowired
    @Genre("Action")
    private MovieCatalog actionCatalog;
    private MovieCatalog comedyCatalog;

    @Autowired
    public void setComedyCatalog(@Genre("Comedy") MovieCatalog comedyCatalog) {
        this.comedyCatalog = comedyCatalog;
    }

    // ...

}

在XML中还是需要定义一下的塞,不然不好说了!
接下来,提供候选者 bean 定义的信息。可以在< bean/>标签上增加< qualifier/>
标签子元素,然后指定 type 类型和 value 值来匹配自定义的 qualifier 注解。type 是自定义注解的权限定类名(包路径+类名)。如果没有重名的注解,那么可以使用类名(不含包路径)

<?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 type="Genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        _<qualifier type="example.Genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean id="movieRecommender" class="example.MovieRecommender"/>

</beans>

这种单一的,并不能满足我们的要求!

比如有些时候,可能有这样的需求。没得网络的时候检索。有网络的时候检索。或许我们对应两个不同的实现类。这个时候我们
也可以为自定义限定名 qualifier 注解增加属性,用于替代简单的 value 属性。如果有多个属性值在自动装配的域 field 或者是参数上指定, bean 的定义必须全部匹配这些属性值才能作为自动装配的候选者

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface MovieQualifier {

    String genre();

    Format format();

}

public enum Format {
    VHS, DVD, BLURAY
}

我们类中怎么去选择呢?

public class MovieRecommender {

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Action")
    private MovieCatalog actionVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.VHS, genre="Comedy")
    private MovieCatalog comedyVhsCatalog;

    @Autowired
    @MovieQualifier(format=Format.DVD, genre="Action")
    private MovieCatalog actionDvdCatalog;

    @Autowired
    @MovieQualifier(format=Format.BLURAY, genre="Comedy")
    private MovieCatalog comedyBluRayCatalog;

    // ...

}

如果可以, < qualifier/>及其属性优先生效,但是若没有 qualifier 出现,自动装配机制会使用< meta/>标签的值,都是可以完成这样的工作的!

<?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 type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Action"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <qualifier type="MovieQualifier">
            <attribute key="format" value="VHS"/>
            <attribute key="genre" value="Comedy"/>
        </qualifier>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="DVD"/>
        <meta key="genre" value="Action"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

    <bean class="example.SimpleMovieCatalog">
        <meta key="format" value="BLURAY"/>
        <meta key="genre" value="Comedy"/>
        <!-- inject any dependencies required by this bean -->
    </bean>

</beans>

@Resouce

@Resource 使用 name 属性, Spring 默认解释其 value 值作为注入 bean 的名字,没有也会自动的注入的

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder")
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}

@Resource 没有明确指定 name 时,和@Autowired 相似

@PostConstruct and @PreDestroy

The CommonAnnotationBeanPostProcessor (这个后处理器是处理我们的很多的注解的,有七百多行的解析注解)not only recognizes the @Resource annotation but also the JSR-250 lifecycle annotations. Introduced in Spring 2.5, the support for these annotations offers yet another alternative to those described in initialization callbacks and destruction callbacks. Provided that the CommonAnnotationBeanPostProcessor is registered within the Spring ApplicationContext, a method carrying one of these annotations is invoked at the same point in the lifecycle as the corresponding Spring lifecycle interface method or explicitly declared callback method. In the example below, the cache will be pre-populated upon initialization and cleared upon destruction.CommonAnnotationBeanPostProcessor 提供了这些注解的支持,它是Spring ApplicationContext 注册,它会在相应的 Spring bean 生命周期调用相应的方法,就像是 Spring 生命周期接口方法,或者是明确声明的回调函数。

public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }

    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }

}

你可能感兴趣的:(注解,spring)