因为在项目中使用Maven打包部署的时候,常常因为配置参数过多(好比Nginx服务器的信息、ZooKeeper的信息、数据库链接、Redis服务器地址等),致使实际现网的配置参数与测试服务器参数混淆,一旦在部署的时候某个参数忘记修改了,那么就必须从新打包部署,这确实让人感到很是头疼。所以就想到使用Spring中的Profile来解决上面描述的问题,而且在此记录一下其使用的方式,若是有不对的地方,请指正!(感谢)。
本文从以下3方面探讨Spring的Profile:java
Spring中的Profile功能其实早在Spring 3.1的版本就已经出来,它能够理解为咱们在Spring容器中所定义的Bean的逻辑组名称,只有当这些Profile被激活的时候,才会将Profile中所对应的Bean注册到Spring容器中。举个更具体的例子,咱们之前所定义的Bean,当Spring容器一启动的时候,就会一股脑的所有加载这些信息完成对Bean的建立;而使用了Profile以后,它会将Bean的定义进行更细粒度的划分,将这些定义的Bean划分为几个不一样的组,当Spring容器加载配置信息的时候,首先查找激活的Profile,而后只会去加载被激活的组中所定义的Bean信息,而不被激活的Profile中所定义的Bean定义信息是不会加载用于建立Bean的。spring
因为咱们平时在开发中,一般会出如今开发的时候使用一个开发数据库,测试的时候使用一个测试的数据库,而实际部署的时候须要一个数据库。之前的作法是将这些信息写在一个配置文件中,当我把代码部署到测试的环境中,将配置文件改为测试环境;当测试完成,项目须要部署到现网了,又要将配置信息改为现网的,真的好烦。。。而使用了Profile以后,咱们就能够分别定义3个配置文件,一个用于开发、一个用户测试、一个用户生产,其分别对应于3个Profile。当在实际运行的时候,只需给定一个参数来激活对应的Profile便可,那么容器就会只加载激活后的配置文件,这样就能够大大省去咱们修改配置信息而带来的烦恼。shell
在介绍完Profile以及为何要使用它以后,下面让咱们以一个例子来演示一下Profile的使用,这里仍是使用传统的XML的方式来完成Bean的装配。数据库
因为只是作一个简单演示,所以无需引入Spring其余模块中的内容,只需引入核心的4个模块+测试模块便可。express
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!--指定Spring版本,该版本必须大于等于3.1--> <spring.version>4.2.4.RELEASE</spring.version> <!--指定JDK编译环境--> <java.version>1.7</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build>
package com.panlingxiao.spring.profile.service; /** * 定义接口,在实际中多是一个数据源 * 在开发的时候与实际部署的时候分别使用不一样的实现 */ public interface HelloService { public String sayHello(); }
定义生产环境使用的实现类apache
package com.panlingxiao.spring.profile.service.produce; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.panlingxiao.spring.profile.service.HelloService; /** * 模拟在生产环境下须要使用的类 */ @Component public class ProduceHelloService implements HelloService { //这个值读取生产环境下的配置注入 @Value("#{config.name}") private String name; public String sayHello() { return String.format("hello,I'm %s,this is a produce environment!", name); } }
定义开发下使用的实现类服务器
package com.panlingxiao.spring.profile.service.dev; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.panlingxiao.spring.profile.service.HelloService; /** * 模拟在开发环境下使用类 */ @Component public class DevHelloService implements HelloService{ //这个值是读取开发环境下的配置文件注入 @Value("#{config.name}") private String name; public String sayHello() { return String.format("hello,I'm %s,this is a development environment!", name); } }
定义配置Spring配置文件maven
<?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" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd"> <!-- 定义开发的profile --> <beans profile="development"> <!-- 只扫描开发环境下使用的类 --> <context:component-scan base-package="com.panlingxiao.spring.profile.service.dev" /> <!-- 加载开发使用的配置文件 --> <util:properties id="config" location="classpath:dev/config.properties"/> </beans> <!-- 定义生产使用的profile --> <beans profile="produce"> <!-- 只扫描生产环境下使用的类 --> <context:component-scan base-package="com.panlingxiao.spring.profile.service.produce" /> <!-- 加载生产使用的配置文件 --> <util:properties id="config" location="classpath:produce/config.properties"/> </beans> </beans>
开发使用的配置文件,dev/config.properties单元测试
name=Tomcat
生产使用的配置文件,produce/config.properties测试
name=Jetty
编写测试类
package com.panlingxiao.spring.profile.test; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.panlingxiao.spring.profile.service.HelloService; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:spring-profile.xml") /* * 使用注册来完成对profile的激活, * 传入对应的profile名字便可,能够传入produce或者dev */ @ActiveProfiles("produce") public class TestActiveProfile { @Autowired private HelloService hs; @Test public void testProfile() throws Exception { String value = hs.sayHello(); System.out.println(value); } }
激活dev运行结果.png
激活produce运行结果.jpg
上面介绍了如何使用Profile以及在单元测试的环境下激活指定的Profile,除了使用@ActiveProfiles注解来激活profile外,Spring还提供了其余的几种激活Profile,这些方式在实际的开发中使用的更多。
Spring经过两个不一样属性来决定哪些profile能够被激活(注意:profile是能够同时激活多个的),一个属性是spring.profiles.active和spring.profiles.default。这两个常量值在Spring的AbstractEnvironment中有定义,查看AbstractEnvironment源码:
/** * Name of property to set to specify active profiles: {@value}. Value may be comma * delimited. * <p>Note that certain shell environments such as Bash disallow the use of the period * character in variable names. Assuming that Spring's {@link SystemEnvironmentPropertySource} * is in use, this property may be specified as an environment variable as * {@code SPRING_PROFILES_ACTIVE}. * @see ConfigurableEnvironment#setActiveProfiles */ public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active"; /** * Name of property to set to specify profiles active by default: {@value}. Value may * be comma delimited. * <p>Note that certain shell environments such as Bash disallow the use of the period * character in variable names. Assuming that Spring's {@link SystemEnvironmentPropertySource} * is in use, this property may be specified as an environment variable as * {@code SPRING_PROFILES_DEFAULT}. * @see ConfigurableEnvironment#setDefaultProfiles */ public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
若是当spring.profiles.active属性被设置时,那么Spring会优先使用该属性对应值来激活Profile。当spring.profiles.active没有被设置时,那么Spring会根据spring.profiles.default属性的对应值来进行Profile进行激活。若是上面的两个属性都没有被设置,那么就不会有任务Profile被激活,只有定义在Profile以外的Bean才会被建立。咱们发现这两个属性值实际上是Spring容器中定义的属性,而咱们在实际的开发中不多会直接操做Spring容器自己,因此若是要设置这两个属性,实际上是须要定义在特殊的位置,让Spring容器自动去这些位置读取而后自动设置,这些位置主要为以下定义的地方:
咱们在实际的使用过程当中,能够定义默认的profile为开发环境,当实际部署的时候,主须要在实际部署的环境服务器中将spring.profiles.active定义在环境变量中来让Spring自动读取当前环境下的配置信息,这样就能够很好的避免不一样环境而频繁修改配置文件的麻烦。