Performance Tuning Spring Applications

In a new white paper from SpringSource, Adrian Colyer explains the runtime environment that Spring provides.

The Spring programming and configuration models are well understood and documented and used by hundreds of thousands of developers worldwide. This white paper was written for operations teams who manage those applications.

The first part of the white paper reviews the core responsibilities of the Spring kernel, these are:

Bootstrapping - creates an application context that provides the runtime context for an application.

Determining component configuration - determines which application components need to be created, how they are configured, and what supporting services they require. This step is also know as the blueprint stage, as service readiness is determined.

Instantiation, Configuration, and Assembly - using the blueprint, components can now be constructed when needed. This stage is paramount, as Spring needs to take into account dependencies between components, specific ordering, and construction mechanisms. Failures at this stage will leave the application inoperable.

Component Post Processing - components that are registered as post processors by Spring enterprise services and user servers are invoked.

Decoration - when cross cutting component behavior is specified, declaratively as aspects using the AOP namespace or annotated classes, the Spring kernel has additional tasks. The specified pointcuts need to be qualified and a proxy generated for the original component in order to decorate the component with the additional functionality.

Managing component life cycle and scope - as components may have different life cycles and scope, the Spring kernel continues to oversee creating, re-using, and destroying components.

The more interesting part of the white paper involves performance tuning Spring application. Like any application, the advise is to measure first using tools such as Apache JMeter, Selenium, JAMon, or hand crafting Spring AOP or AspectJ aspects.

Optimizations then fall into two major categories: establishing an effective blueprint (tuning your configuration), and making effective use of runtime facilities (optimizing your application design). Start off with the cleanest and clearest design, making full use of the facilities that Spring offers, and only deviate from this where the numbers show real benefit.

Establishing an effective blueprintTo establish an effective blueprint, you need to take advantage of your deployment platform, and keep environmental dependencies out of the Spring configuration. This is especially important when declaring database connectivity and JMS connections, where utilizing JNDI enables you to take full advantage of your deployment platform facilities. Other advise provided is:

Using Spring's PropertyPlaceholderConfigurer is excellent for externalizing configuration settings that may need to be changed by an operations team.

and

A good tip here is to use Spring's JMX export capabilities to define an MBean that exposes all of the configuration values via JMX. This enables you to connect to a running application and easily see the configuration values it is currently using.

Taking advantage of runtime optimizationsMany runtime production performance issues are tracked down to the persistence layer, and having a properly optimized database and data access layer is of utmost importance.

Strive for the right balance between eager and lazy loading strategies

Show the SQL statements in the logs

For batch style operations, bulk updates, or inserts, and stored procedures it's normally best to use JDBC (via Spring JDBC) than an ORM tool

Make the most of the features that your database offers

If you have an operation that contains entirely persistence logic (no business logic), consider moving it into the database as a stored procedure and invoke it via Spring JDBC

Read-only reference data can be kept in a cache in memory

Wrapping up the performance tuning section is a collection of other tuning and optimization tips gathered from some of SpringSource's consultants:

The retry support in the Spring Batch project can be used to retry failing operations (for example, an operation that has failed on an individual cluster node in an Oracle RAC). This can ease the operational burden by reducing the number of failures that bubble up to end users.

Don't underestimate the cost of web content rendering. You definitely want to do this outside of a transaction.