博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring 高级装配
阅读量:6396 次
发布时间:2019-06-23

本文共 9115 字,大约阅读时间需要 30 分钟。

hot3.png

环境与profile

配置profile bean

在java配置中,可以使用@ProFile注解制定某个Bean属于哪一个profile。例如:@Profile("dev")。

在xml中配置profile 通过<beans>元素的profile属性,在XML中配置profile bean 。

  profile的定义一定要在文档的最下边,否则会有异常。整个xml的结构大概是这样

3.1.2 激活profile

Spring在确定那个Profile处于激活状态时,依赖两个独立的属性:spring.profiles.active 和spring.profiles.default。如果设置了spring.profiles.active属性的话,那么他的值就会用来确定那个profile是激活的,但是如果没有设置 spring.profiles.active属性的话,就会查找 spring.profiles.default的值,如果spring.profiles.active 和 spring.profiles.default 均没有设置的话,那就没有激活的profile,只会创建那些没有定义在profile中的bean。 设置激活属性的方式:

  • 作为DispatcherServlet的初始化参数。
  • 作为web应用的上下问参数。
  • 作为JNDI条目。
  • 作为环境变量。
  • 作为JVM的系统属性。
  • 在集成测试类上,使用@ActiveProfiles注解设置。

比如我们在web.xml中可以声明代码如下

//为上下文设置默认的profile
spring.profile.default
dev
...
... //为Serlvet设置默认的profile
spring-profiles.default
dev
...

另外对于测试,spring为什么提供了一个简单的注解可以使用@ActiveProfiles,它可以指定运行测试的时候应该要激活那个profile。比如这里的测试类DevDataSourceTest

package profiles; import static org.junit.Assert.*; import java.sql.ResultSet;import java.sql.SQLException;import java.util.List; import javax.sql.DataSource; import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import org.springframework.test.context.ActiveProfiles;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.myapp.DataSourceConfig; public class DataSourceConfigTest {  @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=DataSourceConfig.class) @ActiveProfiles("dev") public static class DevDataSourceTest { @Autowired private DataSource dataSource;   @Test public void shouldBeEmbeddedDatasource() { assertNotNull(dataSource); JdbcTemplate jdbc = new JdbcTemplate(dataSource); List
results = jdbc.query("select id, name from Things", new RowMapper
() { @Override public String mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getLong("id") + ":" + rs.getString("name"); } }); assertEquals(1, results.size()); assertEquals("1:A", results.get(0)); } } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes=DataSourceConfig.class) @ActiveProfiles("prod") public static class ProductionDataSourceTest { @Autowired private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { // should be null, because there isn't a datasource configured in JNDI assertNull(dataSource); } } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:datasource-config.xml") @ActiveProfiles("dev") public static class DevDataSourceTest_XMLConfig { @Autowired private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { assertNotNull(dataSource); JdbcTemplate jdbc = new JdbcTemplate(dataSource); List
results = jdbc.query("select id, name from Things", new RowMapper
() { @Override public String mapRow(ResultSet rs, int rowNum) throws SQLException { return rs.getLong("id") + ":" + rs.getString("name"); } }); assertEquals(1, results.size()); assertEquals("1:A", results.get(0)); } } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:datasource-config.xml") @ActiveProfiles("prod") public static class ProductionDataSourceTest_XMLConfig { @Autowired(required=false) private DataSource dataSource; @Test public void shouldBeEmbeddedDatasource() { // should be null, because there isn't a datasource configured in JNDI assertNull(dataSource); } } }

1、ENV方式:

ConfigurableEnvironment.setActiveProfiles("test")

2、JVM参数方式:   tomcat 中 catalina.bat(.sh中不用“set”) 添加JAVA_OPS。通过设置active选择不同配置文件

set JAVA_OPTS="-Dspring.profiles.active=test"

  eclipse 中启动tomcat。项目右键 run as –> run configuration–>Arguments–> VM arguments中添加。local配置文件不必上传git追踪管理

-Dspring.profiles.active="local"

3、web.xml方式:

spring.profiles.active
production

4、标注方式(junit单元测试非常实用):

@ActiveProfiles({"unittest","productprofile"})

3.2 条件化的bean

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

import org.springframework.context.annotation.Bean;  import org.springframework.context.annotation.Conditional;  import org.springframework.context.annotation.Configuration;     @Configuration  public class MyConfiguration {       @Bean(name="emailerService")    @Conditional(WindowsCondition.class)    public EmailService windowsEmailerService(){        return new WindowsEmailService();    }       @Bean(name="emailerService")    @Conditional(LinuxCondition.class)    public EmailService linuxEmailerService(){      return new LinuxEmailService();    }  }

处理自动装配的歧义性

仅有一个bean匹配所需的结果时,自动装配才是有效的。如果不仅有一个bean能够匹配结果的话,这种歧义性会阻碍spring自动装配属性、构造器参数或方法参数。 当确实发生歧义性的时候,spring提供了多种可选方案来解决这样的问题:1.将可选bean中的某一个设为首选(Primary)的bean。或者使用限定符(qualifier)来帮助spring将可选bean的范围缩小到只有一个bean。

3.3.1 标识首选bean

通过@ Primary来表达最喜欢的方案。@primary能够与@component组合用在组建扫描的bean上。也可以与@Bean组合用在java配置的bean声明中。

@Primary  @Component  public class OperaSinger implements Singer{        @Override      public String sing(String lyrics) {          return "I am singing in Bocelli voice: "+lyrics;      }  }
@Primary  @Beanpublic class OperaSinger implements Singer{        @Override      public String sing(String lyrics) {          return "I am singing in Bocelli voice: "+lyrics;      }  }

3.3.2 限定自动装配的bean

@Qualifier 注解是使用限定符的主要方式,可以与@Autowired 和@Inject协同使用,在注入的时候制定想要注入进去的是那个bean。@qualifier注解所设置的参数就是想要注入的bean的id。

@Autowired @Qualifier("office") private Office office;

3.3.2 创建自定义的限定符

创建自己的限定符,所需要做的就是在bean声明上添加@Qualifier注解。

//@Component @Qualifier("code") private Office office;//显示定义bean,声明限定符@Bean@Qualifier("code") private Office office;

当使用自定义的@qualifier值时,最佳实践为bean选择特征或描述性的术语,而不是使用随意的名字

3.3.3 使用自定义的限定符注解

面向特性的限定符要比基于beanID的限定符更好一些。

3.4 bean的作用域

Spring上下文中所有bean都是作为单例(singleton)的形式创建的。注解:scope。作用域包括

  • 单例(singleton):在整个应用中,只创建bean的一个实例。
  • 原型(prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
  • 会话(Session):在web应用中,为每个回话创建一个bean实例。
  • 请求(Request):在web应用中,为每个请求创建一个bean实例。

3.4.1 使用会话和请求作用域

应用场景:购物车场景。

@Component  @Scope (      value=WebApplicationContext.SCOPE_SESSION,      proxyMode=ScopedProxyMode.INTERFACES)  public ShoppingCart cart() {...}

@Scope的ProxyMode属性,它被设置成了ScopedProxyMode.INTERFACES.这个属性解决了会话或请求作用域的bean注入到单例bean中所遇到的问题。

Spring引入了作用域代理的方法,来解决该问题。代理会暴露与ShoppingCart相同的方法,当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内的真正的ShoppingCart bean。(即作用域代理能够延迟注入请求和会话作用域的bean)

在XML中声明作用域代理

如果使用XML来声明会话或请求作用域的bean,除了需要使用<bean>元素的scope属性设置bean的作用域外,还要使用Spring aop命名空间的aop:scoped-proxy元素。

aop:scoped-proxy是与@Scope注解的proxyMode属性功能相同的SpringXML配置元素。它会告诉Spring为bean创建一个作用域代理。默认情况下,它会使用CGLib创建目标类的代理。(可以通过将proxy-target-class属性设置为false,进而要求生成基于接口的代理),例如

注:上述代码,声明作用域为会话的bean,同时指定代理模式为创建目标类的方式。

注:上述代码,声明作用域为会话的bean,同时指定代理模式为基于接口的方式。

另外,为了使用aop:scoped-proxy元素,必须在XML配置中声明Spring的aop命名空间:

...

3.5 运行时注入

运行时注入:是指将一个值注入到bean的属性或者构造器的参数中。为了实现这些功能,spring提供了两种在运行时求值的方式:

  • 属性占位符
  • Spring表达式语言(SPEl)

3.5.1 注入外部的值

处理外部值的最简单方法就是声明属性源并通过Spring的Environment来检索属性。
@Configuration  //声明属性源@PropertySource("classpath:/com/soundsystem/app.properties")  public class ExpressiveConfig {            @Autowired      Environment env;            @Bean      public BlankDisc disc() {          return new BlankDisc(               //检索属性值            env.getProperty("disc.title");              env.getProperty("disc.artist"));      }  }

上述代码,@PropertySource 引用了类路径中一个名为app.properties的文件。该文件内容如下:

disc.title=Sgt. Peppers Lonely Hearts Club Band  disc.artist=The Beatles

深入学习Spring的Environment

  • String getProperty(String key) // 返回String类型的值

  • String getProperty(String key, String defaultValue) // 指定默认值的版本(当指定的属性不存在时,会使用一个默认值)

  • T getProperty(String key, Class<T> type) // 返回指定类型的值

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

方法: containsProperty()方法:检查某个属性是否存在。 getPropertyAsClass()方法:将属性解析为类。例如:

Class
cdClass = env.getPropertyAsClass("disc.class", CompactDisc.class);

除了属性相关的功能外,Environment还提供了一些方法来检查哪些profile处于激活状态:

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

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

【】boolean acceptsProfiles(String... profiles) : 如果environmet支持给定profile的话,返回true;

(2)、解析属性占位符

在Spring装配中,占位符的形式为使用“${...}”包装的属性名称。

如果要在XML中解析构造参数,可以如下所示:

如果是依赖组件扫描和自动装配来创建和初始化组件的话,可以使用@Value注解,例如:在BlankDisc类中,可以如下初始化:

public BlankDisc(      @Value("${disc.title}") String title,      @Value("${disc.artist}")  String artist) {      this.title = title;      this.artist = artist;  }

为了使用占位符,必须配置一个PropertyPlaceholderConfigurer bean 或PropertySourcesPlaceholderConfigurer bean。(从Spring 3.1开始,推荐使用PropertySourcesPlaceholderConfigurer, 因为它能够基于Spring Environment及其属性源来解析占位符)。

转载于:https://my.oschina.net/u/3421984/blog/1606950

你可能感兴趣的文章
2014电子商务安全技术峰会(含全议题下载)
查看>>
东大OJ-5到100000000之间的回文质数
查看>>
linux C 快速排序法
查看>>
模仿与创新
查看>>
Python用subprocess的Popen来调用系统命令
查看>>
Java NIO与IO的差别和比較
查看>>
.NET源代码的内部排序实现
查看>>
解决Strict Standards: Only variables should be passed by reference
查看>>
解决JBoss只能通过localhost(127.0.0.1)而不能通过IP访问
查看>>
MS SQL处理双引号(DoubleQuote)函数
查看>>
[智能架构系列]什么是Buddy智能开发框架
查看>>
三十一、关于android camera setParameters出错
查看>>
【收藏】QCIF、 CIF、2CIF、DCIF、D1(4CIF)格式介绍
查看>>
hdu 3836 Equivalent Sets (tarjan缩点)
查看>>
一些iOS高效开源类库(转)
查看>>
JAVA编程心得-JAVA实现CRC-CCITT(XMODEM)算法
查看>>
C# DES加密
查看>>
浅谈Oracle分区表之范围分区
查看>>
IBM Tivoli NetView网管软件实战
查看>>
IPSec逻辑体系架构
查看>>