I have an application with maven as a build tool.
I am using maven profiles to set up different properties from different profiles.
What i would like to do is that all active profiles in maven will be ported to spring active profiles as well so i can reference them in bean signature (#profile). but i am not sure how to do it.
for example: consider the following maven setup
<profiles>
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
</properties>
</profile>
<profile>
<id>profile2</id>
<properties>
</properties>
</profile>
<profile>
<id>development</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
</properties>
</profile>
<profile>
<id>production</id>
<properties>
</properties>
</profile>
</profiles>
assuming i run maven with out specifying any other profiles i would like for spring to have profile1 and development as active profiles.
There is a more elegant way to switch between 2 maven+spring profiles simultaneously.
First, add profiles to POM (pay attention - maven+spring profile is activated by single system variable):
<profiles>
<profile>
<id>postgres</id>
<activation>
<activeByDefault>true</activeByDefault>
<property>
<name>spring.profiles.active</name>
<value>postgres</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901.jdbc4</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>h2</id>
<activation>
<property>
<name>spring.profiles.active</name>
<value>h2</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.191</version>
</dependency>
</dependencies>
</profile>
</profiles>
Second, set default profile for spring (for maven it is already set in POM). For web application, I inserted following lines to web.xml:
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>postgres</param-value>
</context-param>
Third, add profile-dependent beans to your config. In my case (XML config), it is:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="mainDataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties" ref="hibProps"/>
<property name="packagesToScan">
<list>
<value>my.test.model</value>
</list>
</property>
</bean>
...
<beans profile="postgres">
<bean name="mainDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://127.0.0.1:5432/webchat" />
<property name="username" value="postgres" />
<property name="password" value="postgres" />
</bean>
</beans>
<beans profile="h2">
<bean name="mainDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:file:./newsdb;INIT=RUNSCRIPT FROM 'classpath:init.sql';TRACE_LEVEL_FILE=0" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
</beans>
Now it is possible to:
Run my web-app on Postgres DB with mvn jetty:run or mvn jetty:run -Dspring.profiles.active=postgres commands
Run my web-app on H2 DB with mvn clean jetty:run -Dspring.profiles.active=h2
The first thing you need is two properties files for keeping your configurations. The names of the files should match with the pattern application-{custom_suffix}.properties. Create them in the src/main/resources directory of your Maven project, next to the main application.properties file, which you’re going to use later to activate one of the others and to hold values shared by both profiles.
Then it’s time to modify your pom.xml. You need to define a custom property in each of your Maven profiles and set their values to match with suffixes of corresponding properties files that you want to load with a particular profile. The following sample also marks the first profile to run by default, but it’s not mandatory.
<profile>
<id>dev</id>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>release</id>
<properties>
<activatedProperties>release</activatedProperties>
</properties>
</profile>
Next, in the build section of the same file, configure filtering for the Resources Plugin. That will allow you to insert properties defined in the previous step into any file in the resources directory, which is the subsequent step.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
…
</build>
Finally, add the following line to the application.properties.
spring.profiles.active=#activatedProperties#
When the build is run, the Resources Plugin will replace the placeholder with the value of the property defined in the active Maven profile. After starting your application, the Spring framework will load the appropriate configuration file based on the name of the active Spring profile, which is described by the value of the spring.profiles.active property. Note that Spring Boot 1.3 replaced the default Resources Plugin syntax for filtered values and uses #activatedProperties# instead of ${activatedProperties} notation.
It worked to perfection. Hope this can help you.
You'll have to filter a resources of your application, for instance a property file, that holds the information of which profile to activate in spring.
For instance
spring.profile = ${mySpringProfile}
And for each profile, define a value for this variable (mySpringProfile).
During the build, this will be filtered accordingly to the value defined in the currently active profile.
Then during the bootstrap of your application you'll select the appropriated profile according to this file (can't help you more as you didn't gave us more information, but this is quite easy.
Note: I can't find a way to get the currently active profile in maven (something like project.profiles.active that holds your -P values), that's why you'll have to set a new variable for each profile.
Note 2: if you are running a web application, instead of using this intermediate file, filter this value in your web.xml
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>${mySpringProfile}</param-value>
</context-param>
Note 3: This is actually a bad practice, and you should set the profile at runtime with a system property
For a Spring Boot application, one can add a property in the Maven profile in pom.xml and then reference that property in application.properties.
Add Maven profiles to pom.xml with, for example, a property called spring.profile.from.maven:
<profiles>
<profile>
<id>postgres</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<spring.profile.from.maven>postgres</spring.profile.from.maven>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</profile>
<profile>
<id>noDb</id>
<properties>
<spring.profile.from.maven>noDb</spring.profile.from.maven>
</properties>
</profile>
</profiles>
Reference the Maven property in application.properties:
spring.profiles.include=#spring.profile.from.maven#
With this setup, running maven with the postgres Maven profile or with no profile adds the postgres Spring profile to the list of Spring's active profiles, while running maven with the noDb Maven profile adds the noDb Spring profile to the list of Spring's active profiles.
Add placeholder ${activeProfile} in web.xml:
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>${activeProfile}</param-value>
</context-param>
Set properties in pom.xml for each profile:
<profiles>
<profile>
<id>profile1</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<activeProfile>profile1</activeProfile>
</properties>
</profile>
<profile>
<id>profile2</id>
<properties>
<activeProfile>profile2</activeProfile>
</properties>
</profile>
</profiles>
Add maven-war-plugin and set <filteringDeploymentDescriptors>true</filteringDeploymentDescriptors> to replace the placeholder when running mvn package -Pprofile1 or mvn package -Pprofile2:
<build>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
</plugin>
</build>
I'm currently building a small webapp that (due to reasons beyond my control) has to be capable of running on an old server/container that only supports Servlet 2.5 and Java 6. There is also a requirement for the webapp configuration to be completely self-contained, so even system variables and/or JVM parameters cannot be used. The administrator just wants a .war file for each environment that can be dropped into the container for deployment.
I'm using Spring 4.x in my webapp. This is how I configured my application such that the active Maven profile is used to set the active Spring 4.x profile.
pom.xml file changes
I added the following bits to my POM file. My POM is using model version 4.0.0 and I'm running Maven 3.1.x when I do my builds.
<modelVersion>4.0.0</modelVersion>
...
<profiles>
<profile>
<id>dev</id>
<activation>
<!-- Default to dev so we avoid any accidents with prod! :) -->
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<!-- This can be a single value, or a comma-separated list -->
<spring.profiles.to.activate>dev</spring.profiles.to.activate>
</properties>
</profile>
<profile>
<id>uat</id>
<properties>
<!-- This can be a single value, or a comma-separated list -->
<spring.profiles.to.activate>uat</spring.profiles.to.activate>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<!-- This can be a single value, or a comma-separated list -->
<spring.profiles.to.activate>prod</spring.profiles.to.activate>
</properties>
</profile>
</profiles>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<webResources>
<webResource>
<filtering>true</filtering>
<directory>src/main/webapp</directory>
<includes>
<include>**/web.xml</include>
</includes>
</webResource>
</webResources>
<failOnMissingWebXml>true</failOnMissingWebXml>
</configuration>
</plugin>
...
</plugins>
</build>
web.xml file changes
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Setup for root Spring context
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-core-config.xml</param-value>
</context-param>
<!--
Jim Tough - 2016-11-30
Per Spring Framework guide: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-environment
...profiles may also be activated declaratively through the spring.profiles.active
property which may be specified through system environment variables, JVM system
properties, servlet context parameters in web.xml, or even as an entry in JNDI.
-->
<context-param>
<param-name>spring.profiles.active</param-name>
<param-value>${spring.profiles.to.activate}</param-value>
</context-param>
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
Now I can create Java-based configuration classes like the one below that will only be used when a particular Spring profile is active.
#Configuration
#Profile({"dev","default"})
#ComponentScan
#EnableTransactionManagement
#EnableSpringDataWebSupport
public class PersistenceContext {
// ...
}
spring boot plugin itself can help:
<profiles>
<profile>
<id>postgres</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jmxPort>9001</jmxPort>
<environmentVariables>
<SPRING_PROFILES_ACTIVE>postgres</SPRING_PROFILES_ACTIVE>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>h2</id>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jmxPort>9002</jmxPort>
<environmentVariables>
<SPRING_PROFILES_ACTIVE>h2</SPRING_PROFILES_ACTIVE>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
In the spring boot application, there are several ways to set profiles (dev, uat, prod, etc.)
For exmaple : You can add this in your property file:
spring.profiles.active=dev
Programmatically:
SpringApplication.setAdditionalProfiles("dev");
To specify what profiles are active, use this line
#ActiveProfiles("dev")
In a Unix environment
export spring_profiles_active=dev
Running the jar file with the dev profile.
java -jar -Dspring.profiles.active=dev JARNAME.jar
here JARNAME.jar means your application's jar
Related
I need to create different application properties for a spring boot project and include the proper one in the generated war. I'm able to generate a war, but no to include the proper file in it. I have different profiles created, and different application.properties following the pattern application-env.properties where env is (dev, cert...), all of then placed in src/main/resources but I'm not able to pick the proper one and include in the generated war, even including "-Dspring.profiles.active=cert" to define the profile active. The war is generated with all of them. Any idea?
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<build.profile.id>dev</build.profile.id>
<packaging.type>jar</packaging.type>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>
<profile>
<id>cert</id>
<properties>
<build.profile.id>cert</build.profile.id>
<spring.profiles.active>cert</spring.profiles.active>
<packaging.type>war</packaging.type>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
I am working on a spring-boot application. I have two profiles inside my POM, but when I am trying the build the project using clean install -Pdev its not reflecting the change in application.properties, it'll only reflect when I am using 'activeByDefault' tag in one of the profile.
<profiles>
<profile>
<id>dev</id>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
</profile>
<profile>
<id>release</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<activatedProperties>release</activatedProperties>
</properties>
</profile>
</profiles>
If I am running clean install -Pdev I am getting this in my application.properties.
activatedProperties=#activatedProperties#
If I am setting the <activeByDefault>true</activeByDefault> then I'll get the value inside application.properties.
activatedProperties=release.
The frustration is I am not able to use other profiles.
Add in your application.properties
spring.profiles.active=#activatedProperties#
If Maven doesn't find the directory which contains your application.properties file in runtime, you need to setup the Maven Resources Plugin to filter the directory.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
...
</build>
Or just add what profile you want to active in application.properties
spring.profiles.active=dev
NOTE: The Maven profile and the Spring profile are different things.
Little stuck here. I have a pom with 3 profiles. Theese profiles have different version name. I want to inject that version name into properties file when a specific profile is building.
My profiles:
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<projectVersion>DEV</projectVersion>
</properties>
</profile>
<profile>
<id>test</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<projectVersion>1.0.0-RC1</projectVersion>
</properties>
</profile>
<profile>
<id>prod</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<projectVersion>1.0.0-Final</projectVersion>
</properties>
</profile>
</profiles>
and filter.properties looks like this:
projectName = defaultName
versionName = defaultVersion
How to do that? Im building project by command:
mvn clean install -D profile_name
What you need to do is to add a new section to your <build> section of your POM file.
Like this:
<build>
<resources>
<resource>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
This will look inside the specified folder (src/main/resources) on the specified files **/*.properties and change the files when it encounters defined variables.
So in order to this work your propertie file must be this way:
projectName = ${defaultName}
versionName = ${defaultVersion}
Be aware with these variables name. Maven will replace it with the defined names by you or the names of the Maven structure like ${projectVersion} will be replaced by the <version>1.0</version> tag of your pom file.
So instead of using:
<properties>
<projectVersion>1.0.0-Final</projectVersion>
</properties>
Change the name (and the version) of this variable to something else like:
<properties>
<defaultVersion>1.0.0-Final</defaultVersion>
<defaultName>someName</defaultName>
</properties>
On all your profiles.
And just run your maven command as:
mvn install -Pprofilename
Be careful with the profiles you shown. All of them are active by default and this is a problem because they all define the same maven property. Instead, you should mark only one as active by default.
You also don't show <resources> filtering to process filter.properties, so this can be a mistake, as well.
And a final though, you are controlling artifact version on maven profiles. I don't think it is a good idea. Please read about maven-release-plugin.
We have a maven based Spring Web-Application. All the web-calls are Restful and need authentication. But for development purpose, it is a pain to do all the needful. So for the development cycle, it is preferred to not have any security.
Using a maven flag or something, how do we generate separate builds for production and development?
All the security related stuff are in web.xml and applicationContext.xml. We can have 2 copies (one for development and the other for production). In the maven build, what is the simplest way to include the necessary files and omit others.
PS: I have seen examples of doing above using assembly plugin. I do not need all that but just a simple way to do it. I am using maven-war-plugin to generate war file.
Use profiles. You define them in your pom.xml (see below) and then when you build you include them. For command line this is simply
mvn -P <profile> <target>
most IDE's provide a way to set a profile.
pom.xml:
<properties>
<!-- default -->
<webXmlPath>src\main\webapp\WEB-INF\web-test.xml</webXmlPath>
</properties>
<profiles>
<profile>
<id>Production</id>
<properties>
<webXmlPath>src\main\webapp\WEB-INF\web.xml</webXmlPath>
</properties>
<build>
<finalName>${artifactId}</finalName>
</build>
</profile>
<profile>
<id>Accept</id>
<properties>
<webXmlPath>src\main\webapp\WEB-INF\web-accept.xml</webXmlPath>
</properties>
<build>
<finalName>${artifactId}-accept</finalName>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<webXml>${webXmlPath}</webXml>
</configuration>
</plugin>
</plugins>
</build>
Three questions in decreasing order of importance - Links will do.
I need to read certain maven settings such as proxies, servers in my maven plugin. How do I read them from my plugin. I can read from .m2/settings.xml file but I think there must be an easier way (some API that already does it).
I see from developers cookbook there is a class org.apache.maven.project.MavenProject What dependency I need for this to be available in my plugin - I feel this would be good to have.
Is it possible to have my own properties in settings.xml say for example
<users> <user> <username>user_name1</username> <password>encrypted_password</password> </user></users>
How ?
PS: I am a beginner.
Update 1
I was able to create and read custom properties following Injecting POM Properties via Settings.xml. However I would like to have configuration similar to what cargo provides. E.g.
<servers>
<server>
<id>tomcat7_local</id>
<configuration>
<cargo.hostname>localhost</cargo.hostname>
<cargo.remote.uri>http://localhost:8080/manager/text</cargo.remote.uri>
<cargo.remote.username>my_username</cargo.remote.username>
<cargo.remote.password>my_password</cargo.remote.password>
<cargo.servlet.port>8080</cargo.servlet.port>
</configuration>
</server>
<server>
<id>tomcat6_local</id>
<configuration>
<cargo.hostname>localhost</cargo.hostname>
<cargo.remote.uri>http://localhost:8080/manager</cargo.remote.uri>
<cargo.remote.username>my_username</cargo.remote.username>
<cargo.remote.password>my_password</cargo.remote.password>
<cargo.servlet.port>8080</cargo.servlet.port>
</configuration>
</server>
</servers>
How do I achieve this. Have a kind of workaround for my 3rd problem not sure if its the right way.
Edit
Thanks Jordan002! I know I can have multiple profiles but I didn't know to use them. This way by having profiles I can set my variable's value or rather inject the value in my plugin by saying something like #Parameter(alias = "cargo.hostname")
private String hostname; But as I see, for cargo plugin all it requires is defined like below
<servers>
<server>
<id>someId</id>
<configuration>
<!-- Configurations are placed here -->
</configuration>
</servers>
Similarly, or may be not so similar as there is no configuration here
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>My_proxy_host</host>
<port>My_proxy_port</port>
</proxy>
</proxies>
is where I can put proxy information that maven uses. Now, I don't want to redefine it inside some profiles and I don't want to parse this file to get informations.
Further, I would like do something like cargo is doing. It lets me write all the configuration inside servers and in project's pom I only have to do following
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<configuration>
<container>
<containerId>tomcat7x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.server.settings>tomcat7_local</cargo.server.settings>
</properties>
</configuration>
<deployer>
<type>remote</type>
</deployer>
<deployables>
<deployable>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<type>war</type>
<properties>
<context>${project.artifactId}</context>
</properties>
</deployable>
</deployables>
</configuration>
</plugin>
And cargo picks up configurations(s) that I defined for tomcat7_local, no need to write a profile for this.
Inject the setttings component as described here http://maven.apache.org/plugin-tools/maven-plugin-tools-annotations/
Its in Maven core org.apache.maven:maven-core:3.0.5
use properties directly and not nested. e.g. http://maven.apache.org/examples/injecting-properties-via-settings.html
I'm not too familiar with the Cargo plugin, but from the documentation, it appears to be configurable as any other Maven plugin would be. What I would change from your 'Update 1' would be to make tomcat6 and tomcat7 profiles:
<profiles>
<profile>
<id>tomcat6_local</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<cargo.hostname>localhost</cargo.hostname>
<cargo.remote.uri>http://localhost:8080/manager/text</cargo.remote.uri>
<cargo.remote.username>my_username</cargo.remote.username>
<cargo.remote.password>my_password</cargo.remote.password>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</profile>
<profile>
<id>tomcat7_local</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<cargo.hostname>localhost</cargo.hostname>
<cargo.remote.uri>http://localhost:8080/manager</cargo.remote.uri>
<cargo.remote.username>my_username</cargo.remote.username>
<cargo.remote.password>my_password</cargo.remote.password>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</profile>
</profiles>
and indicate at run time which tomcat you would like to start/stop by passing in the appropriate profile:
mvn install -P tomcat6_local
Hope this helps.