前言

由于在项目中使用Maven打包部署的时候,经常由于配置参数过多(比如Nginx服务器的信息、ZooKeeper的信息、数据库连接、Redis服务器地址等),导致实际现网的配置参数与测试服务器参数混淆,一旦在部署的时候某个参数忘记修改了,那么就必须重新打包部署,这确实让人感到非常头疼。因此就想到使用Spring中的Profile来解决上面描述的问题,并且在此记录一下其使用的方式,如果有不对的地方,请指正!(感谢)。
本文从如下3方面探讨Spring的Profile:

  • Spring中的Profile是什么
  • 为什么要使用Profile
  • 如何使用Profile

1.Spring中的Profile 是什么?

Spring中的Profile功能其实早在Spring 3.1的版本就已经出来,它可以理解为我们在Spring容器中所定义的Bean的逻辑组名称,只有当这些Profile被激活的时候,才会将Profile中所对应的Bean注册到Spring容器中。举个更具体的例子,我们以前所定义的Bean,当Spring容器一启动的时候,就会一股脑的全部加载这些信息完成对Bean的创建;而使用了Profile之后,它会将Bean的定义进行更细粒度的划分,将这些定义的Bean划分为几个不同的组,当Spring容器加载配置信息的时候,首先查找激活的Profile,然后只会去加载被激活的组中所定义的Bean信息,而不被激活的Profile中所定义的Bean定义信息是不会加载用于创建Bean的。

2.为什么要使用Profile

由于我们平时在开发中,通常会出现在开发的时候使用一个开发数据库,测试的时候使用一个测试的数据库,而实际部署的时候需要一个数据库。以前的做法是将这些信息写在一个配置文件中,当我把代码部署到测试的环境中,将配置文件改成测试环境;当测试完成,项目需要部署到现网了,又要将配置信息改成现网的,真的好烦。。。而使用了Profile之后,我们就可以分别定义3个配置文件,一个用于开发、一个用户测试、一个用户生产,其分别对应于3个Profile。当在实际运行的时候,只需给定一个参数来激活对应的Profile即可,那么容器就会只加载激活后的配置文件,这样就可以大大省去我们修改配置信息而带来的烦恼。

3.配置Spring profile

在介绍完Profile以及为什么要使用它之后,下面让我们以一个例子来演示一下Profile的使用,这里还是使用传统的XML的方式来完成Bean的装配。

3.1 例子需要的Maven依赖

由于只是做一个简单演示,因此无需引入Spring其他模块中的内容,只需引入核心的4个模块+测试模块即可。

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

3.2 例子代码

package com.panlingxiao.spring.profile.service;

/**
* 定义接口,在实际中可能是一个数据源
* 在开发的时候与实际部署的时候分别使用不同的实现
*/
public interface HelloService { public String sayHello();
}

定义生产环境使用的实现类

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配置文件

<?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

4.激活Profile的其他几种方式

上面介绍了如何使用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容器自动去这些位置读取然后自动设置,这些位置主要为如下定义的地方:

  • 作为SpringMVC中的DispatcherServlet的初始化参数
  • 作为Web 应用上下文中的初始化参数
  • 作为JNDI的入口
  • 作为环境变量
  • 作为虚拟机的系统参数
  • 使用@AtivceProfile来进行激活

我们在实际的使用过程中,可以定义默认的profile为开发环境,当实际部署的时候,主需要在实际部署的环境服务器中将spring.profiles.active定义在环境变量中来让Spring自动读取当前环境下的配置信息,这样就可以很好的避免不同环境而频繁修改配置文件的麻烦。

4.5 示例代码下载

示例代码下载地址:Spring-profile-test

参考:

  1. Spring Framework Reference Documentation 4.2.5.RELEASE-- 6.13. Environment abstraction
  2. Spring Framework Reference Documentation 3.2.3.RELEASE --3.2 Bean Definition Profiles
  3. <<Spring In Action Fourth Edition>>

from: http://www.jianshu.com/p/948c303b2253

详解Spring中的Profile的更多相关文章

  1. 用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)

    用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心.依赖注入(DI)是 ...

  2. 使用IDEA详解Spring中依赖注入的类型(上)

    使用IDEA详解Spring中依赖注入的类型(上) 在Spring中实现IoC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(例如属性值)注入Bean组件 ...

  3. 详解Spring中Bean的作用域与生命周期

    摘要:在利用Spring进行IOC配置时,关于bean的配置和使用一直都是比较重要的一部分,同时如何合理的使用和创建bean对象,也是小伙伴们在学习和使用Spring时需要注意的部分,所以这一篇文章我 ...

  4. 【Spring】详解Spring中Bean的加载

    之前写过bean的解析,这篇来讲讲bean的加载,加载要比bean的解析复杂些,该文之前在小编原文中有发表过,要看原文的可以直接点击原文查看,从之前的例子开始,Spring中加载一个bean的方式: ...

  5. 详解Spring中的ApplicationListener和ContextRefreshedEvent

    ApplicationListener和ContextRefreshedEvent一般都是成对出现的.最近在面试中问到了被面试者对于这两个的用法,面试者大多数被问懵了.可见基础知识的掌握程度.基于此本 ...

  6. 详解Spring中的CharacterEncodingFilter

    在项目中有很多让人头疼的问题,其中,编码问题位列其一,那么在Spring框架中是如何解决从页面传来的字符串的编码问题的呢?下面我们来看看Spring框架给我们提供过滤器CharacterEncodin ...

  7. 详解Spring中的CharacterEncodingFilter--forceEncoding为true在java代码中设置失效--html设置编码无效

    在项目中有很多让人头疼的问题,其中,编码问题位列其一,那么在Spring框架中是如何解决从页面传来的字符串的编码问题的呢?下面我们来看看Spring框架给我们提供过滤器CharacterEncodin ...

  8. applicationContext.xml详解 spring+mybatis+struts

    今天给大家详细解释一项关于Spring的applicationContext.xml文件,这对于初学者来说,应该是很有帮助的, 以下是详解Spring的applicationContext.xml文件 ...

  9. 【转】详解spring 每个jar的作用

    spring.jar 是包含有完整发布模块的单个jar 包.但是不包括mock.jar, aspects.jar, spring-portlet.jar, and spring-hibernate2. ...

随机推荐

  1. HTTP Status 500 - Request processing failed; nested exception is org.apache.ibatis.binding.BindingException

    在使用Maven工程管理工具整合SSM框架时,Mybatis使用逆向工程生成的pojo,mapper接口及映射文件,把mapper接口和映射文件放在DAO工程的同一级src/main/java目录下. ...

  2. php中explode和implode函数

    explode array explode ( string $delimiter, string $string, [ , $limit ] ) 函数返回由字符串组成的数组,每个元素都是string ...

  3. Java 中的定时任务(一)

    定时任务简单来说就是在指定时间,指定的频率来执行一个方法,而在 Java 中我们又该如何实现呢? 想来主要有 3 种方式,最原始的方式肯定是开启一个线程,让它睡一会跑一次睡一会跑一次这也就达到了定频率 ...

  4. 基于TensorFlow Serving的深度学习在线预估

    一.前言 随着深度学习在图像.语言.广告点击率预估等各个领域不断发展,很多团队开始探索深度学习技术在业务层面的实践与应用.而在广告CTR预估方面,新模型也是层出不穷: Wide and Deep[1] ...

  5. FGPA 中的计数器Verilog语言(时钟分频器)

    在quartusII8.0中为ALTERAFPGA设置一个分频器(计数器) 输入时钟48Mhz 输出时钟9600HZ /* 实验名称: 计数器 ** 程序功能: 将48Mhz的时钟分频为9600Hz ...

  6. iOS Sprite Kit教程之xcode安装以及苹果帐号绑定

    iOS Sprite Kit教程之xcode安装以及苹果帐号绑定 其它的网站上下载安装Xcode 有时候,应用商店下载较慢,所以用户也可以选择从其他网站下载Xcode安装文件.下面讲解这种Xcode的 ...

  7. hdu1242Rescue

     STL容器之优先队列 优先级队列,以前刷题的时候用的比较熟,现在竟然我只能记得它的关键字是priority_queue(太伤了).在一些定义了权重的地方这个数据结构是很有用的. 先回顾队列的定义 ...

  8. python的可变与不可变数据类型

    <python的可变与不可变数据类型>     python与C/C++不一样,它的变量使用有自己的特点,当初学python的时候,一定要记住“一切皆为对象,一切皆为对象的引用”这句话,其 ...

  9. 凡信(超仿微信Android版)开源了,内有源码下载 -

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 凡信(超仿微信Android版)开源了,内有源码下载 - IM Geek开发者社区-移动 ...

  10. JZYZOJ1140 飞船控制站

    http://172.20.6.3/Problem_Show.asp?id=1140 p1140 就一道非常普通的二分,但是非常蛋疼的是验证mid left的过程一直错(就是写一个k次循环然后根据可行 ...