How do I control spring injections that vary betwe

2020-03-24 07:45发布

I'm setting up a CI situation in which I will deploy my web app to a test environment. In this test environment, I want the business objects used by the app to be mocks of the real ones; the mocks will return static test data. I'm using this to run tests agains my ui. I'm controlling the injections of these business object dependencies with Spring; it's a struts 2 application, for what that's worth.

My question is Maven related, I think. What is the best way to have my Maven build determine whether or not to build the spring configuration out for injecting the mocks or injecting the real thing? Is this a good use for maven profiles? Other alternatives?

2条回答
三岁会撩人
2楼-- · 2020-03-24 08:25

Spring itself has support for profiles (if you're using 3.1 or newer), for a web-application you can use context-parameter to set the active profile for different environments in the web.xml:

<context-param>
   <param-name>spring.profiles.default</param-name>
   <param-value>test</param-value>
</context-param>

Edit: For Maven & Jenkins, you should be able to set the parameter for a build job as follows:

First, let Maven filter your xml-resources (in this example, only files ending with xml are filtered, others are included without filtering) by adding the following into your pom.xml inside the <build> </build> -tags:

    <resources>
        <resource>
            <directory>src/main/webapp</directory>
            <filtering>true</filtering>
            <includes>
                <include>**/*xml</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/webapp</directory>
            <filtering>false</filtering>
            <excludes>
                <exclude>**/*xml</exclude>
            </excludes>
        </resource>
    </resources> 

Then, parameterize the context-param in your web.xml:

<context-param>
   <param-name>spring.profiles.default</param-name>
   <param-value>${env.SPRINGPROFILE}</param-value>
</context-param>

Then parameterize the build job in Jenkins to set the desired string parameter for SPRINGPROFILE (for example test or prod): https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+Build

查看更多
孤傲高冷的网名
3楼-- · 2020-03-24 08:30

It's probably a bad idea to do anything with the build of the web app artifact ( Maven best practice for generating artifacts for multiple environments [prod, test, dev] with CI/Hudson support? ). While you could use various mechanisms to produce a WAR file with different configurations of the Spring injections for different contexts, the WAR artifact should be the same every time it's built.

In order to extract the configuration out of the WAR, I have used Spring 3's ability to pull in override values from an external property file. I define default, i.e. produciton, values of my business objects. And I configure spring to check for the existence of a properties file, something I will deploy when the app is in a testing environment and requires mock injections. If that properties file exists, it's values are injected instead. Here's the relevent bit of the spring config file.

<!-- These are the default values -->
    <util:properties id="defaultBeanClasses">
    <prop key="myManagerA">com.myco.ManagerAImpl</prop>
    <prop key="myManagerB">com.myco.ManagerBImpl</prop>
</util:properties>

<!-- Pull in the mock overrides if they exist. -->
<context:property-placeholder 
    location="file:///my/location/mockBeans.properties"
    ignore-resource-not-found="true"
    properties-ref="defaultBeanClasses"/>

<!-- The beans themselves. -->  
<bean id="managerA" class="${myManagerA}"/>
<bean id="managerB" class="${myManagerB}"/>

And here is the contents of the external "mockBeans.properties" file:

#Define mock implementations for core managers
myManagerA=com.myco.ManagerAMockImpl
myManagerB=com.myco.ManagerBMockImpl

This works nicely. You can even include the mockBeans.properties file in the actual WAR, if you like, but not in the live location. Then the test environment task would be too move it to the location pointed at by the spring config. Alternatively, you could have the mock properties reside in a completely different project.

查看更多
登录 后发表回答