【问题标题】:Controlling a project with Maven and Spring: How to set Spring config file using Maven profiles?使用 Maven 和 Spring 控制项目:如何使用 Maven 配置文件设置 Spring 配置文件?
【发布时间】:2012-08-06 02:58:15
【问题描述】:

我正在尝试根据某个 Maven 配置文件是否处于活动状态来配置包含数据库信息的 Spring 配置文件。我已经看到了这方面的一些答案,但我无法将它们放在一起。

我有一个这样的 Maven 配置文件:

<profiles>
    <profile>
        <id>production</id>
        <activation>
            <property>
                <name>environment.type</name>
                <value>prod</value>
            </property>
        </activation>
    </profile>

    <profile>
        <id>development</id>
        <activation>
            <property>
                <name>environment.type</name>
                <value>dev</value>
            </property>
        </activation>

        <!-- Database properties for Spring -->
        <properties>
            <db.driver>oracle.jdbc.driver.OracleDriver</db.driver>
            <db.type>oracle</db.type>
            <db.host>192.168.0.0</db.host>
            <db.port>1521</db.port>
            <db.name>myDb</db.name>
            <db.url>jdbc:${db.type}:thin:@${db.host}:${db.port}:${db.name}</db.url>
        </properties>

还有一个像这样的 settings.xml 文件:

<servers>
  <server>
    <id>development</id>
    <username>jsmith</username>
    <password>secret</password>
  </server>
</servers>

....

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

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

在 servlet-context.xml 中:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
    <property name="driverClassName">
        <value>${db.driver}</value>
    </property>

    <property name="url">
        <value>${db.url}</value>
    </property>

    <property name="username">
        <value>${db.username}</value>
    </property>

    <property name="password">
        <value>${db.password}</value>
    </property>

    <property name="maxActive">
        <value>10</value>
    </property>

    <property name="maxIdle">
        <value>1</value>
    </property>
</bean>

我的问题基本上是,如何将 Maven 属性放入 servlet-context.xml 文件中?我需要一个 .properties 文件吗?我对 Maven 中的过滤和 Spring 中的 PropertyPlaceholderConfigurer 了解一些,但我不知道如何将它们组合在一起——或者它们是否组合在一起?还是有更简单的方法?

【问题讨论】:

    标签: java spring maven configuration-files


    【解决方案1】:

    我需要一个 .properties 文件吗?

    一般来说,是的,你需要使用.properties文件,这是我们通常做的,尤其是在spring上下文文件中处理数据库连接配置。

    .properties 文件的目的是提供在应用程序运行时配置数据库连接的能力(对于 Web 应用程序,通常需要在 .properties 文件更改后重新启动应用程序容器/服务器)。这通常在不同环境(DEV/TEST/UAT/PROD)中的应用程序部署/安装步骤中完成。

    将这些数据库连接设置存储在 pom.xml 中并不是一个好习惯,因为 pom.xml 的目的是用于项目描述并且仅在应用程序构建时使用一次(例如 mvn deploy)。而且在大多数情况下,即使它被打包到最终的 jar/war 文件中,我们也不会真正关心并在构建应用程序后对其进行修改。

    要在 spring 上下文中使用 .properties 文件,请在 applicationContext 中定义一个 propertyConfigurer bean,例如:

    <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>
    

    希望这是有道理的。

    【讨论】:

    • 可以,谢谢!我无法让我的 servlet-contect.xml “查看”配置文件。另外,有什么方法可以让 Maven 配置文件控制 servlet-context.xml 看到哪个配置文件?
    • 您的 applicationContext 将通过 PropertyPlaceholderConfigurer 看到配置文件。您可以使用 maven 配置文件来包含/排除特定的环境相关资源,但是,我们通常不会对配置文件执行此操作。
    • @yorkw 独立应用程序怎么样?为什么我不能即时更改独立应用程序的属性?
    【解决方案2】:

    利用我从两个答案和我的研究中学到的知识,我能够获得一个由 pom 控制的开发/生产系统,它可以设置正确的数据库值。

    首先,在 pom 中,我创建了两个配置文件。

    <!-- 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>
    

    在servlet-context.xml的WEBINF目录下,我放了占位符:

    <!-- 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>
    

    然后我创建了一个位于 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
    

    然后我可以使用 Maven 启动

    mvn -P developement clean install
    

    或者有一个 settings.xml 为我设置正确的配置文件:

    <settings>
      <profiles>
        <profile>
          <activation>
            <activeByDefault>true</activeByDefault>
          </activation>
    
          <properties>
            <environment.type>dev</environment.type>
          </properties>
        </profile>
      </profiles>   
    </settings>
    

    【讨论】:

      【解决方案3】:

      主要问题是:您将如何将 WAR 文件部署到不同的环境?通过 RPM、jenkins 构建,手动?您是否还希望将相同的 WAR 文件部署到所有环境?

      a)您希望通过 JENKINS 作业(或通过 maven 手动)部署您的 WAR,只需处理您的资源并在 jar(mvn -P production clean deploy)、maven pom 的构建过程中使用配置文件应该包括这样的代码:

          <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>
      

      您应该在 your_proyect.properties 文件中定义您的属性(每个环境一个),并为所有不同的配置文件定义 config.environment.dir。

      b) 您希望所有项目都使用相同的 WAR/RPM 等。然后,您必须在应用程序 servert 的 java 启动中将环境定义为属性:-DENVIRONMENT=production,然后使用 yorkw 指出的参数化 PropertyPlaceholderConfigurer 加载所有属性:

      <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>
      

      还记得把所有的属性都放在 WAR 中,WAR 构建的 pom 应该包含如下代码:

                      <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) 混合的:您可以手动选择一个环境而不是定义为服务器中属性的环境 (-D),您可以通过使用默认属性来获得它,如果找不到,则使用该环境的环境,这一步非常复杂,因为它需要另一组属性,如果您有兴趣查看我的帖子: deployment for different environments with maven and spring,我也对 c) 的更好解决方案感兴趣

      【讨论】:

      • 谢谢,我会试试的。在开发中,我们只是通过 Eclipse 运行 Tomcat 来运行应用程序,它需要指向开发数据库。对于生产,它将是 JBoss 中指向生产数据库的 WAR 文件。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-21
      • 1970-01-01
      • 1970-01-01
      • 2021-01-08
      • 2016-09-27
      • 2014-10-14
      • 1970-01-01
      相关资源
      最近更新 更多