A story when developing a backend with SpringBoot.
Nowadays, since Docker came out, there is a tendency to manage from combination to production with one module and one source to the end.
The distinction between each environment is based on the design policy of simply passing environment arguments from the outside. So, I will summarize what to do with the application module created with Spring Boot inside
The official information is below, so you can do it here. Official
If you include the following in the startup argument,
-Dspring.profiles.active=dev1
It is a specification that the following files are read.
src/main/resource/application-dev1.properties」
When solidifying a module, making it into a jar, war, etc., switch the configuration file with the maven function. The easiest way to switch configuration files is to transfer files at build time.
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory>
<webResources>
<resource>
<directory>${basedir}/release/${project.stage}</directory>
</resource>
</webResources>
<useCache>false</useCache>
<!--Added due to warning error--> <failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<!--main class specification (if necessary)--> <mainClass>jp.co.●●.●●.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<profiles>
<profile>
<id>dev1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<project.stage>dev01</project.stage>
</properties>
</profile>
<profile>
<id>dev02</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<project.stage>dev02</project.stage>
</properties>
</profile>
</profiles>
Since it is possible to embed shell commands internally, For those who are used to maven, it is familiar.
First, the profile switching method of springboot has a fixed property file format, and it is very difficult to make settings such as reading multiple files. It lacks flexibility, especially when the environment increases.
Secondly, the profile switching method of maven is a setting that only a specific module works in a specific environment when reading multiple files, so if there is an error or procedure error in the deployment shell etc., a failure will occur. Probability is high.
Use ApplicationContextInitializer to set profile at startup.
Java startup argument specification → Specify in profile with ApplicationContextInitializer With this method, you can group when you specify the profile. When executed with dev01, it can contain two pieces of information, dev and dev01.
java -Dproject.stage=dev01 hoge.war
public class SpringActiveProfileInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
/**Logger*/
private static final Logger LOG = LoggerFactory.getLogger(SpringActiveProfileInitializer.class);
@Override
public void initialize(final ConfigurableApplicationContext applicationContext) {
//Get startup argument (dev01)
String projectStage = System.getProperty("project.stage");
//Get boot group (dev)
String prjectStageGroup = projectStage.replaceAll("[0-9]+", "");
ConfigurableEnvironment env = applicationContext.getEnvironment();
if (StringUtils.equals(projectStage, prjectStageGroup)) {
env.setActiveProfiles(projectStage);
} else {
env.setActiveProfiles(prjectStageGroup);
env.addActiveProfile(projectStage);
}
if (LOG.isDebugEnabled()) {
// setting spring.profiles.active = [dev, dev01]
LOG.debug("setting spring.profiles.active = {}", Arrays.asList(env.getActiveProfiles()));
}
}
}
web-fragment.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:webfragment="http://xmlns.jcp.org/xml/ns/javaee/web-fragment_3_0.xsd" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-fragment_3_0.xsd"
version="3.0">
<!--Set Project Stage set in JVM system parameter to Spring Active Profile-->
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>jp.co.future.project.palette.common.context.SpringActiveProfileInitializer</param-value>
</context-param>
</xml>
Profile can be described even inside xml, Definition files can be separated for each environment
Although described in the sample, settings such as commonality and reading of external files are also possible.
<beans profile="dev">
<!--Data source-->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="jdbcUrl" value=""/>
</bean>
</beans>
<beans profile="stg">
<!--Data source-->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="jdbcUrl" value=""/>
</bean>
</beans>
<!--Multiple stages can be specified by separating them with commas-->
<beans profile="dev,stg">
<bean id="redis" >
</bean>
</beans>
<beans profile="dev01">
<!--Property files can also be read from xml-->
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="classpath:config/connect-config-dev01.properties" />
</bean>
</beans>
<!--It is also possible to import the xml itself-->
<import resource="classpath:META-INF/common-context.xml" />
As mentioned above, it was the method of switching the environment with spring boot. One module, one source!
Recommended Posts