581 lines
26 KiB
XML
581 lines
26 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!--
|
|
/*
|
|
* Copyright 2002-2008 the original author or authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
-->
|
|
<chapter version="5" xml:id="tx-quickstart"
|
|
xmlns="http://docbook.org/ns/docbook"
|
|
xmlns:ns6="http://www.w3.org/1999/xlink"
|
|
xmlns:ns5="http://www.w3.org/1998/Math/MathML"
|
|
xmlns:ns4="http://www.w3.org/2000/svg"
|
|
xmlns:ns3="http://www.w3.org/1999/xhtml"
|
|
xmlns:ns="http://docbook.org/ns/docbook">
|
|
<title>Transactions QuickStart</title>
|
|
|
|
<section>
|
|
<title>Introduction</title>
|
|
|
|
<para>The Transaction Quickstart demonstrates Spring's transaction
|
|
management features. The database schema are two simple tables, credit and
|
|
debit, which contain an Identifier and an Amount. The quick start shows
|
|
the use of declarative transactions using attributes and also the ability
|
|
to change the transaction manager (local or distributed) via changes to
|
|
only the configuration files - no code changes are required. It also
|
|
demonstrates some techniques for unit and integration testing an
|
|
application as well as separating Spring's configuration files so that one
|
|
is responsible for describing how the core business classes are configured
|
|
and others that are responsible for the database environment and
|
|
application of AOP.</para>
|
|
|
|
<para>This quickstart assumes you have installed a way to run NUnit tests
|
|
within your IDE. Some excellent tools that let you do this are <ulink
|
|
url="http://www.testdriven.net/">TestDriven.NET</ulink> and <ulink
|
|
url="http://www.jetbrains.com/resharper/">ReSharper</ulink>.</para>
|
|
|
|
<note>
|
|
<para>To follow this Quarts QuickStart load the solution file found in
|
|
the directory
|
|
<literal><spring-install-dir>\examples\Spring\Spring.TxQuickStart</literal></para>
|
|
</note>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Application Overview</title>
|
|
|
|
<para>The design of the application is very simple and consists of two
|
|
logical layers, a business service layer in the namespace
|
|
<package>Spring.TxQuickStart.Services</package> and a DAO layer in the
|
|
namespace <package>Spring.TxQuickStart.Dao</package>. As this is just a
|
|
toy example the business service layer does nothing more than call two DAO
|
|
objects. The business service is to transfer money in a bank account and
|
|
is blatantly taken from the book <ulink
|
|
url="http://www.apress.com/book/bookDisplay.html?bID=10002">Pro
|
|
ADO.NET</ulink> by Sahil Malik. The transfer service is defined by the
|
|
interface <literal>IAccountManager</literal> with the implementation
|
|
<literal>AccountManager</literal> located in the namespace
|
|
<literal>Spring.TxQuickStart.Services</literal>. The money is recorded in
|
|
a credit and debit table in the database. The SQL Server schema for the
|
|
tables is located in the file CreditsDebitsSchema.sql. Transferring the
|
|
money requires an ACID operation on these two tables. The credit operation
|
|
is defined via a <literal>IAccountCreditDao</literal> interface and the
|
|
debit operation via an <literal>IAccountDebitDao</literal> interface.
|
|
Implementations of these interfaces using <literal>AdoTemplate</literal>
|
|
are in the namespace
|
|
<package>Spring.TxQuickStart.Dao.Ado</package>.</para>
|
|
|
|
<section>
|
|
<title>Interfaces</title>
|
|
|
|
<para>The Manager and DAO interfaces are shown below</para>
|
|
|
|
<programlisting language="csharp"> public interface IAccountManager
|
|
{
|
|
void DoTransfer(float creditAmount, float debitAmount);
|
|
}
|
|
|
|
|
|
public interface IAccountCreditDao
|
|
{
|
|
void CreateCredit(float creditAmount);
|
|
}
|
|
|
|
public interface IAccountDebitDao
|
|
{
|
|
void DebitAccount(float debitAmount);
|
|
}</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Implementation</title>
|
|
|
|
<para>The implementation of the Account Credit DAO is shown below</para>
|
|
|
|
<programlisting language="csharp"> public class AccountCreditDao : AdoDaoSupport, IAccountCreditDao
|
|
{
|
|
public void CreateCredit(float creditAmount)
|
|
{
|
|
AdoTemplate.ExecuteNonQuery(CommandType.Text,
|
|
"insert into Credits (CreditAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,
|
|
creditAmount);
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>and for the Debit DAO</para>
|
|
|
|
<programlisting language="csharp"> public class AccountDebitDao : AdoDaoSupport, IAccountDebitDao
|
|
{
|
|
public void DebitAccount(float debitAmount)
|
|
{
|
|
AdoTemplate.ExecuteNonQuery(CommandType.Text,
|
|
"insert into dbo.Debits (DebitAmount) VALUES (@amount)", "amount", DbType.Decimal, 0,
|
|
debitAmount);
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Both of these DAO implementations inherit from Spring's
|
|
<literal>AdoDaoSupport</literal> class that provides convenient access to
|
|
an <literal>AdoTemplate</literal> for performing data access operations.
|
|
With no other properties that can be configured in these implementations,
|
|
the only configuration required is setting of AdoDaoSupport's
|
|
<literal>DbProvider</literal> property representing the connection to the
|
|
database.</para>
|
|
|
|
<para>The implementation of the service layer interface,
|
|
<literal>IAccountManager</literal>, is shown below.</para>
|
|
|
|
<programlisting language="csharp"> public class AccountManager : IAccountManager
|
|
{
|
|
|
|
private IAccountCreditDao accountCreditDao;
|
|
private IAccountDebitDao accountDebitDao;
|
|
|
|
private float maxTransferAmount = 1000000;
|
|
|
|
public AccountManager(IAccountCreditDao accountCreditDao, IAccountDebitDao accountDebitDao)
|
|
{
|
|
this.accountCreditDao = accountCreditDao;
|
|
this.accountDebitDao = accountDebitDao;
|
|
}
|
|
|
|
public float MaxTransferAmount
|
|
{
|
|
get { return maxTransferAmount; }
|
|
set { maxTransferAmount = value; }
|
|
}
|
|
|
|
|
|
[Transaction]
|
|
public void DoTransfer(float creditAmount, float debitAmount)
|
|
{
|
|
accountCreditDao.CreateCredit(creditAmount);
|
|
|
|
if (creditAmount > maxTransferAmount || debitAmount > maxTransferAmount)
|
|
{
|
|
throw new ArithmeticException("see a teller big spender...");
|
|
}
|
|
|
|
accountDebitDao.DebitAccount(debitAmount);
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The if statement is a poor-mans representation of business logic,
|
|
namely that there is a policy that does not allow the use of this service
|
|
for amounts larger than $1,000,000. If the credit or debit amount is
|
|
larger than 1,000,000 then and exception will be thrown. We can write a
|
|
unit test that will test for this business logic and provide stub
|
|
implementations of the DAO objects so that our tests are not only
|
|
independent of the database but will also execute very quickly.<note>
|
|
<para>Notice the Transaction attribute on the
|
|
<literal>DoTransfer</literal> method. This attribute can be read by
|
|
Spring and used to create a transactional proxy to AccountManager in
|
|
order to perform declarative transaction management.</para>
|
|
</note></para>
|
|
|
|
<para>The NUnit unit test for AccountManager is shown below</para>
|
|
|
|
<programlisting language="csharp"> public class AccountManagerUnitTests
|
|
{
|
|
private IAccountManager accountManager;
|
|
|
|
[SetUp]
|
|
public void Setup()
|
|
{
|
|
IAccountCreditDao stubCreditDao = new StubAccountCreditDao();
|
|
IAccountDebitDao stubDebitDao = new StubAccountDebitDao();
|
|
accountManager = new AccountManager(stubCreditDao, stubDebitDao);
|
|
}
|
|
|
|
[Test]
|
|
public void TransferBelowMaxAmount()
|
|
{
|
|
accountManager.DoTransfer(217, 217);
|
|
}
|
|
|
|
[Test]
|
|
[ExpectedException(typeof(ArithmeticException))]
|
|
public void TransferAboveMaxAmount()
|
|
{
|
|
accountManager.DoTransfer(2000000, 200000);
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Running these tests we exercise both code pathways through the
|
|
method <literal>DoTransfer</literal>. Nothing we have done so far is
|
|
Spring specific (aside from the presence of the [Transaction] attribute.
|
|
Now that we know the class works in isolation, we can now 'wire' up the
|
|
application for use in production by specifying how the service and DAO
|
|
layers are related. This configuration file is shown below and can loosely
|
|
be referred to as your 'application blueprint'. This configuration file is
|
|
named application-config.xml and is an embedded resource inside the 'main'
|
|
project, Spring.TxQuickStart.</para>
|
|
|
|
<programlisting language="myxml"><objects xmlns='http://www.springframework.net'>
|
|
|
|
<!-- DAO Implementations -->
|
|
<object id="accountCreditDao" type="Spring.TxQuickStart.Dao.Ado.AccountCreditDao, Spring.TxQuickStart">
|
|
<property name="DbProvider" ref="CreditDbProvider"/>
|
|
</object>
|
|
|
|
<object id="accountDebitDao" type="Spring.TxQuickStart.Dao.Ado.AccountDebitDao, Spring.TxQuickStart">
|
|
<property name="DbProvider" ref="DebitDbProvider"/>
|
|
</object>
|
|
|
|
|
|
<!-- The service that performs multiple data access operations -->
|
|
<object id="accountManager"
|
|
type="Spring.TxQuickStart.Services.AccountManager, Spring.TxQuickStart">
|
|
<constructor-arg name="accountCreditDao" ref="accountCreditDao"/>
|
|
<constructor-arg name="accountDebitDao" ref="accountDebitDao"/>
|
|
</object>
|
|
|
|
</objects></programlisting>
|
|
|
|
<para>This configuration is selecting the real ADO.NET implementations
|
|
that will insert records into the database. We can now write a NUnit
|
|
integration test that will test the service and DAO layers. To do this we
|
|
add on configuration information specific to our test environment. This
|
|
extra configuration information will determine what databases we speak to
|
|
and what transaction manager (local or distribute) to use. The code for
|
|
this integration style NUnit test is shown below</para>
|
|
|
|
<programlisting language="csharp"> [TestFixture]
|
|
public class AccountManagerTests
|
|
{
|
|
private AdoTemplate adoTemplateCredit;
|
|
private AdoTemplate adoTemplateDebit;
|
|
|
|
private IAccountManager accountManager;
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
// Configure Spring programmatically
|
|
NamespaceParserRegistry.RegisterParser(typeof(DatabaseNamespaceParser));
|
|
NamespaceParserRegistry.RegisterParser(typeof(TxNamespaceParser));
|
|
NamespaceParserRegistry.RegisterParser(typeof(AopNamespaceParser));
|
|
IApplicationContext context = new XmlApplicationContext(
|
|
"assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/system-test-local-config.xml"
|
|
);
|
|
accountManager = context["accountManager"] as IAccountManager;
|
|
CleanDb(context);
|
|
}
|
|
|
|
[Test]
|
|
public void TransferBelowMaxAmount()
|
|
{
|
|
accountManager.DoTransfer(217, 217);
|
|
|
|
int numCreditRecords = (int)adoTemplateCredit.ExecuteScalar(CommandType.Text, "select count(*) from Credits");
|
|
int numDebitRecords = (int)adoTemplateDebit.ExecuteScalar(CommandType.Text, "select count(*) from Debits");
|
|
Assert.AreEqual(1, numCreditRecords);
|
|
Assert.AreEqual(1, numDebitRecords);
|
|
}
|
|
|
|
[Test]
|
|
[ExpectedException(typeof(ArithmeticException))]
|
|
public void TransferAboveMaxAmount()
|
|
{
|
|
accountManager.DoTransfer(2000000, 200000);
|
|
}
|
|
|
|
|
|
private void CleanDb(IApplicationContext context)
|
|
{
|
|
IDbProvider dbProvider = (IDbProvider)context["DebitDbProvider"];
|
|
adoTemplateDebit = new AdoTemplate(dbProvider);
|
|
adoTemplateDebit.ExecuteNonQuery(CommandType.Text, "truncate table Debits");
|
|
|
|
dbProvider = (IDbProvider)context["CreditDbProvider"];
|
|
adoTemplateCredit = new AdoTemplate(dbProvider);
|
|
adoTemplateCredit.ExecuteNonQuery(CommandType.Text, "truncate table Credits");
|
|
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>The essential element is to create an instance of Spring's
|
|
application context where the relevant layers of the application are
|
|
'wired' together. The <literal>IAccountManager</literal> implementation is
|
|
retrieved from the IoC container and stored as a field of the test class.
|
|
The basic logic of the test is the same as in the unit test but in
|
|
addition there is the verification of actions performed in the database.
|
|
The set up method puts the database tables into a known state before
|
|
running the tests. Other techniques for performing integration testing
|
|
that can alleviate the need to do extensive database state management for
|
|
integration tests is described in the <link
|
|
linkend="testing">testing</link> section.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Configuration</title>
|
|
|
|
<para>The configuration file system-test-local-config.xml shown in the
|
|
previous program listing includes application-config.xml and specifies the
|
|
database to use and the local (not distributed) transaction manager
|
|
AdoPlatformTransactionManager. This configuration file is shown
|
|
below</para>
|
|
|
|
<programlisting language="myxml"><objects xmlns="http://www.springframework.net"
|
|
xmlns:db="http://www.springframework.net/database"
|
|
xmlns:tx="http://www.springframework.net/tx">
|
|
|
|
|
|
<!-- Imports application configuration -->
|
|
<import resource="assembly://Spring.TxQuickStart/Spring.TxQuickStart/application-config.xml"/>
|
|
|
|
<!-- Imports additional aspects -->
|
|
<!--
|
|
<import resource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"/>
|
|
-->
|
|
|
|
|
|
<!-- Database Providers -->
|
|
|
|
<db:provider id="DebitDbProvider"
|
|
provider="System.Data.SqlClient"
|
|
connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"/>
|
|
|
|
<db:provider id="CreditDbProvider"
|
|
provider="System.Data.SqlClient"
|
|
connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=CreditsAndDebits;User ID=springqa; Password=springqa"/>
|
|
|
|
<alias name="DebitDbProvider" alias="CreditDbProvider"/>
|
|
|
|
<!-- Transaction Manager if using a single database that contain both credit and debit tables -->
|
|
<object id="transactionManager"
|
|
type="Spring.Data.Core.AdoPlatformTransactionManager, Spring.Data">
|
|
<property name="DbProvider" ref="DebitDbProvider"/>
|
|
</object>
|
|
|
|
<!-- Transaction aspect -->
|
|
|
|
<tx:attribute-driven/>
|
|
|
|
</objects></programlisting>
|
|
|
|
<para>Moving from top to bottom in the configuration file, the
|
|
'application-blueprint' configuration file is included. Then the database
|
|
type and connection parameters are specified for the two databases. The
|
|
names of these providers must match those specific in
|
|
application-config.xml. Since the two names point to the same database, an
|
|
alias configuration element is used to have them point to the same
|
|
dbProvider under different names. The type of transaction manager is then
|
|
selected, in this case we are showing the use of local transactions with
|
|
AdoPlatformTransactionManager. Running the tests will result in 217 being
|
|
entered into the Credits and Debits table of each database. You can fire
|
|
up SQL Server Management Studio or equivalent to verify this.</para>
|
|
|
|
<para>To switch to a distributed transaction you can refer to the
|
|
configuration file system-test-dtc-config.xml, which is shown below</para>
|
|
|
|
<programlisting language="myxml"><objects xmlns='http://www.springframework.net'
|
|
xmlns:db="http://www.springframework.net/database"
|
|
xmlns:tx="http://www.springframework.net/tx">
|
|
|
|
|
|
<!-- Imports application configuration -->
|
|
<import resource="assembly://Spring.TxQuickStart/Spring.TxQuickStart/application-config.xml"/>
|
|
|
|
<!-- Imports additional aspects -->
|
|
<!--
|
|
<import resource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"/>
|
|
-->
|
|
|
|
<db:provider id="DebitDbProvider"
|
|
provider="System.Data.SqlClient"
|
|
connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=Debits;User ID=springqa; Password=springqa"/>
|
|
|
|
|
|
<db:provider id="CreditDbProvider"
|
|
provider="System.Data.SqlClient"
|
|
connectionString="Data Source=MARKT60\SQL2005;Initial Catalog=Credits;User ID=springqa; Password=springqa"/>
|
|
|
|
|
|
<!-- Transaction Manager if using two databases, one containing the credit table and the other a debit table -->
|
|
|
|
<object id="transactionManager"
|
|
type="Spring.Data.Core.TxScopeTransactionManager, Spring.Data">
|
|
</object>
|
|
|
|
|
|
<!-- Transaction aspect -->
|
|
<tx:attribute-driven/>
|
|
|
|
</objects></programlisting>
|
|
|
|
<para>TxScopeTransactionManager uses .NET 2.0 System.Transactions as the
|
|
implementation, allowing for distributed transactions between the two
|
|
different databases listed. In a larger application the different layers
|
|
would typically be broken up into individual configuration files and
|
|
imported into the main configuration file. This allows your configuration
|
|
to mirror your architecture.</para>
|
|
|
|
<para>You can also use the configuration file
|
|
system-test-dtc-es-config.xml that will use EnterpriseServices to perform
|
|
transaction management.</para>
|
|
|
|
<section>
|
|
<title>Rollback Rules</title>
|
|
|
|
<para>Using Rollback rules allows you to specify which exceptions will
|
|
not cause a rollback and instead only stop execution flow, committing
|
|
the work done up to the exception. An alternative implementation of
|
|
AccountManager's DoTransfer method (included in the sample code) is
|
|
shown below.</para>
|
|
|
|
<programlisting language="csharp"> [Transaction(NoRollbackFor = new Type[] { typeof(ArithmeticException) })]
|
|
public void DoTransfer(float creditAmount, float debitAmount)
|
|
{
|
|
accountCreditDao.CreateCredit(creditAmount);
|
|
|
|
if (creditAmount > maxTransferAmount || debitAmount > maxTransferAmount)
|
|
{
|
|
throw new ArithmeticException("see a teller big spender...");
|
|
}
|
|
|
|
accountDebitDao.DebitAccount(debitAmount);
|
|
} </programlisting>
|
|
|
|
<para>All that has changed is the use of the NoRollbackFor property on
|
|
the transaction attribute.</para>
|
|
|
|
<para>The expected behavior is that the credit table will be updated
|
|
even though the exception is thrown. This is due to specifying that
|
|
exceptions of the type ArithmethicException should not rollback the
|
|
database transaction. Running the test code below verifies that the
|
|
exception still propagates out of the method.</para>
|
|
|
|
<programlisting language="csharp"> [Test]
|
|
public void DeclarativeWithAttributesNoRollbackFor()
|
|
{
|
|
try
|
|
{
|
|
accountManager.DoTransfer(2000000, 2000000);
|
|
Assert.Fail("Should have thrown Arithmetic Exception");
|
|
} catch (ArithmeticException) {
|
|
int numCreditRecords = (int)adoTemplateCredit.ExecuteScalar(CommandType.Text, "select count(*) from Credits");
|
|
int numDebitRecords = (int)adoTemplateDebit.ExecuteScalar(CommandType.Text, "select count(*) from Debits");
|
|
Assert.AreEqual(1, numCreditRecords);
|
|
Assert.AreEqual(0, numDebitRecords);
|
|
}
|
|
}</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Adding additional Aspects</title>
|
|
|
|
<para>Transactional advice is just one type of advice that can be applied
|
|
to the service layer. You can also configure other pieces of advice to be
|
|
executed as part of the general advice chain that is associated with
|
|
methods that have the Transaction attribute applied. In this example we
|
|
will add logging of thrown exceptions using Spring's
|
|
ExceptionHandlerAdvice as well as logging of the service layer method
|
|
invocation. No code is required to be changed in order to have this
|
|
additional functionality. Instead all you have to do is uncomment the
|
|
line</para>
|
|
|
|
<programlisting language="myxml"> <import resource="assembly://Spring.TxQuickStart.Tests/Spring.TxQuickStart/aspects-config.xml"/></programlisting>
|
|
|
|
<para>in either system-test-dtc-config.xml or system-test-local-config.xml
|
|
The aspect configuration file is shown below</para>
|
|
|
|
<programlisting language="myxml"><objects xmlns='http://www.springframework.net'
|
|
xmlns:aop="http://www.springframework.net/aop">
|
|
|
|
|
|
|
|
<object name="exceptionAdvice" type="Spring.Aspects.Exceptions.ExceptionHandlerAdvice, Spring.Aop">
|
|
<property name="exceptionHandlers">
|
|
<list>
|
|
<value>on exception name ArithmeticException log 'Logging an exception thrown from method ' + #method.Name </value>
|
|
</list>
|
|
</property>
|
|
</object>
|
|
|
|
<object name="loggingAdvice" type="Spring.Aspects.Logging.SimpleLoggingAdvice, Spring.Aop">
|
|
<property name="logUniqueIdentifier" value="true"/>
|
|
<property name="logExecutionTime" value="true"/>
|
|
<property name="logMethodArguments" value="true"/>
|
|
<property name="Separator" value=";"/>
|
|
|
|
<property name="HideProxyTypeNames" value="true"/>
|
|
<property name="UseDynamicLogger" value="true"/>
|
|
|
|
<property name="LogLevel" value="Info"/>
|
|
</object>
|
|
|
|
|
|
<object id="txAttributePointcut" type="Spring.Aop.Support.AttributeMatchMethodPointcut, Spring.Aop">
|
|
<property name="Attribute" value="Spring.Transaction.Interceptor.TransactionAttribute, Spring.Data"/>
|
|
</object>
|
|
|
|
<aop:config>
|
|
|
|
<aop:advisor id="exceptionProcessAdvisor" order="1"
|
|
advice-ref="exceptionAdvice"
|
|
pointcut-ref="txAttributePointcut"/>
|
|
|
|
<aop:advisor id="loggingAdvisor" order="2"
|
|
advice-ref="loggingAdvice"
|
|
pointcut-ref="txAttributePointcut"/>
|
|
|
|
</aop:config>
|
|
|
|
</objects></programlisting>
|
|
|
|
<para>The transaction aspect is now additionally configured with an order
|
|
value of "10", which will place it after the execution of the exception
|
|
aspect, which is configured to use an order value of 1. The behavior for
|
|
logging the exception is specified by creating and configuring an instance
|
|
of <literal>Spring.Aspects.Exceptions.ExceptionHandlerAdvice</literal>.
|
|
The location where that behavior is applied, the pointcut, is the
|
|
Transaction attribute. The logging of method arguments and execution time
|
|
is specified by configuring an instance of
|
|
<literal>Spring.Aspects.Logging.SimpleLoggingAdvice</literal>.</para>
|
|
|
|
<para>The AOP configuration section on the bottom is what ties together
|
|
the behavior and where it will take place in the program flow. Under the
|
|
covers the transaction configuration, <tx:attribute-driven/> creates
|
|
similar advice and pointcut definitions. Running the test
|
|
TransferBelowMaxAmount will then log the following messages</para>
|
|
|
|
<programlisting>INFO - Entering DoTransfer;45b6af04-b736-4efa-a489-45462726ddf2;creditAmount=217; debitAmount=217
|
|
INFO - Exiting DoTransfer;45b6af04-b736-4efa-a489-45462726ddf2;1328.125 ms;return=
|
|
</programlisting>
|
|
|
|
<para>When the test case of the test TransferAboveMaxAmount is run the
|
|
following messages are logged</para>
|
|
|
|
<programlisting>INFO - Entering DoTransfer;d94bc81b-a4ff-4ca1-9aaa-f2834f262307;creditAmount=2000000; debitAmount=200000
|
|
INFO - Exception thrown in DoTransferDoTransfer;d94bc81b-a4ff-4ca1-9aaa-f2834f262307;1140.625
|
|
System.ArithmeticException: see a teller big spender...
|
|
at Spring.TxQuickStart.Services.AccountManager.DoTransfer(Single creditAmount, Single debitAmount) in L:\projects\Spring.Net\examples\Spring\Spring.TxQuickStart\src\Spring\Spring.TxQuickStart\TxQuickStart\Services\AccountManager.cs:line 36
|
|
at Spring.DynamicReflection.Method_DoTransfer_ec48557f22b149958fd2243413136600.Invoke(Object target, Object[] args)
|
|
at Spring.Reflection.Dynamic.SafeMethod.Invoke(Object target, Object[] arguments) in l:\projects\Spring.Net\src\Spring\Spring.Core\Reflection\Dynamic\DynamicMethod.cs:line 108
|
|
at Spring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint() in l:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\DynamicMethodInvocation.cs:line 89
|
|
at Spring.Aop.Framework.AbstractMethodInvocation.Proceed() in l:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\AbstractMethodInvocation.cs:line 257
|
|
at Spring.Transaction.Interceptor.TransactionInterceptor.Invoke(IMethodInvocation invocation) in l:\projects\Spring.Net\src\Spring\Spring.Data\Transaction\Interceptor\TransactionInterceptor.cs:line 80
|
|
at Spring.Aop.Framework.AbstractMethodInvocation.Proceed() in l:\projects\Spring.Net\src\Spring\Spring.Aop\Aop\Framework\AbstractMethodInvocation.cs:line 282
|
|
at Spring.Aspects.Logging.SimpleLoggingAdvice.InvokeUnderLog(IMethodInvocation invocation, ILog log) in l:\projects\Spring.Net\src\Spring\Spring.Aop\Aspects\Logging\SimpleLoggingAdvice.cs:line 185
|
|
TRACE - Logging an exception thrown from method DoTransfer
|
|
</programlisting>
|
|
|
|
<para></para>
|
|
</section>
|
|
</chapter>
|