• 基于注解(Annotationbased)的配置


     

    Spring 2.0 对必须的属性引入了@Required注解。在 Spring 2.5中已经可以用注解的方式去驱动 Spring 的依赖注射了。更重要的是,@Autowired注解提供了与第 3.3.5 节 “自动装配(autowire)协作者”一节中描述的同样功能,并且提供了更细致的控制与更好的适应性。Spring 2.5 也支持 JSR-250 中的一些注解,例如@Resource@PostConstruct,以及@PreDestroy。当然,要使注解可用,您必须使用 Java 5 (Tiger)或更新的版本,以使得可以访问源代码层次的注解。这些注解可以被注册为独立 bean 的定义,但它们也可以被隐式地注册,通过基于 XML 的配置方式,如下例(请注意包含 'context' 命名空间):

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

    (隐式注册 post-processors 包括了 AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor,也包括了前面提到的 RequiredAnnotationBeanPostProcessor。)

    3.11.1. @Autowired

    @Autowired 注解可以用于“传统的”setter 方法,如下例:

    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;
        }
    
        // ...
    }

    @Autowired注解甚至可以用于构造器与字段:

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

    也可以一种提供来自ApplicationContext的特殊类型的所有 beans,注解字段或者方法,例如:

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

    这同样适用于集合类型:

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

    甚至是 Maps 也可以这样注解,只要这个 Map 的 key 类型为 String。这个 Map 的 values 应该是已知的类型,并且 keys 应该包含符合 bean 的命名:

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

    在缺省情况下,当出现0个候选的 beans时自动连接将失败;缺省行为把连接方法,构造器,字段假设为 required 的依赖。这样的行为如下所示:

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

    注意

    虽然当 一个类只有一个连接构造器时它将被标记为 required, 但是还是可以标记多个构造器的。在这种情况下,每一个构造器都有可能被认为是连接构造器, Spring 将会把依赖关系能够满足的构造器认为是greediest 的构造器。

    @Autowired也能用于总所周知的“可解决的依赖”:BeanFactory接口,ApplicationContext接口,ResourceLoader接口,ApplicationEventPublisher接口,还有MessageSource接口。这些接口(还有它们的扩展,例如ConfigurableApplicationContext或者ResourcePatternResolver)将可以自动解决依赖,没有任何特殊必须的其它步骤需要。

    public class MovieRecommender {
    
        @Autowired
        private ApplicationContext context;
    
        public MovieRecommender() {
        }
    
        // ...
    }

    3.11.2. 基于注解的自动连接微调

    因为通过类型的自动连接可能会有多个候选,因此经常需要在选择过程中加以控制。一种方法去完成这个控制就是使用@Qualifier注解。在最简单的情况下,您能够通过命名方式去实现这个自动连接:

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

    @Qualifier注解也能够被指定为构造器的参数或者方法的参数:

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

    您也可以创建您自定义的限定器注解。您只要在定义一个注解时提供@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;
        }
    
        // ...
    }

    下一步就是提供信息给候选的 bean 的定义。您能够添加<qualifier/>标签作为<bean/>标签的子元素,然后指定'type'还有'value'以匹配您的自定义限定器注解。类型必须匹配注解的全名,或者是一个不危险的、方便一点的名字,您也可以使用“短” 类名。参看下例:

    <?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-2.5.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.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>
    

    在下一节,题目是第 3.12 节 “对受管组件的Classpath扫描”,您将看到使用XML提供给限定器元数据且基于注解的可选解决方案。特别地,请参看:第 3.12.6 节 “用注解提供限定符元数据”

    在某些情况下,有足够充分的理由去使用不带值的注解。这使得注解可以提供更多解决不同类型依赖的能力。例如,在 Internet 连接不可用时,您可以提供一个离线的搜索目录。首先就要定义一个简单的注解:

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

    然后添加这个注解给字段作为自动连接:

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

    现在,这个 bean 的定影只组要一个限定器了:

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

    另外,也可以定制自己的限定器注解去使用命名的属性或者简单的'value'属性。如果自动连接时多个属性值被指定给了一个字段或者参数,那么一个 bean 的定义必须全部匹配这些属性的值。例如,考虑如下的注解定义:

    @Target({ElementType.FIELD, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface MovieQualifier {
    
        String genre();
        
        Format format();
    
    }

    在这种情况下,Format是一个枚举:

    public enum Format {
        
        VHS, DVD, BLURAY
    }

    这些字段将与自定义的限定器进行自动连接,包括了每个属性的值:'genre' 以及 'format'

    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;
       
        // ...
    }

    最终,这个 bean 的定义应该与限定器匹配的值。这个列子将说明bean 的属性可以用于替代<qualifier/>的子元素。那样的话,<qualifier/>以及它的属性将优先考虑,但是如果没有限定器的话(参看如下定义的后两个 bean ),自动连接机制将取消以<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-2.5.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    
        <context:annotation-config/>
    
        <bean class="example.SimpleMovieCatalog">
            <qualifier type="MovieQualifier">
                <attribute name="format" value="VHS"/>
                <attribute name="genre" value="Action"/>
            </qualifier>
            <!-- inject any dependencies required by this bean -->
        </bean>
    
        <bean class="example.SimpleMovieCatalog">
            <qualifier type="MovieQualifier">
                <attribute name="format" value="VHS"/>
                <attribute name="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>

    3.11.3. 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>

    请注意,AutowireCandidateResolver的实现将依赖于 Java 版本。如果在 Java 5 以下,限定器注解是不被支持的,因此自动连接后选将被'autowire-candidate'的值或者在<beans/>中元素'default-autowire-candidates'可用的模式所决定。如果运行在 Java 5 或者更新的版本上,@Qualifier注解或者任何自定义并在CustomAutowireConfigurer上注册过的注解都将正常工作。

    忽略 Java 版本,决定“主要”的后选(当多个 beans 都配置为自动连接后选时)都是一样的:在这些后选中只要一个 bean 的'primary'属性定义为'true'即可。

    3.11.4. @Resource

    Spring 也提供了使用 JSR-250 bean 属性支持的注射方式。这是一种在 Java EE 5 与 Java 6 中普遍使用的方式(例如,在 JSF 1.2 中映射 beans 或者 JAX-WS 2.0 端点),对于Spring 托管的对象 Spring 可以以这种方式支持映射。

    @Resource有一个‘name’属性,缺省时,Spring 将这个值解释为要注射的 bean 的名字。换句话说,如果遵循by-name的语法,如下例:

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

    如果没有显式地给出名字,缺省的名字将继承于字段名或者 setter 方法名:如果是字段名,它将简化或者等价于字段名;如果是 setter 方法名,它将等价于 bean 属性名。下面这个例子使用名字 "movieFinder" 注射到它的 setter 方法:

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

    注意

    注解提供的名字将被BeanFactory解析为 bean 名。请注意,这些名字也可能通过 JNDI 被解析(需要配置 Spring 的SimpleJndiBeanFactory)。不过,建议您依靠缺省行为与 Spring 的 JNDI 查找功能。

    @Autowired类似,@Resource可以回退为与标准 bean 类型匹配(例如,使用原始类型匹配取代特殊命名 bean)来解决著名的"resolvable dependencies":BeanFactory 接口,ApplicationContext 接口,ResourceLoader 接口,ApplicationEventPublisher 接口以及 MessageSource 接口。请注意:这只有适用于未指定命名的@Resource

    下面的例子有一个customerPreferenceDao字段,首先要查找一个名叫 “customerPreferenceDao” 的 bean,然后回退为一个原始类型以匹配类型CustomerPreferenceDao。"context" 字段将基于已知解决的依赖类型ApplicationContext而被注入。

    public class MovieRecommender {
    
        @Resource
        private CustomerPreferenceDao customerPreferenceDao;
    
        @Resource
        private ApplicationContext context;
    
        public MovieRecommender() {
        }
    
        // ...
    }

    3.11.5. @PostConstruct@PreDestroy

    CommonAnnotationBeanPostProcessor 不只是能识别@Resource注解,而且也能识别 JSR-250 lifecycle注解。在 Spring 2.5 中,这些注解的描述请参看initialization callbacksdestruction callbacks节。CommonAnnotationBeanPostProcessor已经在 Spring 的ApplicationContext中注册,当一个方法带有这些注解之一时,将被在其生命周期与 Spring 生命周期接口的方法或者显式声明回调方法同一刻上调用。下面的例子里,缓存将预置于初始化与销毁阶段。

    public class CachingMovieLister {
    
        @PostConstruct
        public void populateMovieCache() {
            // populates the movie cache upon initialization...
        }
        
        @PreDestroy
        public void clearMovieCache() {
            // clears the movie cache upon destruction...
        }
    }

    注意

    关于组合不同的生命周期机制,请查看第 3.5.1.4 节 “组合生命周期机制”

  • 相关阅读:
    Python 字典
    CentOS6.8部署MongoDB集群及支持auth认证
    Python 字符串
    Ubuntu下部署GitLab-——基于14.04系统
    Python 用户登录程序
    设计模式之美学习-快速改善代码质量(十三)
    SpringMvc源码阅读View之JstlView如何渲染视图(十)
    SpringMVC源码阅读ViewResolver如何处理ContentNegotiatingViewResolver(九)
    SpringMVC源码阅读RequestMappingHandlerAdapter如何处理Handle(八)
    SpringMVC源码阅读HandlerAdapter初始化-RequestMappingHandlerAdapter(七)
  • 原文地址:https://www.cnblogs.com/liaomin416100569/p/9332122.html
Copyright © 2020-2023  润新知