java - Build once and deploy for many environments -


we have legacy system 50 -60 maven modules, of these modeules have used maven resource plugin filter properties (replace tokens @ build time in property files). painful when comes build different environments, because have build application each time when need deploy different environments.

we have new requirement build application once , deploy many environments. best solution this? think of externalizing filter properties, biggest issue replace token of existing property files of application (see application.properties) file below. want keep existing property files , pick values external config file.

any appreciate it.

e.g filter.properties injected maven.

generic.sharepoint.host=xxxxx generic.deploy.apps.host=xxxxx generic.deploy.apps.url=xxxx generic.deploy.trusted.host=xxxx generic.deploy.trusted.url=xxxx generic.deploy.orderentry=xxxxx 

application.properties

generic.sharepoint.host=${generic.sharepoint.host} generic.deploy.apps.host=${generic.deploy.apps.host} generic.deploy.apps.url=${generic.deploy.apps.url} generic.deploy.trusted.host=${generic.deploy.trusted.host} generic.deploy.trusted.url=${generic.deploy.trusted.url} generic.deploy.orderentry=${generic.deploy.orderentry} 

in experience had build spring based web application once , deploy on many different environments, i'm trying show solution worked fine me.

i couldn't find way hand off task maven, decided externalize configuration , found exploiting spring manage achieve performing 2 steps:

  1. make application 'aware' of environment deployed to, reading file containing environment's name (e.g. dev, test, production)
  2. accordingly environment value found,set system property , load config file placed in correspondent folder.

having tomcat, set configuration folder structure under shared/classes in way this:

config structure

and put in application-config folder application-config.properties file containing descripton of environment:

application-config.env=dev 

and same configuration files under every single child folder configured related environment required. after had add spring application context application-config-context.xml bean definitions in order interact org.springframework.beans.factory.config.propertiesfactorybean:

<?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"   xsi:schemalocation="http://www.springframework.org/schema/beans     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     http://www.springframework.org/schema/context     http://www.springframework.org/schema/context/spring-context-3.0.xsd">    <bean id="environmentdetector" class="com.mycompany.myapp.spring.util.propertiesbasedenvironmentdetector" init-method="init" >     <property name="properties" ref="environmentdefinitionproperties" />     <property name="environmentdefinitionpropertyname" value="application-config.env"/>   </bean>    <bean id="environmentdefinitionproperties" class="org.springframework.beans.factory.config.propertiesfactorybean">     <property name="ignoreresourcenotfound" value="true" />     <property name="locations">       <list>         <value>classpath:application-config/application-config.properties</value>       </list>     </property>   </bean>    <bean     class="org.springframework.beans.factory.config.propertyplaceholderconfigurer" >     <property name="systempropertiesmodename" value="system_properties_mode_override" />     <property name="ignoreresourcenotfound" value="false" />     <property name="ignoreunresolvableplaceholders" value="true" />     <property name="properties" ref="applicationexternalproperties" />   </bean>    <bean id="applicationexternalproperties" class="org.springframework.beans.factory.config.propertiesfactorybean" >     <property name="location" value="${application-config.prefix}application-config/${application-config.env}/application.properties" />   </bean>  </beans> 

i had code class override spring's postprocessbeanfactory method of interface org.springframework.beans.factory.config.beanfactorypostprocessor this:

package com.mycompany.myapp.doc.spring.util;  import java.util.properties;  import javax.annotation.postconstruct;  import org.apache.commons.logging.log; import org.apache.commons.logging.logfactory; import org.springframework.beans.beansexception; import org.springframework.beans.factory.config.beanfactorypostprocessor; import org.springframework.beans.factory.config.configurablelistablebeanfactory; import org.springframework.core.priorityordered;  public class propertiesbasedenvironmentdetector implements beanfactorypostprocessor, priorityordered{     private static final log log = logfactory.getlog(propertiesbasedenvironmentdetector.class);      private properties properties;     private string environmentdefinitionpropertyname ="env";     private string defaultenvironment="dev";     private string environmentsystempropertyname;     private int order = priorityordered.highest_precedence;      private string prefixsystempropertyname = "application-config.prefix";     private string prefixdefault = "classpath:";     private string prefix;      public void setproperties(properties properties) {         this.properties = properties;     }      @postconstruct     public void init()     {         if (environmentsystempropertyname == null) {             environmentsystempropertyname = environmentdefinitionpropertyname;         }         string activeenvironment = properties.getproperty(environmentdefinitionpropertyname, defaultenvironment);         prefix = properties.getproperty(prefixsystempropertyname);         if (prefix == null) {             prefix = prefixdefault;             properties.put(prefixsystempropertyname, prefix);         }         system.setproperty(environmentsystempropertyname , activeenvironment);         system.setproperty(prefixsystempropertyname , prefix);          log.warn("initializing environment: "+activeenvironment);      }      public string getenvironmentdefinitionpropertyname() {         return environmentdefinitionpropertyname;     }      public void setenvironmentdefinitionpropertyname(         string environmentdefinitionpropertyname) {         this.environmentdefinitionpropertyname = environmentdefinitionpropertyname;     }      public string getdefaultenvironment() {         return defaultenvironment;     }      public void setdefaultenvironment(string defaultenvironment) {         this.defaultenvironment = defaultenvironment;     }      public string getenvironmentsystempropertyname() {         return environmentsystempropertyname;     }      public void setenvironmentsystempropertyname(string environmentsystempropertyname)     {         this.environmentsystempropertyname = environmentsystempropertyname;     }      @override     public void postprocessbeanfactory(configurablelistablebeanfactory beanfactory)         throws beansexception     {         string activeenvironment = system.getproperty(environmentsystempropertyname);         log.warn("postprocessing applicationcontext environment: "+activeenvironment+" "+prefix);     }      @override     public int getorder() {         return order;     }      public void setorder(int order) {         this.order = order;     }  } 

when application starts, spring loads contexts , our custom class called. in init() method first loads environmentdefinitionpropertyname through injected properties property , set system property having key environmentdefinitionpropertyname value set in bean definition.

after that, propertyplaceholderconfigurer can load properties file location since resolves:

<property name="location" value="${application-config.prefix}application-config/${application-config.env}/application.properties" /> 

into

<property name="location" value="classpath:application-config/dev/application.properties" /> 

this approach had these principal advantages:

  • you can add further environments adding folder under original configuration folder
  • the original application package same on environments
  • the properties file has 'normal' key=value format, application.properties file.

hope helps , may others well.


Popular posts from this blog