Spring Quick Start |
rate-7766455-65451
| Article Rating? |
|
|
|
Table of Contents
Introduction
This document describes the process of getting started clustering the Spring framework with Terracotta.
Further Reading
• For a deeper discussion of Terracotta for Spring, see the [Spring section] of the [Concept and Architecture Guide].
Installation
Unix/Linux
Download the Unix/Linux install kit for Terracotta and unzip and untar it. A typical location to use for a production deployment is the /usr/local directory. For testing purposes, your home directory is appropriate.
For information on the sample applications included with Terracotta DSO, view the samples.html file in the samples/spring directory.
Microsoft Windows
Download the Windows executable (.exe) install file for Terracotta and run it. The installer guides you through the process of installing the product.
If the same version of the product has been previously installed in the same directory, the installer will backup the existing installation and perform a new install. The installer will notify the user about the backup and display the location of the new backup directory.
The installation creates an uninstaller for removing the product. The uninstaller does not delete files modified or created after the installation. These files will need to be removed manually.
Configuring Terracotta for Spring
The heart of Terracotta for Spring is the XML configuration file. Terracotta for Spring does not have a Java API and does not require code changes or additions. Declaration of clustering behavior is externalized into the XML configuration file.
Configuration Options
Naming Web Application to Share
Typically, you use the name of the WAR file you want to share:
<jee-application name="SampleWebApp">
...
</jee-application>
If you are running a stand-alone application you can use the wildcard '*' as shown in the code sample below:
<jee-application name="*">
...
</jee-application>
Sharing Application Contexts
Each new instance of an application context (invocation to new ClassPathXmlApplicationContext(..) or similar), is a unique "logical" application context throughout the cluster.
<application-contexts>
<application-context>
<paths>
<path>config/inventory-bean-config.xml</path>
</paths>
<application-context>
<application-contexts>
An application context is identified by the set of bean definition files that are used to construct it. Each <path> element can be the full path from the root of the package (classpath root or web application root as defined for loading Spring context), or a pattern. The order of the <path> elements is unimportant but they must match the paths used to construct the application context exactly.
This same code shows an application context that is constructed from config/foo.xml and config/bar.xml:
ApplicationContext ac = new ClassPathXmlApplicationContext({
"config/foo.xml",
"config/bar.xml"
});
or in web.xml using Spring's ContextLoaderListener:
<web-app>
...
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/foo.xml
classpath:config/bar.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
...
Then in Terracotta config it should be as shown in the following code sample:
<application-contexts>
<application-context>
<paths>
<path>config/foo.xml</path>
<path>config/bar.xml</path>
</paths>
</application-context>
</application-contexts>
Here are some code examples of valid patterns. In this example, if the bean definition file resides in the package com/biz/webapp, then these are all valid patterns:
<path>com/biz/webapp/my-bean-config.xml</path>
<path>*/webapp/my-bean-config.xml</path>
<path>*/my-bean-config.xml</path>
However, if you are using patterns then you have to ensure that there are no other bean definition files that can match the pattern.
Naming Spring Beans to Share
The names of the Spring beans you want to share (for a specific application context).
<beans>
<bean name="myBean"/>
<bean name="txManager"/>
<bean name="securityManager"/>
...
</beans>
Naming Fields Not to Share
You can name the fields in a Spring bean that you do not want to share such as
which fields might hold on to resources on disk, for example.
<beans>
<bean name="myBean">
<non-distributed-field>dataSource</non-distributed-field>
</bean>
</beans>
Changes to non-distributed fields are not propagated to other JVMs. As an example, imagine that the bean myBean is defined as follows:
<bean name="myBean" class="com.biz.webapp.MyBeanImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
If the dataSource field is defined to be non-distributed then each myBean bean will be initialized with a reference to that JVM's DataSource.
Defining Spring Events to be Distributed
You can define if you want the Spring events to be distributed for a specific application context. You define the event classes that you are interested in distributing.
For example:
<distributed-events>
<distributed-event>org.comp.SomeEvent</distributed-event>
<distributed-event>*.SomeEvent</distributed-event>
<distributed-event>org.comp.Some*</distributed-event>
<distributed-event>org.comp.*</distributed-event>
<distributed-event>*</distributed-event>
</distributed-events>
You can use wildcards ('*'). The wildcards can be used either at the beginning, at the end, both at the end or the beginning, or solely as a wildcard.
Including Classes for Instrumentation
Terracotta is instrumenting the bytecode of the classes for the target application transparently at class load time. During instrumentation Terracotta inserts the clustering hooks needed to cluster the application.
When using Terracotta for Spring, explicit instrumentation is something that, in most cases, will not be a concern since Terracotta for Spring figures most of this out on the fly. Terracotta for Spring inspects the Spring bean configuration file, grabs the types for the beans that are marked as shared. It then includes this bean type as well as all types that are reachable from this bean type, e.g. it better navigates the type hierarchy up to java.lang.Object for the target bean type as well as for all references that are reachable from this bean type.
The only references that Terracotta Spring cannot resolve are the Java Collection types such as java.util.ArrayList, java.util.HashMap, etc. In these cases you will have to explicitly define which classes Terracotta for Spring needs to instrument. This means all non-resolvable types that will potentially join the clustered object e.g., those reachable from the shared bean instance, have to be included for instrumentation in the XML configuration file.
<instrumented-classes>
<include>
<class-expression>com.biz.webapp..*</class-expression>
</include>
</instrumented-classes>
You can define classes you want to include for instrumentation by using AOP-style pattern matching:
| Pattern |
Matches |
| * |
Exactly one class or package |
| .. |
Eagerly zero or more packages |
Turning on Session Clustering
Use the <session-support> element if you want to turn on HTTP session clustering or Spring Web Flow support.
<session-support>true</session-support>
Defining Locks
Generally, locking is not something you have to configure. By default, Terracotta manages all locking for instrumented classes (bean types and types reachable from the bean, for example). However, what you have to ensure is that you have written a correct multi-threaded application. E.g. if you modify the state of an instance that is part of a shared object graph, then this object needs to be protected by a synchronized block, e.g. the code has to be thread-safe. Terracotta will then turn this synchronized block into a cluster-wide lock. The same holds for wait(), notifyAll() etc.
There is one exception from the rule above: if you specify a certain set of classes for instrumentation explicitly (using a fully qualified name or pattern), then you also have to define the locking necessary for these classes. Locks are defined using AOP-style pointcuts.
<locks>
<autolock>
<method-expression>
* com.biz.webapp.MyBeanImpl.updateBar(..)
</method-expression>
<lock-level>write</lock-level>
</autolock>
<named-lock>
<lock-name>lockTwo</lock-name>
<method-expression>
* com.biz.webapp.MyBeanImpl.getBar(..)
</method-expression>
<lock-level>read</lock-level>
</named-lock>
</locks>
Configuration File Example
Imagine that the web application has the following Spring configuration.
<web>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/services-applicationContext.xml
/WEB-INF/dao-applicationContext.xml
</param-value>
</context-param>
...
</web-app>
</web>
Below is a complete example of how the corresponding Terracotta for Spring XML configuration file can look. The file is a bit verbose, but illustrates everything you can do.
In the beginning of the file are some mandatory general server and client settings, such as hostname and log directories. Following the server and client settings come the different applications and how they are defined as described in detail above.
<?xml version="1.0" encoding="UTF-8"?>
<tc:tc-config xmlns:tc="http://www.terracotta.org/config">
<system>
<configuration-model>development</configuration-model>
</system>
<clients>
<logs>%d/client-logs-%h</logs>
</clients>
<servers>
<server name="localhost" />
</servers>
<application>
<spring>
<jee-application name="SampleWebApp">
<instrumented-classes>
<include>
<class-expression>com.biz.webapp..*</class-expression>
</include>
</instrumented-classes>
<session-support>true</session-support>
<fast-proxy>true</fast-proxy>
<application-contexts>
<application-context>
<paths>
<path>/WEB-INF/services-applicationContext.xml</path>
<path>/WEB-INF/dao-applicationContext.xml</path>
</paths>
<distributed-events>
<distributed-event>com.biz.MyEvent1</distributed-event>
<distributed-event>com.biz.MyEvent2</distributed-event>
</distributed-events>
<beans>
<bean name="service1"/>
<bean name="service2"/>
<bean name="dao1">
<non-distributed-field>
connectionPool
</non-distributed-field>
</bean>
<bean name="dao2"/>
</beans>
</application-context>
</application-contexts>
<locks>
<autolock>
<method-expression>
* com.biz.webapp.MyFoo.updateBar(..)
</method-expression>
<lock-level>write</lock-level>
</autolock>
</locks>
</jee-application>
</spring>
</application>
</tc:tc-config>
Enabling Terracotta for Spring in Applications
To enable Terracotta for Spring in your application you need to modify how you start up the application (or application server if you are using one). You can use either the Java wrapper script that ships with Terracotta for Spring, which is the simplest, or you can feed the regular invocation with some additional options.
Using the Java Wrapper Script
Terracotta for Spring ships with a startup script that should be used as a drop-in replacement to the regular java command. The name of the script is dso-java and can be found in the bin directory in the distribution.
To use the recommended Terracotta startup script:
- Find the (dso-java) script in the bin directory
- Replace the regular invocation to java with the invocation to dso-java.
Using Additional JVM Options
To use additional JVM options for applications inside the web container, perform the following:
- Prepend the Terracotta boot Jar to the Java bootclasspath
- Define the path to the Terracotta configuration file
Here is an example (assuming you are running Windows):
Sample Applications
Terracotta for Spring sample applications are included in the samples/spring directory. These samples illustrate how to cluster with Terracotta and show by example ways you can cluster your own applications.
Web Flow
The Web Flow sample application shows how Spring Web Flow with continuation support can be clustered with Terracotta for Spring to enable failover of the conversation state.
A four-step conversation flow requires that you answer simple questions at each conversation stage. As you use the Back, Forward and Refresh browser buttons to navigate through the conversation, you can stop and start the individual web server nodes that make up the cluster. The application continues to work as expected, since Terracotta for Spring keeps your conversation available and intact, regardless of which server node actually handles your request (a load balancer round-robins each web request to a different server node).
For instructions on running the Web Flow sample application, consult the readme.html file in the samples/spring/webflow directory.
Thread Coordination
The Thread Coordination sample application shows how to use Terracotta for Spring to coordinate processes across a cluster of nodes using standard Java synchronization.
When each web server node in the sample starts, it creates a Spring bean that increments a counter every second. The counter is protected from multi-threaded access using Java synchronization, such that only one thread at a time may increment the counter. Terracotta for Spring clusters this Spring bean across all web server nodes, keeping the synchronization semantics the same across all threads in the cluster.
In this demonstration, the web server node that first enters the synchronized portion of the code is said to be "active," while the other web server nodes that are waiting to enter the synchronized block are said to be "passive." By viewing each web server you can see which is active and which is passive; as you bring down the active web server node you can see the passive node switch to active as the synchronization lock is made available.
For instructions on running the Thread Coordination sample application, consult the readme.html file in the samples/spring/coordination directory.
Events
The Events sample application shows how to use Terracotta for Spring to propagate ApplicationContext events across the cluster.
It is a simple Spring web application that takes as input a text message and publishes it as an event to its application context. Terracotta for Spring clusters the application context and the events published to it. As you refresh the list of published messages on each of the web server nodes, you can see that they all receive the events published by other nodes.
For instructions on running the Events sample application, consult the readme.html file in the samples/spring/events directory.
JMX
The JMX sample application shows how to use Terracotta for Spring to cluster Spring beans and AOP Advices and how to expose clustered data through JMX.
The application has a Spring bean that increments one of two counters, depending on which Increment button is pressed in the UI. One counter is configured to be transparently clustered with Terracotta for Spring, while the other is left alone and is "local" to each web server node.
Additionally, the Spring bean is advised using an AOP interceptor which keeps track of the increment history of each counter – this history is also configured to be clustered with Terracotta for Spring.
All of these components are published to JMX via the Spring framework. By using a JMX compliant tool (such as JConsole which ships with the 1.5 version JDKs) you can view and verify the local verses clustered data.
For instructions on running the JMX sample application, consult the readme.html file in the samples/spring/jmx directory.