3

I was wondering if it's possible to somehow conditionally include spring beans depending on some property.

In my applicationContext.xml I have a list of beans that I setup:

<bean id="server1Config" class="... />
<bean id="server2Config" class="... />
<bean id="server3Config" class="... />
...

Then I include them in a list:

<bean class="java.util.ArrayList">
        <constructor-arg>
            <list>
                <ref bean="server1Config"/>
                <ref bean="server2Config"/>
                <ref bean="server3Config"/>
                ...
            </list>
    </constructor-arg>
</bean>

I want to conditionally include server1Config, server2Config, server3Config, etc depending on whether ${includeServer1} == true, ${includeServer2} == true etc and if possible, only initialize those beans if they are marked for inclusion.

To clarify, it's a ping service checking if servers are online or not, each bean contains special urls. If I have 5 servers running, I'd like to set in my config includeServer1=true ... includeServer5=true ... includeServer6=false, if I shutdown server2, I'd like to change includeServer2=false before shutting down the server to not get bombarded with SMSe telling me server2 is offline.

Jan Vladimir Mostert
  • 12,380
  • 15
  • 80
  • 137

4 Answers4

5

As your names refer to different stages or enviroments, spring profiles might be helpful to use. You can define beans like this inside your context.xml

<beans profile="dev">
    <jdbc:embedded-database id="dataSource">
        <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
        <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
    </jdbc:embedded-database>
</beans>

<beans profile="production">
    <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
</beans>

In the example [1] you see the usage of two profiles called "dev" and "production".

  • Spring will always load every bean without a profile
  • Depending on the profiles (yes, you can load multiple profiles at once) all the related beans will be loaded

Loading a profile in Java:

ctx.getEnvironment().setActiveProfiles("dev");

Loading two profiles

ctx.getEnvironment().setActiveProfiles("profile1", "profile2");

Loading from CMD Line declaratively:

-Dspring.profiles.active="profile1,profile2"

Usage in web.xml (can be comma-separated)

  <servlet>
      <servlet-name>dispatcher</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <init-param>
          <param-name>spring.profiles.active</param-name>
          <param-value>production</param-value>
      </init-param>
  </servlet>

@Comment: If you want to do it using properties and you are able to use newer spring elements, annotations etc. please have a look at this tutorial [2] to make it work with properties file as you commented below.

[1] http://spring.io/blog/2011/02/11/spring-framework-3-1-m1-released/ [2] http://kielczewski.eu/2013/11/setting-active-profile-and-property-sources-in-spring-mvc/

swinkler
  • 1,703
  • 10
  • 20
  • I'm compiling to a war file and the server I'm deploying to only has a Tomcat Admin panel, so no command line access. Is there a way to set the profile in XML via a properties file? Something like – Jan Vladimir Mostert May 04 '15 at 15:32
  • 1
    Updated regarding your question – swinkler May 04 '15 at 15:34
  • Is web.xml the only way to set spring profiles ? Still a potential solution if I can exclude things from the list using profiles, how would I exclude items from the ArrayList, or will they automatically be excluded if their beans doesn't match the profile? – Jan Vladimir Mostert May 04 '15 at 15:38
  • As far as I know only for spring boot is a mechanism available where you can place the property inside the application.properties and it will automatically be loaded (http://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html) But as far as I can see you don't use this. If you use spring in a web application, the context is loaded by spring based on the web.xml - do you see any obstacles with this solution for your application? – swinkler May 04 '15 at 15:46
  • The only place I currently need to update config is in application.properties which I include via ``, so was hoping for a solution where I can commit applicationContext.xml, never touch it again and only modify myapp.properties – Jan Vladimir Mostert May 04 '15 at 15:48
  • 1
    Here is another solution if you work with annotations or consider to switch to - http://stackoverflow.com/questions/8587489/how-to-set-active-spring-3-1-environment-profile-via-a-properites-file-and-not-v – swinkler May 04 '15 at 15:48
4

This is almost an add-on to @swinkler's answer.

He gave the first part of the solution which is usage of Spring 3.1+ profiles.

The second part would be to use a kind of automatic registration :

<bean class="java.util.ArrayList" id="serverConfigList"/>
<beans profile="server1">
    <bean id="server1Config" class="... />
    <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject"><ref local="serverConfigList"/></property>
        <property name="targetMethod"><value>add</value></property>
        <property name="arguments"><ref local="server1Config/></property>
    </bean>
</beans>

That way you create an empy list and only add relevant configs to it.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
2

Your code shouldn't change based on environment. If your aim is to use different settings for each environment then load them as properties at start up.

Refer this for 'external configuration'

K139
  • 3,654
  • 13
  • 17
1

This can be done in Spring framework 3.1 onwards using a built in Spring environment profiles.

Here's a few resources: http://java.dzone.com/articles/spring-31-environment-profiles

Hope this helps.

Ashoka
  • 935
  • 7
  • 20
  • Spring Profiles is a potential solution now that I found out I can load multiple profiles. I can see how I would exclude beans from being initialized, will that automatically exclude them from the list or will they be inserted as null into the list if their profile doesn't match? – Jan Vladimir Mostert May 04 '15 at 15:43