Spring is a popular framework for developing Java™ applications. WebSphere® eXtreme Scale provides support to
allow Spring to manage eXtreme Scale transactions
and configure eXtreme Scale clients
and servers.
Native transactions with WebSphere eXtreme Scale
Spring provides
container-managed transactions along the style of a
Java Platform,
Enterprise Edition application server
but has the advantage that Springs mechanism can have different implementations
plugged in. This topic describes an
eXtreme Scale Platform Transaction
manager that can be used with Spring. This allows programmers to annotate
their POJOs (plain old Java objects)
and then have Spring automatically acquire Sessions from
eXtreme Scale and begin, commit,
rollback, suspend, and resume
eXtreme Scale transactions. Spring
transactions are described more fully in
Chapter 10 of the official Spring User Guide. The following explains how to create
an
eXtreme Scale transaction
manager and use it with annotated POJOs. It also explains
how to use this approach with client or local
eXtreme Scale as well as a collocated
Data Grid style application.
Creating a transaction manager
eXtreme Scale provides an implementation
of a Spring PlatformTransactionManager. This manager can provide managed
eXtreme Scale sessions to POJOs
managed by Spring. Through the use of annotations, Spring manages
those sessions for the POJOs in terms of transaction life cycle. The
following XML snippet shows how to create a transaction Manager:
<aop:aspectj-autoproxy/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="ObjectGridManager"
class="com.ibm.websphere.objectgrid.ObjectGridManagerFactory"
factory-method="getObjectGridManager"/>
<bean id="ObjectGrid"
factory-bean="ObjectGridManager"
factory-method="createObjectGrid"/>
<bean id="transactionManager"
class="com.ibm.websphere.objectgrid.spring.ObjectGridSpringFactory"
factory-method="getLocalPlatformTransactionManager"/>
</bean>
<bean id="Service" class="com.ibm.websphere.objectgrid.spring.test.TestService">
<property name="txManager" ref+"transactionManager"/>
</bean>
This shows the transactionManager bean being
declared and wired in to the Service bean that will use Spring transactions.
We will demonstrate this using annotations and this is the reason
for the tx:annotation clause at the beginning.
Obtaining an ObjectGrid Session for the current Spring
transaction
A POJO that has methods managed by Spring can now
obtain the ObjectGrid session for the current transaction using
Session s = txManager.getSession();
This
returns the session for the POJO to use. Beans participating in the
same transaction will receive the same session when they call this
method. Spring will automatically handle begin for the Session and
also automatically invoke commit or rollback when necessary. You can
obtain an ObjectGrid EntityManager also by simply calling getEntityManager
from the Session object.
A sample POJO using annotations
Here is a POJO
that uses annotations to declare its transactional intentions to Spring.
You can see the class has a class level annotation indicating all
methods by default should use REQUIRED transaction semantics. The
class implements an interface with a method for all methods on the
class. This is necessary for Spring AOP to work when it cannot do
bytecode weaving. The class has an instance variable txManager that
we wire to the ObjectGrid transaction manager using the Spring xml
file. Each method simply calls the txManager.getSession method to
obtain the Session to use for the method.The queryNewTx method is
annotated to indicate a REQUIRES_NEW semantic. This means any existing
transaction will be suspended and a new independent transaction created
for that method.
@Transactional(propagation=Propagation.REQUIRED)
public class TestService implements ITestService
{
SpringLocalTxManager txManager;
public TestService()
{
}
public void initialize()
throws ObjectGridException
{
Session s = txManager.getSession();
ObjectMap m = s.getMap("TEST");
m.insert("Hello", "Billy");
}
public void update(String updatedValue)
throws ObjectGridException
{
Session s = txManager.getSession();
System.out.println("Update using " + s);
ObjectMap m = s.getMap("TEST");
String v = (String)m.get("Hello");
m.update("Hello", updatedValue);
}
public String query()
throws ObjectGridException
{
Session s = txManager.getSession();
System.out.println("Query using " + s);
ObjectMap m = s.getMap("TEST");
return (String)m.get("Hello");
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
public String queryNewTx()
throws ObjectGridException
{
Session s = txManager.getSession();
System.out.println("QueryTX using " + s);
ObjectMap m = s.getMap("TEST");
return (String)m.get("Hello");
}
public void testRequiresNew(ITestService bean)
throws ObjectGridException
{
update("1");
String txValue = bean.query();
if(!txValue.equals("1"))
{
System.out.println("Requires didnt work");
throw new IllegalStateException("requires didn't work");
}
String committedValue = bean.queryNewTx();
if(committedValue.equals("1"))
{
System.out.println("Requires new didnt work");
throw new IllegalStateException("requires new didn't work");
}
}
public SpringLocalTxManager getTxManager() {
return txManager;
}
public void setTxManager(SpringLocalTxManager txManager) {
this.txManager = txManager;
}
}
Setting the ObjectGrid instance for a thread
A
single Java Virtual Machine
(JVM) can host many ObjectGrid instances. Each primary shard placed
in a JVM has its own ObjectGrid instance. A JVM acting as a client
to a remote ObjectGrid uses an ObjectGrid instance returned from the
connect method's ClientClusterContext to interact with that Grid.
Before invoking a method on a POJO using Spring transactions for ObjectGrid,
the thread must be primed with the ObjectGrid instance to use. The
TransactionManager instance has a method allowing a specific ObjectGrid
instance to be specified. Once specified then any subsequent txManager.getSession
calls will returns Sessions for that ObjectGrid instance.
Simple bootstrap for testing
The following
example shows a sample main for exercising this capability:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]
{"applicationContext.xml"});
SpringLocalTxManager txManager = (SpringLocalTxManager)ctx.getBean("transactionManager");
txManager.setObjectGridForThread(og);
ITestService s = (ITestService)ctx.getBean("Service");
s.initialize();
assertEquals(s.query(), "Billy");
s.update("Bobby");
assertEquals(s.query(), "Bobby");
System.out.println("Requires new test");
s.testRequiresNew(s);
assertEquals(s.query(), "1");
Here we use a Spring
ApplicationContext. The ApplicationContext is used to obtain a reference
to the txManager and specify an ObjectGrid to use on this thread.
The code then obtains a reference to the service and invokes methods
on it. Each method call at this level causes Spring to create a Session
and do begin/commit calls around the method call. Any exceptions will
cause a rollback.
New eXtreme Scale interfaces
This introduces a single new interface,
SpringLocalTxManager. This interface is implemented by the ObjectGrid
Platform Transaction Manager and has all public interfaces. The methods
on this interface are for selecting the ObjectGrid instance to use
on a thread and obtaining a Session for the thread. Any POJOs using
ObjectGrid local transactions should be injected with a reference
to this manager instance and only a single instance need be created,
that is, its scope should be singleton.This instance is created using
a static method on ObjectGridSpringFactory. getLocalPlatformTransactionManager().
eXtreme Scale for JTA and global transactions
eXtreme Scale does
not support JTA or 2 phase commit for various reasons mainly to do
with scalability. Thus, except at a last single-phase participant,
ObjectGrid does not interact in XA or JTA type global transactions.
This platform manager is intended to make using local ObjectGrid transactions
as easy as possible for Spring developers.
Spring managed extension beans
ObjectGrid includes
an approach to declare POJOs to use as extension points in the objectgrid.xml
file. ObjectGrid provides a way to name the beans and then specify
the class name. ObjectGrid normally creates instances of the specified
class and uses those instances as the plug-in. ObjectGrid can now
delegate to Spring to act as the bean factory for obtaining instances
of these plug-in objects. If an application uses Spring then typically
such POJOs have a requirement to be wired in to the rest of the application.
ObjectGrid
has been modified to allow an application to register a Spring Bean
Factory instance to use for a specific named ObjectGrid. The application
should create an instance of BeanFactory or a Spring application context
and then register it with ObjectGrid using the following static method:
void registerSpringBeanFactoryAdapter(String objectGridName, Object springBeanFactory)
This
method specifies that if ObjectGrid finds an extension bean (such
as an ObjectTransformer, Loader, TransactionCallback, and so on) whose
className begins with the prefix {spring} then use the remainder of
the name as a Spring Bean name and obtain the bean instance using
the Spring Bean Factory. ObjectGrid can also create a Spring bean
factory from a default spring xml configuration file. If no bean factory
was registered for a given ObjectGrid then ObjectGrid tries to find
an xml file called 'ObjectGridName'_spring.xml. For example, if your
grid is called GRID then the xml file is called '/GRID_spring.xml'
and should be in the class path in the root package. If this file
is found then ObjectGrid constructs an ApplicationContext using that
file and constructs beans from that bean factory. As example class
name would be:
"{spring}MyLoaderBean"
This would
cause ObjectGrid to ask Spring for a bean named "MyLoaderBean". This
approach can be used to specify Spring managed POJOs for any extension
point in ObjectGrid so long as the bean factory has been registered
up front. The ObjectGrid spring extensions are in the ogspring.jar
file. This jar file must be on the class path for spring support to
work due. If a JavaEE application running in an XD augmented ND then
the application should place the spring.jar file and its associated
files in the EAR modules. The ogspring.jar must also be placed in
the same location.
Spring Webflow
Spring Webflow stores its session
state in the HTTP Session by default. If a web application is configured
to use ObjectGrid for session management then ObjectGrid will be used
automatically by Spring to store this state and it will be made fault
tolerant in the same manner as the session.