在java配置中,能够使用@ProFile注解制定某个Bean属于哪个profile。例如:@Profile("dev")。java
在xml中配置profile 经过<beans>元素的profile属性,在XML中配置profile bean 。linux
<!-- 开发环境配置文件 --> <beans profile="test"> <context:property-placeholder location="/WEB-INF/test-orm.properties" /> </beans> <!-- 本地环境配置文件 --> <beans profile="local"> <context:property-placeholder location="/WEB-INF/local-orm.properties" /> </beans>
profile的定义必定要在文档的最下边,不然会有异常。整个xml的结构大概是这样git
<beans xmlns="..." ...> <bean id="dataSource" ... /> <bean ... /> <beans profile="..."> <bean ...> </beans> </beans>
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。 设置激活属性的方式:web
好比咱们在web.xml中能够声明代码以下spring
<?xml version="1.0" encoding="UTF-8"?> <web -app version="2.5" ...> //为上下文设置默认的profile <context-param> <param-name>spring.profile.default</param-name> <param-value>dev</param-value> </context-param> ... <servlet> ... //为Serlvet设置默认的profile <init-param> <param-name>spring-profiles.default</param-name> <param-value>dev</param-value> </init-prama> ... <web-app>
另外对于测试,spring为何提供了一个简单的注解能够使用@ActiveProfiles,它能够指定运行测试的时候应该要激活那个profile。好比这里的测试类DevDataSourceTestsql
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<String> results = jdbc.query("select id, name from Things", new RowMapper<String>() { @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<String> results = jdbc.query("select id, name from Things", new RowMapper<String>() { @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); } } }
一、ENV方式:windows
ConfigurableEnvironment.setActiveProfiles("test")
二、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追踪管理tomcat
-Dspring.profiles.active="local"
三、web.xml方式:session
<init-param> <param-name>spring.profiles.active</param-name> <param-value>production</param-value> </init-param>
四、标注方式(junit单元测试很是实用):
@ActiveProfiles({"unittest","productprofile"})
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。
经过@ 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 @Bean public class OperaSinger implements Singer{ @Override public String sing(String lyrics) { return "I am singing in Bocelli voice: "+lyrics; } }
<bean id ="iceCream" class = "com.dess.IceCream" primary = "true">
@Qualifier 注解是使用限定符的主要方式,能够与@Autowired 和@Inject协同使用,在注入的时候制定想要注入进去的是那个bean。@qualifier注解所设置的参数就是想要注入的bean的id。
@Autowired @Qualifier("office") private Office office;
建立本身的限定符,所须要作的就是在bean声明上添加@Qualifier注解。
// @Component @Qualifier("code") private Office office; //显示定义bean,声明限定符 @Bean @Qualifier("code") private Office office;
当使用自定义的@qualifier值时,最佳实践为bean选择特征或描述性的术语,而不是使用随意的名字
面向特性的限定符要比基于beanID的限定符更好一些。
Spring上下文中全部bean都是做为单例(singleton)的形式建立的。注解:scope。做用域包括
应用场景:购物车场景。
@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来声明会话或请求做用域的bean,除了须要使用<bean>元素的scope属性设置bean的做用域外,还要使用Spring aop命名空间的aop:scoped-proxy元素。
aop:scoped-proxy是与@Scope注解的proxyMode属性功能相同的SpringXML配置元素。它会告诉Spring为bean建立一个做用域代理。默认状况下,它会使用CGLib建立目标类的代理。(能够经过将proxy-target-class属性设置为false,进而要求生成基于接口的代理),例如
<bean id="cart" class="com.myapp.ShoppingCart" scope="session"> <aop:scoped-proxy/> </bean>
注:上述代码,声明做用域为会话的bean,同时指定代理模式为建立目标类的方式。
<bean id="cart" class="com.myapp.ShoppingCart" scope="session"> <aop:scoped-proxy proxy-target-class="false" /> </bean>
注:上述代码,声明做用域为会话的bean,同时指定代理模式为基于接口的方式。
另外,为了使用aop:scoped-proxy元素,必须在XML配置中声明Spring的aop命名空间:
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> ... </bean>
运行时注入:是指将一个值注入到bean的属性或者构造器的参数中。为了实现这些功能,spring提供了两种在运行时求值的方式:
处理外部值的最简单方法就是声明属性源并经过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
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<CompactDisc> 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中解析构造参数,能够以下所示:
<bean id="sgtPeppers" class="soundsystem.BlankDisc" c:_title="${disc.title}" c:_title="${disc.artist}" />
若是是依赖组件扫描和自动装配来建立和初始化组件的话,能够使用@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及其属性源来解析占位符)。