Configuring Spring depending on the deployment environment

June 30, 2007

The central idea in Spring is to promote loose coupling and avoiding to tie the application code to the environment it is going to be deployed in. For example, whether your DAO’s database connection is retrieved from JNDI our is coming from a driver directly is neatly configured in the application context without the DAO having to be aware of this. A common entry in the application context file is:

<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/my_db" />
<property name="username" value="my_name" />
<property name="password" value="my_pwd" />
<bean>

This configures a datasource bean that is later going to be injected a number of DAO beans. All the DAO has to know is that it operates on some kind of datasource. It doesn’t need to concern itself where the datasource is coming from.

This is very well during development, but at a certain moment the application is going to be deployed in a different environment. At that time some of the configuration of the application likely needs changes. In our example the database username and password are probably different in acceptance and production. Also some input or output file can be in a different location or some thresholds are different, etc. However, Since those settings are in a Spring configuration file that is typically deployed inside the application jar or war, this would require making a special build for each deployment environment. People are doing this, but it’s not an ideal situation in my opinion.

Luckily, Spring has a PropertyPlaceholderConfigurer that enables us to get rid of the exact values of properties (and other string literals). It enables us to convert the above fragment to:

<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>

The support for this is enabled by adding a bean definition like this:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="
classpath:env.properties"/>
</bean>

We have now gained that the database configuration is read from a property file in the classpath. However, that really doesn’t bring all that much closer to our goal of avoiding environment specific builds. We still have to put the property file on the classpath, thus presumably still in some deployed resource, if not the original jar/war.

A bit better is to use the file: prefix as in value="file:/etc/apps/myapp/env.properties". If you have a dedicated machine for each environment and all use the same directories, this might work. If there’s an indication of the environment in the path or the paths in the development is widely different in development (a windows laptop for example) and production (a 16-way Sun box perhaps) this still won’t be good enough.

Luckily there’s a somewhat hidden feature of Spring property values. I don’t know in what Spring version it was introduced and I can’t find it the documentation but if you use an attribute value of the form ${value}, Spring will look up value as a system property. Although this has the same syntax as the PropertyPlaceholderConfigurer, it follows a completely different code path. Anyway, if we set the location property to file:${myapp_config_basepath}/env.properties and define a system variable myapp_config_basepath on the VM that is hosting the application, we achieved what we were striving for: a single jar/war that can be deployed unchanged in all application environments and that still can be configured based on a property file that is located wherever the system administrator fancies. There may be other application specific ways of achieving this, but the above solution has the merit of working everywhere (if the security manager is not being unusually strict).


A Spring timing proxy

November 3, 2006

When developing a multi-tiered application it’s good to have an idea about the performance characteristics of the tiers. One way to do that is by running the application in a profiler. That requires some infrastructure that may not by easily available to every project however. Setting up the profiler may be non-trivial too.

Spring’s AOP capabilities provide a poor man’s alternative. We can write a proxy that records the time elapsed between method invocation start and end. Together with the controllable logging of log4j we can adequately pinpoint the slower parts of our application. In particular in the case of the typical Java web application with a clean separation between application flow, business logic and data access. At a certain stage in the development, it’s the database layer that is the most expensive part of processing a request. So knowing just which parts are most time consuming is valuable information.

We could hard-code the timing logic in the DAO methods itself, but that would be both tedious, error-prone and a permanent performance loss. Logging is the prototypical AOP example and Spring makes it easy to implement this. When using a design based on Spring, chances are that the DAO’s in the data access layer are bridged to the business logic through dependency injection.

Suppose all DAO’s are in a package named DAO, then the following Spring configuration fragment will advise all accesses of the DAO interfaces.

 <bean
    class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

  <bean id="timingAdvisor"
    class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
      <ref local="timingLogger" />
    </property>
    <property name="patterns">
      <list>
        <value>.*DAO.*</value>
      </list>
    </property>

  </bean>  <bean id="timingLogger"
    class="net.premereur.npps.services.oper.logging.TimingLoggingInterceptor"
    destroy-method="summary">
    <property name="logName" value="trace.SQLTimer" />
    <property name="debugThreshold" value="5" />
    <property name="infoThreshold" value="50" />
    <property name="warnThreshold" value="150" />
  </bean>

The first bean instructs the Spring AOP system (I’m not using the new AspectJ integration here) to look for beans that provide advice and potentially apply it to all Spring managed beans.

The second tag sets up an advisor that uses regular expression matching on the fully qualified name of methods. In this case anything with DAO in it will be matched. Since the DAO package is aptly named DAO in my case this will fulfill its role well. Note that there will be a double match because the DAO’s themselves have names ending in DAO as well. That doesn’t hurt of course. The advice is a reference to the third bean.

The timingLogger is an instance of TimingLoggingInterceptor that is configured with the name of the logger that is to be used. Indeed, it doesn’t make sense logging under the name of the Interceptor. Better to use a name that is a bit easier on the eyes. Also, it allows us to group other instrumentation logs (maybe in another blog) together. Even more interesting is the specification of the logging thresholds. The application will probably make a lot of short transactions that we don’t want to log as we will mostly focus on the long-running queries. In the present configuration, anything above 150 milliseconds will be logged at the warn facility. If we’re not interested in the shorter-running queries, we can configure the logging system not to display those. Just try to consistently implement that in each and every DAO method!

To conclude, the non completely trivial parts of the interceptor implementation:

public Object invoke(MethodInvocation invocation) throws Throwable {
  long start = System.currentTimeMillis();
  try {
    return invocation.proceed();
  } finally {
    long interval = System.currentTimeMillis() - start;
    if (interval > longestCall) {
      longestCall = interval;
    }
    if (interval < shortestCall) {
      shortestCall = interval;
    }
    averageCall = (averageCall * numCalls + interval) / (numCalls + 1);
    ++numCalls;
    try {
      if (interval >= warnThreshold && logger.isWarnEnabled()) {
        logger.warn(invocation.getMethod().getName() + ", " + interval);
      } else if (interval >= infoThreshold && logger.isInfoEnabled()) {
        logger.info(invocation.getMethod().getName() + ", " + interval);
      } else if (interval >= debugThreshold && logger.isDebugEnabled()) {
        logger.debug(invocation.getMethod().getName() + ", " + interval);
      }
    } catch (Exception e) {
      // Logging should never break things
    }
  }
}

As an added bonus, this implementation also records some simple statistics on all advised invocations. That’s where the destroy-method attribute in the bean specification is for. Upon shut-down of the application it will log the statistics as in:

public void summary() throws Exception {
  if (logger.isInfoEnabled()) {
    logger.info("Call statistics");
    logger.info("Number of calls : " + numCalls);
    if (numCalls > 0) {
      logger.info("Shortest call : " + shortestCall + "ms");
      logger.info("Longest call : " + longestCall + "ms");
    }
    logger.info("Average call : " + averageCall + "ms");
  }
}

This more useful for e.g. running unit tests than for running inside an application container since the only time the statistics are printed is right before the application stops. One can easily enhance this with Quartz to periodically dump the statistics or with JMX to request them at will. For the moment the need isn’t here…


Session scoped Spring beans in Tapestry

November 1, 2006

The new Spring 2.0 introduces 3 new bean scopes useful in developing web applications: request, session & application. Yesterday, I had the opportunity of trying this on my Tapestry 4.0 application. What I needed was letting DAO beans know what user was logged in so that they can add accounting information to the records in the DB. Since this is a separate concern from just storing data I didn’t want to introduce this information in business object properties or pass it through parameter values. The typical thing to do then is to use some kind of thread-local storage. However, why fiddle with the JDK ThreadLocalStorage if Spring can do this for you? So, let’s simply inject a session-scoped bean with the account information in the DAO beans.
Obviously, the actual value of the account name has to be stored in the session as well. The logical place for this in the login page. Tapestry isn’t too fond of working with the http session directly. Luckily, when using session-scoped beans that isn’t necessary. All you need to do is inject the spring bean into the logon page like this:

public abstract String getLogin();

@InjectObject("spring:executionEnvironment")
public abstract ExecutionEnvironment getExecutionEnvironment();

In case you’re wondering, the spring: prefix is contributed by the tapestry-spring module by HLS.
And then after authentication:

getExecutionEnvironment().setCurrentUserId(getLogin());

Together with this fragment in the Spring applicationContext.xml file:

<bean id="executionEnvironment"
      class="....env.SettableExecutionEnvironment"
      scope="session">
<aop:scoped-proxy />
</bean>

As it says in the Spring documentation the aop:scoped-proxy tag is important to avoid that everyone shares the same executionContext bean (and thus also their account name!). Also remember that you’ll also have to include a cglib2 jar in /WEB-INF/lib. This is because an actual class is being proxied, not an interface.