Spring小知识——profile配置

引言

工作中我们会遇到一些实际有关配置不同的情况,比如生产数据库配置、开发环境数据库配置、测试环境数据库配置,还有一些特殊方法只需要开发环境执行生产环境不需要执行的。
这种情况的解决方式一般两种:
1、使用maven打包方式不同,不同的环境使用不同的配置文件打包(常用)
2、使用Spring提供的profile配置,不同的环境使用不同的运行参数。

介绍

笔者针对的是Spring提供的profile配置方式的介绍。
Springboot中实现Profile的配置如下

@Configuration
@Profile("dev")
public class  DevelopmentProfileConfig{
     @Bean
     public UserInfo userInit(){
          return ......;
     }
}

那么在我们使用的Spring中是如何配置的?笔者提供了以下的配置方式以供参考:

Spring配置步骤如下
第一步:编写三个环境的Spring配置文件如下

applicationContest-dev.xml 配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- 手动定义一个bean -->
    <bean id="userInfo" name="userInfo2" class="com.leo.model.UserInfo" init-method="myInit"
          destroy-method="myDestroy">
        <property name="id" value="2"></property>
        <property name="name" value="开发环境配置"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

applicationContest-dev.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- 手动定义一个bean -->
    <bean id="userInfo" name="userInfo2" class="com.leo.model.UserInfo" init-method="myInit"
          destroy-method="myDestroy">
        <property name="id" value="2"></property>
        <property name="name" value="测试环境配置"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

applicationContest-prod.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <!-- 手动定义一个bean -->
    <bean id="userInfo" name="userInfo2" class="com.leo.model.UserInfo" init-method="myInit"
          destroy-method="myDestroy">
        <property name="id" value="2"></property>
        <property name="name" value="生产环境配置"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>
第二步:配置Spring的主配置文件

配置applicationContest-mainTest.xml,将三个环境的配置文件引入

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

    <beans profile="test">
        <import resource="applicationContext-test.xml"></import>
    </beans>
    <beans profile="prod">
        <import resource="applicationContext-prod.xml"></import>
    </beans>
    <beans profile="dev">
        <import resource="applicationContext-dev.xml"></import>
    </beans>
</beans>
第三步:编写测试代码
    /**
     *  针对Profile的测试
     */
    @Test
    public void profileTest() throws InterruptedException {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(CLASS_PATH_RESOURCE);
        UserInfo userInfo = (UserInfo) applicationContext.getBean("userInfo");
        System.out.println(userInfo);
        TimeUnit.SECONDS.sleep(3);
        applicationContext.registerShutdownHook();
    }

运行单元测试,发现报错了

三月 01, 2020 1:23:18 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6c629d6e: startup date [Sun Mar 01 13:23:18 CST 2020]; root of context hierarchy
"D:\Program Files\Java\jdk1.8.0_45\bin\java" -ea -Didea.launcher.port=7532 "-Didea.launcher.bin.path=D:\Program Files (x86)\JetBrains\IntelliJ IDEA 14.0.2\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files (x86)\JetBrains\IntelliJ IDEA 14.0.2\lib\idea_rt.jar;D:\Program Files (x86)\JetBrains\IntelliJ IDEA 14.0.2\plugins\junit\lib\junit-rt.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\rt.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_45\jre\lib\ext\zipfs.jar;E:\WorkSpace\Git\spring-framework-learning-example\chapter-4-springmvc-sourcecode-analysis\target\test-classes;E:\WorkSpace\Git\spring-framework-learning-example\chapter-4-springmvc-sourcecode-analysis\target\classes;D:\Library\maven\repository\junit\junit\4.12\junit-4.12.jar;D:\Library\maven\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\Library\maven\repository\org\springframework\spring-webmvc\4.3.25.RELEASE\spring-webmvc-4.3.25.RELEASE.jar;D:\Library\maven\repository\org\springframework\spring-aop\4.3.25.RELEASE\spring-aop-4.3.25.RELEASE.jar;D:\Library\maven\repository\org\springframework\spring-beans\4.3.25.RELEASE\spring-beans-4.3.25.RELEASE.jar;D:\Library\maven\repository\org\springframework\spring-context\4.3.25.RELEASE\spring-context-4.3.25.RELEASE.jar;D:\Library\maven\repository\org\springframework\spring-core\4.3.25.RELEASE\spring-core-4.3.25.RELEASE.jar;D:\Library\maven\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\Library\maven\repository\org\springframework\spring-expression\4.3.25.RELEASE\spring-expression-4.3.25.RELEASE.jar;D:\Library\maven\repository\org\springframework\spring-web\4.3.25.RELEASE\spring-web-4.3.25.RELEASE.jar;D:\Library\maven\repository\javax\servlet\javax.servlet-api\3.0.1\javax.servlet-api-3.0.1.jar;D:\Library\maven\repository\javax\servlet\jsp\jsp-api\2.2\jsp-api-2.2.jar;D:\Library\maven\repository\org\springframework\spring-test\4.3.25.RELEASE\spring-test-4.3.25.RELEASE.jar;D:\Library\maven\repository\org\aspectj\aspectjrt\1.8.9\aspectjrt-1.8.9.jar;D:\Library\maven\repository\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar" com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 BeanTest,profileTest
三月 01, 2020 1:23:18 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6c629d6e: startup date [Sun Mar 01 13:23:18 CST 2020]; root of context hierarchy
三月 01, 2020 1:23:18 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext-mainTest.xml]
三月 01, 2020 1:23:19 下午 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader doRegisterBeanDefinitions
信息: Skipped XML bean definition file due to specified profiles [test] not matching: class path resource [applicationContext-mainTest.xml]
三月 01, 2020 1:23:19 下午 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader doRegisterBeanDefinitions
信息: Skipped XML bean definition file due to specified profiles [prod] not matching: class path resource [applicationContext-mainTest.xml]
三月 01, 2020 1:23:19 下午 org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader doRegisterBeanDefinitions
信息: Skipped XML bean definition file due to specified profiles [dev] not matching: class path resource [applicationContext-mainTest.xml]

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userInfo' available
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:682)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1218)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1082)
	at BeanTest.profileTest(BeanTest.java:39)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
第四步:报错原因分析

通过报错的日志分析,我们报错的直接原因:org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userInfo' available
没有找到这个bean对象。
根本原因是:Skipped XML bean definition file due to specified profiles [test] not matching: class path resource [applicationContext-mainTest.xml]
翻译过来过来就是没有找到匹配的profiles为test的文件。
产生这个错误的原因是我们需要提前在环境变量中激活我们需要使用的配置文件

激活的配置的参数有两个:spring.profiles.defaultspring.profiles.active

激活的方式有以下几种

  1. 在SpringMVC中作为DispatcherServlet的初始化参数
  <servlet>
        <servlet-name>myspringmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 指定spring配置文件的位置,如果不配置默认/WEB-INF/[servlet-name]-servlet -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:myspringmvc-servlet.xml</param-value>
            <param-name>spring.profiles.default</param-name>
            <!-- 在这里激活dev的配置 -->
            <param-value>dev</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
  1. 在Web应用中作为应用上下文参数
<context-param>
    <param-name>spring.profiles.default</param-name>
    <param-value>dev</param-value>
</context-param>
  1. 作为环境变量
    环境变量配置
  2. 作为JVM的系统属性

jvm参数
最后附一下测试结果:
spring.profiles.default=dev之后结果
结果2
spring.profiles.default=prod之后结果
结果3

总结

使用Spring提供的profile配置可以让不同环境使用不同的配置,本文也只是抛砖引玉给大家提供一种解题思路。本文介绍了spring.profiles.default其实还有spring.profiles.active ,后者的用法和前者类似,如果共同使用则以spring.profiles.active的配置优先。
测试结果也证明了以上说法:
两个都配置
结果6
最后,笔者使用下面配置方式并未达到预期的效果,推测原因是bean初始化的时候已经通过环境变量或者JVM参数完成了bean参数的初始化,在此之后如果再使用applicationContext.getEnvironment().setActiveProfiles("prod")修改的话,虽然能修改Profiles参数,但是bean的初始化已经完成了,因此这个时候获取的bean仍然是修改之前的bean。

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(CLASS_PATH_RESOURCE);
        applicationContext.getEnvironment().setActiveProfiles("prod");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leo825...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值