Controlling a project with Maven and Spring: How to set Spring config file using Maven profiles?

[亡魂溺海] 提交于 2019-11-27 21:33:26

Do I need a .properties file?

Generally speaking, YES, you need to use .properties file, this is what we do usually, especially for handling database connection configuration in spring context file.

The purpose of .properties file is to provide the capability of configuring database connections at application runtime (for web application, usually require restarting application container/server after .properties file changes). This is usually done at application deployment/installation step in different environment (DEV/TEST/UAT/PROD).

It is not a good practice to store those database connection settings in pom.xml, as the purpose of pom.xml is for project description and only used once at application build time (e.g. mvn deploy). And for most of time, even though it is packed into the final jar/war file, we don't really care and touch it after application is built.

To use .properties file in spring context, define a propertyConfigurer bean in your applicationContext, for example:

<bean id="propertyConfigurer"
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations">
    <list>
      <!-- Default location inside war file -->
      <value>classpath:db.properties</value>
      <!-- Environment specific location, a fixed path on server -->
      <value>file:///opt/my-web-app/conf/db.properties</value>
    </list>
  </property>
  <property name="ignoreResourceNotFound" value="true"/>
</bean>

Hope this make sense.

Using what I learned from the two answers and my research, I was able to get a development/production system, controlled by the pom, that sets the correct database values.

First, in the pom, I created two profiles.

<!-- Production and Development Profiles -->

<profiles>
    <!-- Nike profile needs go here -->
    <profile>
        <id>production</id>
        <activation>
            <property>
                <name>environment.type</name>
                <value>prod</value>
            </property>
        </activation>
    </profile>

    <!-- Catalyst profile needs go here -->
    <profile>
        <id>development</id>
        <activation>
            <property>
                <name>environment.type</name>
                <value>dev</value>
            </property>
        </activation>

        <build>

            <!-- This holds the properties for the Spring context file.
                 Database values will be changes to development. -->
            <filters>
                <filter>src/main/resources/dev.database.properties</filter>
            </filters>

            <resources>

                <!-- This is the directory that holds the Spring context
                     file.  The entire folder is searched, so either no
                     other file should have place holders or you should
                     exclude other files from being filtered. -->
                <resource>
                    <directory>src/main/webapp/WEBINF/</directory>
                    <filtering>true</filtering>
                </resource>
            </resources>
    </profile>
</profiles>

In the servlet-context.xml, in the WEBINF directory, I put place holders:

<!-- For database, uses maven filtering to fill in placeholders -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db.driver}" />
    <property name="url"             value="${db.url}" />
    <property name="username"        value="${db.username}" />
    <property name="password"        value="${db.password}" />
    <property name="maxActive">
        <value>10</value>
    </property>
    <property name="maxIdle">
        <value>1</value>
    </property>
</bean>

Then I created a properties file to sit in src/main/resources

#
# Development database properties file
#
db.driver=oracle.jdbc.driver.OracleDriver
db.url=jdbc:oracle:thin:[USER/PASSWORD]@[HOST][:PORT]:SID
db.username=jsmith
db.password=s3cr3t

I can then start Maven with

mvn -P developement clean install

or have a settings.xml that sets the correct profile for me:

<settings>
  <profiles>
    <profile>
      <activation>
        <activeByDefault>true</activeByDefault>
      </activation>

      <properties>
        <environment.type>dev</environment.type>
      </properties>
    </profile>
  </profiles>   
</settings>
user311174

The main question is: how are you going to deploy your WAR file to the different environemnts?, via a RPM, a jenkins build, by hand?, also do you want the same WAR file to de deployed to all the environments?

a) you want your WAR to be deployed vi a JENKINS job (or manually through maven), just process your resources and use the profile in the build process of the jar (mvn -P production clean deploy), the maven pom should include code like this:

    <filters>
        <filter>${config.maven.plattform.resources}/environment/${config.environment.dir}/your_proyect.properties</filter>
    </filters>
    <resources>
        <resource>
            <directory>resources/servlet-context.xml</directory>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>target/generated-resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>

You should define your properties in the file your_proyect.properties (one per environment) and also define config.environment.dir for all your different profiles.

b) you want the same WAR/RPM, etc. for all your projects. Then you have to define the environemt as a property in the java startup of the application servert: -DENVIRONMENT=production and then load all the properties with a parametrized PropertyPlaceholderConfigurer as yorkw pointed out:

<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
        <value>classpath:environment/${ENVIRONMENT}/your_project.properties</value>
        </list>
    </property>
</bean>

Also remember to put all the properties in the WAR, the pom for the WAR build should include code like this:

                <execution>
                    <id>copy-env-resources</id>
                    <!-- here the phase you need -->
                    <phase>validate</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${basedir}/src/main/webapp/WEB-INF/classes/environment/</outputDirectory>
                        <overwrite>true</overwrite>
                        <resources>
                            <resource>
                                <directory>${basedir}/${build_to_all_your_environments}</directory>
                                <includes>
                                    <include>**/*.properties</include>
                                </includes>
                            </resource>
                        </resources>
                    </configuration>
                </execution>

c) A mixed one: you can manually choose an enviroment over the one defined as a property in the server (-D), you can get this by using default properties, if not found then resort to the one for that environemt, this step is quite convoluted as it requires another set of properties, if you're interested check my post: deployment for different environments with maven and spring, i'm also interested in a better solution for c)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!