spring的Profile使用对比和应用场景分析

spring中存在这样一个功能,通过Profile来选择不同环境下的不同配置,说白了,就是通过设置一个参数来选择使用不同的数据,这个数据可能是一个bean,可能是一个xml文件,也有可能是一个propertes文件。

经过代码演练和测试,我大体知道了这个功能是干嘛的,也初步知道了它的几种实现方式,但是实际上我依然不是十分明白它的优势和好处在何处,因为根据自己以往的项目经验来说,我觉得用这种方式似乎还有点把简单功能复杂化了。

只是,在网络上我不止一次看到过它,似乎很多人都在用。因此我觉得还是了解一下、学习一下为好,或许它的好处只是我暂时不清楚,而不代表这个好处不存在。

为了让刚接触的朋友能更好的理解,我这里基本上都是代码和测试都写出来,并且三种方式简单的对比,以便于在大家需要用到的时候能具体场景下具体的选择。

实现方式一

完全的java代码加注解的方式,首先创建一个简单的带有构造方法和get、set方法的类:

package springTest4;
public class ProFileTest {
    private String msg;
    public ProFileTest(String msg) {
        super();
        this.msg = msg;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public void printTest() {
        System.out.println(msg);
    }
}

然后再创建一个相当于spring中xml配置文件的类,并且使用注解把这个类声明成一个配置类,同时把上边的类声明为一个bean,并制定profile名称(也就是上边说的profile的选择参数):

 package springTest4;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;

 @Configuration
 public class ProFileConf {
 @Bean
 @Profile("test1")
 public ProFileTest proTest1() {
 return new ProFileTest("test11111");
 }
 @Bean
 @Profile("test2")
 public ProFileTest proTest2() {
 return new ProFileTest("test22222");
 }
 }

这里的@Configuration即声明这个类是一个相当于spring中xml的配置类,剩下两个在前一段文字描述中已经说了,就不再赘述。

至于这段代码的解释,我想通过下边调用的测试代码之后再做解释,模拟profile调用的main方法如下:

package springTest4;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainPro {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.getEnvironment().setActiveProfiles("test2");
        context.register(ProFileConf.class);
        context.refresh();
        String mString = context.getBean(ProFileTest.class).getMsg();
        System.out.println(mString);
        context.close();
    }
}

这里的new AnnotationConfigApplicationContext()声明一个空的上下文,我想学过spring的应该都不需要解释。

context.getEnvironment().setActiveProfiles(“test2”)的意思是获取环境变量,或者理解成获取配置数据,然后把活动的profile的参数或者说名称设置成test2。

context.register(ProFileConf.class)注册具体的配置文件,这里就是ProFileCon.class。

然后后边的几行代码分别是刷新上下文,获取具体的bean对象等等,这些就是比较常规的操作了。

上面的方法执行后结果如图:

而当我把context.getEnvironment().setActiveProfiles(“test2”)这里的test2设置成test1的时候,结果就会成为test11111。

那么结合上边的ProFileConf 中的代码,我想就比较容易理解了,也就是说这里配置了profile参数后,当我们把activeProfiles设置成某个参数时,spring在加载时便会调用这个参数对应的profile的内容。

但是为什么我要说看不出来这样使用的好处在哪里呢?是因为我觉得就这个例子来说,完全可以直接在创建新的对象时用构造方法的不同参数来实现。

当然了,这只是个为了说明这项功能的例子,实际使用自然不会这样,实际使用的时候,可能是用来加载不同的配置文件里的值和属性,也可能是用来调用不同的配置文件。

只不过,即便是这样,我依旧觉得也都可以用参数的方式实现,似乎没有必要这样绕来绕去,并没看到怎么简化了开发,也没看到有什么性能上的提升。

那么还有实现方式二

这个方式和上边的其实是类似的,因为唯一的不同在于把起xml配置文件作用的java类实打实的变成xml配置,因为使用的有构造方法和get、set方法的类是同一个,因此就不再重复贴出来,这里就从test1.xml开始:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">  

<beans profile="test1">
  <bean id="proTest1" class="springTest4.ProFileTest">
   <constructor-arg name="msg" value="test11111" />
  </bean>
</beans>
<beans profile="test2">
  <bean id="proTest2" class="springTest4.ProFileTest">
   <constructor-arg name="msg" value="test22222" />
  </bean>
</beans>
</beans>

这也是一个极其简单的spring配置,除开必要的文件头尾,就只有两个几乎一模一样的beans,指定了profile名称,以及内部的一个普通bean,这个bean以构造函数注入。

对于这种写法,调用也基本是一样的,只不过context获取的是xml而不是calss:

package springTest4;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainPro {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");
        context.getEnvironment().setActiveProfiles("test2");
        context.refresh();
        String mString = context.getBean(ProFileTest.class).getMsg();
        System.out.println(mString);
        context.close();
    }
}

至于这里的具体说明,我想通过对第一个例子的解释,应该已经没有必要再多说了。

实现方式三

前边两种方式,根本上来说是改变了profile的声明方式,而这里需要变得则是调用方式,前两个抛开细节来说,都是在java类中调用,而这里则是在web.xml中调用,当然了,既然有web.xml文件,自然也要是一个web项目才行,web.xml文件配置如下:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
   <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:test1.xml</param-value>
    </init-param>
    <init-param>
      <param-name>spring.profiles.default</param-name>
      <param-value>test2</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping> >
</web-app>

这个web.xml也是一个只为了说明profile的文件,只要一个selvlet配置,两个init-param,第一个是指定自定义的dispatcher-servlet.xml,如果不指定,启动tomcat的时候就会出现如下的错误:

org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/dispatcher-servlet.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/dispatcher-servlet.xml]
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:343)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:303)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)

而第二个init-param则是指定默认的profile的名称。

为了测试这种方式是否可行,我在第二种方式的基础上略作了修改,java类中加入了一个init-method方法,修改之后对应的java类和xml配置如下:

package springTest4;
public class ProFileTest {
    private String msg;
    public ProFileTest(String msg) {
        super();
        this.msg = msg;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public void printTest() {
        System.out.println(msg);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">  

<beans profile="test1">
  <bean id="proTest1" class="springTest4.ProFileTest" init-method="printTest">
   <constructor-arg name="msg" value="test11111" />
  </bean>
</beans>
<beans profile="test2">
  <bean id="proTest2" class="springTest4.ProFileTest" init-method="printTest">
   <constructor-arg name="msg" value="test22222" />
  </bean>
</beans>
</beans>

启动tomcat的过程中,控制台也打印出了预想中的数据,证明第三种方式也是可行的。

以上便是我所知道的三种profile的实现方式,至于具体应用场景,我虽然知道主要是为了方便各种不同环境的切换。比如生产一套配置,测试一套配置;再比如一套单机环境,一套集群环境等等,但是我都觉得完全可以在部署的时候,在spring的context:property-placeholder以及import resource的时候切换。

而且这种切换比起profile来说似乎更加容易上手,所以就不太明白profile的优势究竟在于哪里,欢迎朋友们留言解惑。

时间: 2024-10-15 05:45:47

spring的Profile使用对比和应用场景分析的相关文章

Spring Cloud介绍: Spring Cloud与Dubbo对比

spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式. Spring Cloud与Dubbo对比提到Dubbo,我想顺便提下ESB,目前央视新华社也在用ESB来做任务编排,这里先比较下Dubbo和ESB: ESB(企业数据总线),一般采用集中式转发请求,适合大量异构系统集成,侧重任务的编排,性能问题可通过异构的方式

spring通过profile实现开发和测试环境切换

以开发测试为例,介绍tomcat部署应用和maven部署应用下利用profile实现测试环境和开发环境切换 一.tomcat部署应用 1.数据源配置 dev.properties 路径:/src/main/resrouces jdbc.database=MYSQL jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://mysql:3306/develop?useUnicode=true&characterEncoding=utf-8 jd

scala akka 修炼之路6(scala函数式柯里化风格应用场景分析)

胜败兵家事不期,包羞忍耻是男儿--斗牛士fighting,fighting,fighting... 小象学习和使用scala也一段时间了,最初小象学习scala主要为了学习spark生态,但是深入学习scala的一些特性后,深深被scala函数式和面向对象的风格所折服,不得不赞美设计这门语言的设计者.小象大学阶段在使用MATLAB做数据分析和自动化设计时,就非常喜欢使用MATLAB的命令行和面向矩阵运算的风格编写分析代码:喜欢使用java编写层次化和清晰的模块接口,而这些Scala语言设计中都有

典型用户及用户场景分析

典型用户及用户场景分析 糖糖---一个热爱编程的准程序员 名字 糖糖 性别.年龄 男,刚21岁 收入 暂时还没有 比例和重要性 市场比例很大,很重要 典型场景 写了一段自认为很优秀的代码,想要保存在一个合适的地方 使用本软件/服务的环境 需要保存自己的代码 生活/工作情况 现在还是学生,努力学习 知识层次和能力 大学还未毕业,学习热情极高,编程能力较好 用户的动机.目的和困难 保存代码,但是没有合适的地方 用户的偏好 喜欢给代码增加自定义的标签 呆呆---热爱思考人生的缺乏编程联系的“小学生”

mariadb 10 多源复制(Multi-source replication) 业务使用场景分析,及使用方法

mariadb 10 多源复制(Multi-source replication) 业务使用场景分析,及使用方法 官方mysql一个slave只能对应一个master,mariadb 10开始支持多源复制,一个slave可以有多个master,分别从各自的master复制不同的DB. 这个特性可以用在OLAP环境中,传统电商DB都是拆了再拆,分库分表,sharding,而OLAP环境或者大数据平台环境,通常需要各种数据的聚合,多个平台多个DB数据的复合查询,而这些数据分散在各个库中,怎么办了,当

用户分析和场景分析

用户分析: 名字:二柱子 年龄:30 收入:3000元一个月 代表的比例:代表的是程序维护人员 二柱子:二柱子是一名负责任的找到了网站的管理员,对电脑有很好的掌握,平常最反感得是那些在网站中发小广告的,严重影响了网站的秩序,对网站维护产生干扰, 用户偏好: 场景分析:在进行维护网站的时候,发现有人在网站中发小广告,这让他很生气,希望把这个用户移除出这个网站,并对这个ip进行判断,禁止这个ip访问该网站.

电商抢购秒杀系统的设计_1_应用场景分析

电商抢购秒杀系统的设计_1_应用场景分析 概述 所谓知已知彼,百战不殆,在开始详细介绍实战中的抢购秒杀系统时,我们了解一些抢购秒杀系统系统面临的尴尬与难点.另外需要说明一点,下面的内容都是在工作中慢慢总结得来,我们团队也是慢慢摸着石头过河,甚至最初的的架构设计并非是抢购秒杀系统. 评估系统处理能力 理论基础:LNMP的并发考虑与资源分配 虽然有基础去评估我们应用系统的处理能力,但是电商购买的业务流程挺复杂,从登录,商品详情,购物车,填写收货地址,选择支付方式,创建订单,完成支付,以及隐含的定时服

软件工程结队项目——智能点餐系统典型用户及用户场景分析

一.典型用户分析:一个典型用户描述了一组用户的典型技巧.能力.需要.想法.工作习惯和工作环境. 1.买家典型用户分析: 名字 小郭(石家庄铁道大学交1202-5班) 性别.年龄 男,22岁 联系方式 18330108270 职业 学生 收入 暂无 知识层次和能力 大学在读,会使用各种手机APP软件 生活/工作情况 上课,吃饭,睡觉,偶尔打打游戏,经常在学校门口买饭 动机,目的,困难 很喜欢吃学校门口小吃摊的炒饼,困难:中午3,4节有课时,下课都排队买饭,等的时间太长. 用户偏好 睡觉,打球 用户

典型用户与用户场景分析

自习室查询APP典型用户和用户场景分析: 典型用户 姓名 阿涛 年龄 19 收入 目前为在校大学生,平时做一些兼职工作 用户比例 典型场景 使用软件的查询自习室功能 使用环境 android智能手机 生活工作能力 周一到周五期间在校学习,周末节假日到校外兼职. 知识层次和能力 在校大学生,对电脑.手机使用熟练 动机.目的和困难 姜东每次上自习都需要到教学楼大厅下查看空教室,如果电子屏坏了(比如说二教)就只能一个教室一个教室的去找了. 用户的偏好 爱学习,平时喜欢去图书馆,喜欢科技类书籍 用户场景