简体   繁体   中英

Spring application is loading properties from all of my properties files instead of just the ones I am specifying in context:property-placeholder

I have a spring application that I am attempting to configure differently for different deployment scenarios. For instance, for integration tests, I want my application to use an H2 in memory database, but for deployment to our pre-production environments, I want to configure a remote MySql datasource. After doing some digging around, I have landed on an approach that relies on using the element in my application context to specify the properties files that I would like to load. Here is the relevant snippet from my applicationContext.xml:

<context:property-placeholder location="classpath:META-INF/spring/database_${spring.profiles.active}.properties"/>

I then define the spring.profiles.active property in my maven POM file, like so:

<properties>
        <spring.profiles.active>localdev</spring.profiles.active>
        ...
</properties>

This will allow the property value to be available to my application when I run "mvn test" (which is how I have been executing my unit tests and attempting to resolve this issue)

I have several different database configuration properties files and they live side-by-side in my /src/main/resources/META-INF/spring folder, here is the relevant subset of my projects folder structure:

META-INF
|
+--spring
|  |
|  +--database_build.properties
|  +--database_localdev.propertes
|  +--applicationContext.xml
|
+--persistence.xml

And here are the contents of each of the two properties files:

database_build.properties

#Updated at Thu Apr 26 17:35:43 PDT 2012
#Thu Apr 26 17:35:43 PDT 2012
database.persistenceUnit=persistenceUnitH2
database.driverClassName=org.h2.Driver
database.url=jdbc\:h2\:mem\:;MODE=MySQL;INIT=create schema IF NOT EXISTS TTS_ADMIN;TRACE_LEVEL_SYSTEM_OUT=3
database.username=sa
database.password=

database_localdev.properties

#Updated at Thu Apr 26 17:35:43 PDT 2012
#Thu Apr 26 17:35:43 PDT 2012
database.persistenceUnit=persistenceUnitMySql
database.driverClassName=com.mysql.jdbc.Driver
database.url=jdbc\:mysql\://localhost\:3306/TTS_ADMIN
database.username=ttsaSchemaMgrUsr
database.password=password

And here is the relevant portions of the applicationContext.xml that references these property values to set up the datasource

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
        <property name="driverClassName" value="${database.driverClassName}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.username}"/>
        <property name="password" value="${database.password}"/>
        <property name="testOnBorrow" value="true"/>
        <property name="testOnReturn" value="true"/>
        <property name="testWhileIdle" value="true"/>
        <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
        <property name="numTestsPerEvictionRun" value="3"/>
        <property name="minEvictableIdleTimeMillis" value="1800000"/>
        <property name="validationQuery" value="SELECT 1"/>
</bean>
...
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="liquibase" id="entityManagerFactory">
        <property name="persistenceUnitName" value="${database.persistenceUnit}"/>
        <property name="dataSource" ref="dataSource"/>
</bean>

As you can tell from this configuration, the persistence unit to load is determine by the value of the database.persistenceUnit property. Here is my persistence.xml file with both persistence units defined:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <!-- An MySql persistence unit -->
    <persistence-unit name="persistenceUnitMySql" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
            <property name="hibernate.hbm2ddl.auto" value="validate"/>
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
            <property name="hibernate.connection.charSet" value="UTF-8"/>
            <!-- Uncomment the following two properties for JBoss only -->
            <!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
            <!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
        </properties>
    </persistence-unit>

    <!-- An in-memory persistence unit -->
    <persistence-unit name="persistenceUnitH2" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
            <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
            <property name="hibernate.connection.charSet" value="UTF-8"/>
            <!-- Uncomment the following two properties for JBoss only -->
            <!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
            <!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
        </properties>
    </persistence-unit>

</persistence>

Now, the problem is that regardless of whether or not I set the spring.profiles.active property to "build" or "localdev", I always get the property values for the database_localdev.properties file. I have turned on trace logging and I see the following lines in the log file when the active profile is "localdev":

2012-05-07 17:47:17,155 [main] INFO  org.springframework.context.support.PropertySourcesPlaceholderConfigurer - Loading properties file from class path resource [META-INF/spring/database_localdev.properties]

And I see this in the log file when the active profile is "build"

2012-05-07 17:47:17,155 [main] INFO  org.springframework.context.support.PropertySourcesPlaceholderConfigurer - Loading properties file from class path resource [META-INF/spring/database_build.properties]

So it would appear that spring.active.profile value is being honored and the correct file is being loaded as a result of my context:property-placeholder settings. However, the "build" file always seems to be loaded and always seems to take precedence over the properties defined in the "localdev" file. The only way I am able to get the property values in the "localdev" file to be honored is by commenting out all of the lines in the "build" file.

I am currently baffled by what is going on. Is there some other rule that I am not considering that would account for both of my properties files to be loaded?

EDIT The section of my POM related to resource-filtering and property processin:

<resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
...
                 <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>properties-maven-plugin</artifactId>
                <version>1.0-alpha-2</version>
                <executions>
                  <execution>
                    <phase>initialize</phase>
                    <goals>
                      <goal>read-project-properties</goal>
                    </goals>
                    <configuration>
                      <files>
                        <file>${basedir}/src/main/resources/META-INF/spring/database_build.properties</file>
                      </files>
                    </configuration>
                  </execution>
                </executions>
           </plugin>

It looks from the POM fragment, that you are filtering your resources, using properties always read from the database_build.properties file.

That would mean that the placeholders in the applicationContext.xml are filled by maven during the build using these properties, and there are none left for the placeholder configurer to really configure. Spring reads only the properties file you tell it to, but by then it is already too late.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM