spring—高级装配

1. 配置profile Bean

  在3.1版本中,Spring引入了bean frofile的功能。要使用profile,你首先要将所有不同的bean定义整理到一个或多个profile之中,在将应用部署到每个环境时,要确保对应的profile处于激活(active)状态。

  @profile(“dev”)

  @profile注解应用在类级别上。他会告诉Spring这个配置类中的bean只有在dev profile激活时才会创建。如果dev profile没有激活的话,那么带有@Bean注解的方法都会被忽略掉。

  我们也可以通过<beans>元素的profile属性,在XML中配置profile bean。

  当你有多个profile bean时,在运行期间只会创建一个bean,这取决于激活状态的是哪个profile。

  Spring在确定哪个profile处于激活状态是,需要依赖两个独立的属性:spring.profiles.active和spring.profile.default。他会先查找有没有active设置如果没有再去查找default设置。如果都没有设置那就不会激活profile中的bean。

  有多种方式来设置这两个属性:

  1. 作为DispatchServlet的初始化参数;

  2. 作为Web应用的上下文参数;

  3. 作为JNDI条目;

  4. 作为环境变量;

  5. 作为JVM的系统属性;

  6. 在集成测试类上,使用@ActiveProfiles注解设置。

 

2. 条件化的bean

  假设你希望一个或多个bean只有在应用的类路径下包含特定的库时才创建。或者我们希望某个bean只要当另外某个特定的bean也声明了之后才会创建。我们还可能要求只有某个特定的环境变量设置之后,才会创建某个bean。

  在Spring 4引入了一个新的@Conditional注解,他可以用到带有@Bean注解的方法上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean就会被忽略。

 

3. 处理自动装配的歧义性

  在Spring配置中,仅有一个bean匹配所需的结果时,自动装配才是最有效的。如果不仅有一个bean能够匹配结果的话,这种歧义性会阻碍Spring自动装配属性、构造器参数或方法参数。

  1. 标示首选的bean:@Primary

  2. 限定自动转配的bean

    设置首选bean的局限性在于@primary无法将可选方案的范围限定到唯一一个无歧义性的选项中。它只能表示一个优先的可选方案。当首选bean的数量超过一个时,我们并没有其他的方法进一步缩小可选范围。

    @Qualifier注解是使用限定符的主要方式。他可以与@Autowired和Inject协同使用,在注入的时候指定想要注入进去的是哪个bean。它的限定符为bean ID。

     创建自定义的限定符:在bean声明上添加@Qualifier注解。例如@Qualifier(“cold”)

     使用自定义的限定符注解:编写代码使用@Qualifier注解来编写特定的自定义注解。

 

4. bean的作用域

  在默认情况下,Spring应用上下文中所有bean都是作为以单例(singleton)的形式创建的。也就是说,不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。

  有时候,可能会发现,你所使用的类是异变的(mutable),他们会保持一些状态,因此重用是不安全的。在这种情况下,将class声明为单例的bean就不是什么好主意了,因为对象会被污染,稍后重用的时候就会出现意向不到的效果。

Spring定义了多种作用域,可以基于这些作用域创建bean,包括:

  单例(Singleton):在整个应用中,之创建bean的一个实例。

  原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。

  会话(Session):在Web应用中,为每个会话创建一个bean实例。

  请求(Rquest):在Web应用中,为每个请求创建一个bean实例。

单例是默认作用域,但是正如之前所述,对于易变的类型,这并不合适。如果选择其他作用域,要使用@Scope注解,它可以与@Component或@Bean一起使用。

原型

  例如,如果你使用组件扫描来发现和声明bean,那么你可以在bean的类上使用@Scope注解,将其声明为原型bean:

  @Component

  @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

  你这里也可以使用@Scope(“prototype”),但是使用SCOPE_PROTOTYPE常量更加安全并且不易出错。

  也可以使用XML来配置bean:<bean id="xxx" class="xxx.xxx.xxx" scope="prototype">

使用会话和请求作用域

  使用@Scope注解:

  @Component

  @Scope(value=WebApplicationContext.SCOPE_SESSION,

       proxyMode=ScopedProxyMode.INTERFACES)

  proxyMode属性被设置为ScopedProxyMode.INTERFACES。这个属性解决了将会话或请求作用域的bean注入到单例bean中所遇到的问题。

  ScopedProxyMode.INTERFACES这表明这个代理要实现的接口,并将调用委托给实现bean。

  XML中声明作用域代理:

  <bean id="xxx"

      class="xxx.xx.xx"

      scope="session">

   <aop:scoped-proxy />

  </bean>

  <aop:scoped-proxy />是与@Scope注解的proxyMode属性功能相同的Spring XML配置元素。默认情况下,它会使用GGLib创建目标类的代理。但是我们可以将proxy-target-class属性设置为false,进而要求它生成基于接口的代理。

  <bean id="xxx"

      class="xxx.xx.xx"

      scope="session">

   <aop:scoped-proxy proxy-target-class=“false” />

  </bean>

 

5. 运行时值注入

  有时候我们希望避免硬编码值,而是想让这些值在运行时再确定。为了实现这些功能,Spring提供了两种在运行时求值得方式:

  属性占位符(Property placeholder)

  Spring 表达式语言(SpEL)

  1. 注入外部的值

  处理外部值的最简单的方式就是声明属性源并通过Spring的Environment来检索属性

  Spring的Environment有四种获取属性值的方法全部都是getProperty()方法重载的变种形式:

    String getProperty(String key)

    String getProperty(String key , String defaultValue)  //defaultValue表示指定属性不存在时使用默认属性值

    T getProperty(String key,Class<T> type)

    T getProperty(String key,Class<T> type,T defaultValue)

    getRequiredProperty(“xxx”)方法表示如果xxx属性没有定义的话,将会抛出IllegalStateException异常。

    containsProperty(“xxx”)方法表示检查xxx属性是否存在。

    如果想将属性解析为类的话,可以使用getPropertyAsClass()方法。

  Environment还提供了一些方法来检查哪些profile处于激活状态:

    String[] getActiveProfiles():返回激活profile名称的数组

    String[] getDefaultProfiles():返回默认profile名称的数组

    boolean acceptsProfiles(String... profiles):如果Environment支持给定profile的话,就返回true

解析属性占位符

  Spring一直支持将属性定义到外部的属性文件中,并使用占位符值将其插入到Spring bean中。在Spring装配中,占位符的形式为使用“${...}”包装的属性名称。

2.使用Spring表达式语言进行装配

  Spring3.1引入了Spring表达式语言(Spring Expression Language,SpEL),它能够以一种强大和简洁的方式将值装配到bean属性和构造器参数中,在这个过程中所使用的的表达式会在运行时计算得到值。

  SpEL拥有很多特性:

  1. 使用bean的ID来引用bean

  2. 调用方法和访问对象的属性

  3. 对值进行算术、关系和逻辑运算

  4. 正则表达式匹配

  5. 集合操作

  SpEL的表达式要放到“#{...}”之中

posted @ 2017-05-05 17:24  wenxudong  阅读(778)  评论(0编辑  收藏  举报