配色: 字号:
spring的Profile使用对比和应用场景分析
2016-12-14 | 阅:  转:  |  分享 
  
spring的Profile使用对比和应用场景分析



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



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

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

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



实现方式一



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



packagespringTest4;

publicclassProFileTest{

privateStringmsg;

publicProFileTest(Stringmsg){

super();

this.msg=msg;

}

publicStringgetMsg(){

returnmsg;

}

publicvoidsetMsg(Stringmsg){

this.msg=msg;

}

publicvoidprintTest(){

System.out.println(msg);

}



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



packagespringTest4;

importorg.springframework.context.annotation.Bean;

importorg.springframework.context.annotation.Configuration;

importorg.springframework.context.annotation.Profile;



@Configuration

publicclassProFileConf{

@Bean

@Profile("test1")

publicProFileTestproTest1(){

returnnewProFileTest("test11111");

}

@Bean

@Profile("test2")

publicProFileTestproTest2(){

returnnewProFileTest("test22222");

}

}

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

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



packagespringTest4;

importorg.springframework.context.annotation.AnnotationConfigApplicationContext;

publicclassMainPro{

publicstaticvoidmain(String[]args){

AnnotationConfigApplicationContextcontext=newAnnotationConfigApplicationContext();

context.getEnvironment().setActiveProfiles("test2");

context.register(ProFileConf.class);

context.refresh();

StringmString=context.getBean(ProFileTest.class).getMsg();

System.out.println(mString);

context.close();

}



这里的newAnnotationConfigApplicationContext()声明一个空的上下文,我想学过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开始:






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



























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

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



packagespringTest4;

importorg.springframework.context.support.ClassPathXmlApplicationContext;

publicclassMainPro{

publicstaticvoidmain(String[]args){

ClassPathXmlApplicationContextcontext=newClassPathXmlApplicationContext("test1.xml");

context.getEnvironment().setActiveProfiles("test2");

context.refresh();

StringmString=context.getBean(ProFileTest.class).getMsg();

System.out.println(mString);

context.close();

}



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



实现方式三



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




"-//SunMicrosystems,Inc.//DTDWebApplication2.3//EN"

"http://java.sun.com/dtd/web-app_2_3.dtd">





ArchetypeCreatedWebApplication





dispatcher

org.springframework.web.servlet.DispatcherServlet



contextConfigLocation

classpath:test1.xml





spring.profiles.default

test2



1





dispatcher

/

>





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



org.springframework.beans.factory.BeanDefinitionStoreException:IOExceptionparsingXMLdocumentfromServletContextresource[/WEB-INF/dispatcher-servlet.xml];nestedexceptionisjava.io.FileNotFoundException:CouldnotopenServletContextresource[/WEB-INF/dispatcher-servlet.xml]

atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:343)

atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(Xmwww.baiyuewang.netlBeanDefinitionReader.java:303)

atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)



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

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



packagespringTest4;

publicclassProFileTest{

privateStringmsg;

publicProFileTest(Stringmsg){

super();

this.msg=msg;

}

publicStringgetMsg(){

returnmsg;

}

publicvoidsetMsg(Stringmsg){

this.msg=msg;

}

publicvoidprintTest(){

System.out.println(msg);

}

}






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



























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



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

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

献花(0)
+1
(本文系thedust79首藏)