New in Spring 3.1: Bean definition profiles at a glimpse

by Allard BuijzeJuly 13, 2011

The next major release of Spring Framework, 3.1, brings a new feature called bean definition profiles. This is a great add-on which makes the definition of the application context even easier, both in xml and Java-based style. With this new functionality it is possible to group beans into profiles which can be activated at runtime. I will show in this blog post how to leverage bean definition profiles, based on a monitoring use case.


Bean definition profiles where designed as a core mechanism allowing the use of different bean definitions in different circumstances. These different circumstances are usually a deployment on a different environment. It is quite a common need to have some beans defined when the application is deployed on a test environment and other ones when in acceptance or production. Stubbing external services, datasource definition (local vs. JNDI), notification mechanisms, just to name a few.

A profile is defined using the “profile” property of the “beans” element in the context definition. The rules are quite simple: Beans not belonging to any profile are always available in the application context. Beans defined in a profile are only included in the application context if the given profile is active. The profile(s) can be defined in the top-level beans element of the context definition or in an embedded beans element [2]. It is also possible to define multiple profiles at once [3]. Additionally the @Profile annotation can be used in @Configuration classes.

applicationContext-dev.xml [1]
<beans profile="dev">
	// beans
</bean>

applicationContext.xml [2]
<beans>
       // beans
    <beans profile="dev">
       // beans
    </beans>
    <beans profile="prod">
       // beans
    </beans>
</beans>

applicationContext-dev-acceptance.xml[3]
<beans profile="dev,acceptance">
      // beans
</bean>

Let’s analyze how we can leverage bean definition profiles in a real-life use case. We will spy on an application’s @Controllers to see how long it takes to handle the incoming requests. For the sake of this example let’s assume that logging of the times is enough. First, let’s write an aspect to intercept the method invocation and log the execution time:

public class ControllerAspect {

private static Logger logger = Logger.getLogger("monitor");

@Pointcut("within(@org.springframework.stereotype.Controller *)")
public void controllerBean() {
}

@Pointcut("execution(* *(..))")
public void methodPointcut() {
}

@Around("controllerBean() && methodPointcut()")
public Object aroundControllerMethods(ProceedingJoinPoint pjp) throws Throwable {
     String signature = pjp.getSignature().toShortString();
     StopWatch stopWatch = new StopWatch(signature);
     stopWatch.start();
     Object retVal = pjp.proceed();
     stopWatch.stop();
     logger.info(stopWatch.shortSummary());
     return retVal;
    }
}

We also need a controller to spy on. Let’s use this trivial implementation of an encoding controller:

@Controller
public class EncodingController {

private static final List<String> algorithms = Arrays.asList("MD5", "SHA");

@RequestMapping(value = "algorithms", method = RequestMethod.GET)
public ResponseEntity<String> supportedAlgorithms() throws InterruptedException, UnsupportedEncodingException, NoSuchAlgorithmException {
    return new ResponseEntity<String>("Supporter algorithms: " + algorithms.toString() , HttpStatus.OK);
}

@RequestMapping(value = "encode", method = RequestMethod.GET)
public ResponseEntity<String>; encode(@RequestParam("value") String value, @RequestParam("algorithm") String algorithm) throws InterruptedException, UnsupportedEncodingException, NoSuchAlgorithmException {
     if (!algorithms.contains(algorithm)) {
          return new ResponseEntity<String>("Algorithm not supported", HttpStatus.UNPROCESSABLE_ENTITY);
     }
    MessageDigest md = MessageDigest.getInstance(algorithm);
    byte[] digest = md.digest(value.getBytes());
    return new ResponseEntity<String>(String.valueOf(Hex.encodeHex(digest)), HttpStatus.OK);
    }
}

Once our aspect and controller code is ready we can move to defining a separate profile for the monitoring. We expect the monitoring to be on only in certain cases, for instance when deployed on a performance testing environment. This is where the bean definition profiles come into play. We will define the aspect in a separate profile which can be activated at runtime:

<beans profile="monitoring">
    <bean id="controllerAspect" class="nl.jteam.sample.aop.ControllerAspect"/>

    <aop:aspectj-autoproxy>
        <aop:include name="controllerAspect"/>
    </aop:aspectj-autoproxy>

</beans>

The “monitoring” profile can be easily activated by passing -Dspring.profiles.active=”monitoring” parameter to the Java VM. More than one profile can be activated by specifying a coma-separated list, eg. -Dspring.profiles.active=”profile1,profile2,profile3″. When running the application with the “monitoring” profile we should notice logs upon each request:

INFO [monitor] - <StopWatch 'EncodingController.supportedAlgorithms()':
                               running time (millis) = 1>
INFO [monitor] - <StopWatch 'EncodingController.encode(..)':
                               running time (millis) = 29>

To keep in mind:
– Do not use the profiles when the difference between the beans lies in properties. The PropertyPlaceholderConfigurer will do the job.
– Watch out for any functionality which could compromise your application when accidentally activated on a production environment.

A working project with the code from the above example can be cloned from github: https://github.com/annagos/beanprofiles-monitoring-sample