ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

J2EE Without the Application Server
Pages: 1, 2, 3, 4, 5, 6, 7

Step 4: Adding Declarative Transaction Management

Spring allows us to add declarative transaction management to any configured Java object. Suppose we want to make sure that the bank is always called with a valid transaction context. We do this by configuring a proxy object on top of the actual object. The proxy has the same interface as the actual object, so clients can use it in exactly the same way. The proxy can be configured to wrap each BankDAO method call in a transaction. The resulting configuration file is shown below. Don't be scared by the apparent volume of XML--most of the content can be reused by copying and pasting into your own projects.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
"http://www.springframework.org
/dtd/spring-beans.dtd">
<beans>
    <!-- 
        Use a JTA-aware DataSource 
        to access the DB transactionally 
    -->
    <bean id="datasource" 
        class="com.atomikos.jdbc.nonxa.NonXADataSourceBean">
        <property name="user">
            <value>sa</value>
        </property>
        <property name="url">
            <value>jdbc:hsqldb:SpringNonXADB</value>
        </property>
        <property name="driverClassName">
            <value>org.hsqldb.jdbcDriver</value>
        </property>
        <property name="poolSize">
            <value>1</value>
        </property>
        <property name="connectionTimeout">
            <value>60</value>
        </property>
    </bean>
    <!-- 
    Construct a TransactionManager, 
    needed to configure Spring 
    -->
    <bean id="jtaTransactionManager" 
        class="com.atomikos.icatch.jta.UserTransactionManager"/>
    <!-- 
    Also configure a UserTransaction, 
    needed to configure Spring  
    -->
    
    <bean id="jtaUserTransaction" 
        class="com.atomikos.icatch.jta.UserTransactionImp"/>
    <!-- 
    Configure the Spring framework to use 
    JTA transactions from the JTA provider 
    -->
    <bean id="springTransactionManager" 
    class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <ref bean="jtaTransactionManager"/>
        </property>
        <property name="userTransaction">
            <ref bean="jtaUserTransaction"/>
        </property>
    </bean>
    <!-- Configure the bank to use our datasource -->
    <bean id="bankTarget" class="jdbc.Bank">
        <property name="dataSource">
            <ref bean="datasource"/>
        </property>
    </bean>
    <!-- 
    Configure Spring to insert 
    JTA transaction logic for all methods 
    -->
    <bean id="bank" 
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="springTransactionManager"/>
        </property>
        <property name="target">
            <ref bean="bankTarget"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">
                    PROPAGATION_REQUIRED, -Exception
                </prop>
            </props>
        </property>
    </bean>
</beans>

This XML file tells Spring to configure the following objects:

  1. The datasource needed to connect via JDBC.
  2. The jtaTransactionManager and jtaUserTransaction objects have been added to prepare for Spring's configuration for JTA transactions.
  3. The springTransactionManager object has been added to tell Spring it needs to use JTA.
  4. The BankDAO has been renamed to bankTarget (for the reason explained below).
  5. The bank object has been added to wrap transactions around all of the methods of the bankTarget. We configured the bank object to use the springTransactionManager, meaning that all transactions will be JTA transactions. The transaction setting is PROPAGATION_REQUIRED for each method, and rollback is forced on any Exception.

Of all of these objects, you can easily copy and paste jtaTransactionManager, jtaUserTransaction, and springTransactionManager to other projects. The only application-specific objects are the datasource, the bankTarget, and the bank. The bank object is interesting: it is in fact a proxy to the bankTarget; it assumes the same interface. The trick is the following: when our application asks Spring to configure and return the object called bank, Spring will actually return the proxy (which looks exactly the same to our application) and this proxy will start/end transactions for us. This way, neither the application nor the Bank class itself needs to know JTA! Figure 4 illustrates what we get at this stage.

Architecture with CMT
Figure 4. Architecture with declarative JTA transactions in Spring

Things now work as follows:

  1. The application retrieves the object named bank. This triggers the Spring initialization process and the proxy is returned. To the application, this proxy looks and behaves like an instance of our Bank class.
  2. When a method of the bank is called, this call goes via the proxy.
  3. The proxy uses the springTransactionManager to create a new transaction.
  4. The springTransactionManager was configured to use JTA, so it delegates to the JTA.
  5. The call is now forwarded to the actual Bank, named bankTarget.
  6. The bankTarget uses the datasource it received from Spring.
  7. The datasource registers with the transaction.
  8. The database access happens via regular JDBC.
  9. Upon returning, the proxy terminates the transaction: if no exception happened in the previous sequence, then the termination instruction is commit. Otherwise, it will be rollback.
  10. The transaction manager coordinates commit (or rollback) with the database.

How about testing at this stage? We can reuse the BankTest with its explicit transaction demarcation: because of the PROPAGATION_REQUIRED setting, the proxy will execute with the transaction context created in the BankTest.

Pages: 1, 2, 3, 4, 5, 6, 7

Next Pagearrow