diff --git a/doc/reference/src/classic-spring.xml b/doc/reference/src/classic-spring.xml
new file mode 100644
index 00000000..21e5e490
--- /dev/null
+++ b/doc/reference/src/classic-spring.xml
@@ -0,0 +1,538 @@
+
+
+
+ Classic Spring Usage
+
+ This appendix discusses some classic Spring usage patterns as a
+ reference for developers maintaining legacy Spring applications. These usage
+ patterns no longer reflect the recommended way of using these features and
+ the current recommended usage is covered in the respective sections of the
+ reference manual.
+
+
+ Classic Hibernate Usage
+
+ For the currently recommended usage patterns for NHibernate see
+
+
+
+ The HibernateTemplate
+
+ The basic programming model for templating looks as follows for
+ methods that can be part of any custom data access object or business
+ service. There are no restrictions on the implementation of the
+ surrounding object at all, it just needs to provide a Hibernate
+ SessionFactory. It can get the latter from anywhere,
+ but preferably as an object reference from a Spring IoC container - via
+ a simple SessionFactory property setter. The
+ following snippets show a DAO definition in a Spring container,
+ referencing the above defined SessionFactory, and an
+ example for a DAO method implementation.
+
+ <objects>
+
+ <object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
+ <property name="SessionFactory" ref="MySessionFactory"/>
+ </object>
+
+</objects>
+
+
+
+ public class HibernateCustomerDao : ICustomerDao {
+
+ private HibernateTemplate hibernateTemplate;
+
+ public ISessionFactory SessionFactory
+ {
+ set { hibernateTemplate = new HibernateTemplate(value); }
+ }
+
+ public Customer SaveOrUpdate(Customer customer)
+ {
+ hibernateTemplate.SaveOrUpdate(customer);
+ return customer;
+ }
+}
+
+ The HibernateTemplate class provides many
+ methods that mirror the methods exposed on the Hibernate
+ Session interface, in addition to a number of
+ convenience methods such as the one shown above. If you need access to
+ the Session to invoke methods that are not exposed on
+ the HibernateTemplate, you can always drop down to a
+ callback-based approach like so.
+
+ public class HibernateCustomerDao : ICustomerDao {
+
+ private HibernateTemplate hibernateTemplate;
+
+ public ISessionFactory SessionFactory
+ {
+ set { hibernateTemplate = new HibernateTemplate(value); }
+ }
+
+ public Customer SaveOrUpdate(Customer customer)
+ {
+ return HibernateTemplate.Execute(
+ delegate(ISession session)
+ {
+ // do whatever you want with the session....
+ session.SaveOrUpdate(customer);
+ return customer;
+ }) as Customer;
+ }
+
+}
+
+ Using the anonymous delegate is particularly convenient when you
+ would otherwise be passing various method parameter calls to the
+ interface based version of this callback. Furthermore, when using
+ generics, you can avoid the typecast and write code like the
+ following
+
+ IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>(
+ delegate(ISession session)
+ {
+ return session.CreateQuery("from Supplier s were s.Code = ?")
+ .SetParameter(0, code)
+ .List<Supplier>();
+ });
+
+ where code is a variable in the surrounding block, accessible
+ inside the anonymous delegate implementation.
+
+ A callback implementation effectively can be used for any
+ Hibernate data access. HibernateTemplate will ensure
+ that Session instances are properly opened and
+ closed, and automatically participate in transactions. The template
+ instances are thread-safe and reusable, they can thus be kept as
+ instance variables of the surrounding class. For simple single step
+ actions like a single Find, Load, SaveOrUpdate, or Delete call,
+ HibernateTemplate offers alternative convenience
+ methods that can replace such one line callback implementations.
+ Furthermore, Spring provides a convenient
+ HibernateDaoSupport base class that provides a
+ SessionFactory property for receiving a
+ SessionFactory and for use by subclasses. In
+ combination, this allows for very simple DAO implementations for typical
+ requirements:
+
+ public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
+{
+ public Customer SaveOrUpdate(Customer customer)
+ {
+ HibernateTemplate.SaveOrUpdate(customer);
+ return customer;
+ }
+}
+
+
+
+ Implementing Spring-based DAOs without callbacks
+
+ As an alternative to using Spring's
+ HibernateTemplate to implement DAOs, data access code
+ can also be written in a more traditional fashion, without wrapping the
+ Hibernate access code in a callback, while still respecting and
+ participating in Spring's generic DataAccessException
+ hierarchy. The HibernateDaoSupport base class offers
+ methods to access the current transactional Session
+ and to convert exceptions in such a scenario; similar methods are also
+ available as static helpers on the
+ SessionFactoryUtils class. Note that such code will
+ usually pass 'false' as the value of the
+ DoGetSession(..) method's
+ 'allowCreate' argument, to enforce running within a
+ transaction (which avoids the need to close the returned
+ Session, as its lifecycle is managed by the
+ transaction). Asking for the
+
+ public class HibernateProductDao : HibernateDaoSupport, IProductDao {
+
+ public Customer SaveOrUpdate(Customer customer)
+ {
+ ISession session = DoGetSession(false);
+ session.SaveOrUpdate(customer);
+ return customer;
+ }
+ }
+}
+
+ This code will not translate the Hibernate
+ exception to a generic DataAccessException.
+
+
+
+
+ Classic Declarative Transaction Configurations
+
+
+ Declarative Transaction Configuration using
+ DefaultAdvisorAutoProxyCreator
+
+ Using the DefaultAdvisorAutoProxyCreator to configure declarative
+ transactions enables you to refer to the transaction attribute as the
+ pointcut to use for the transactional advice for any object definition
+ defined in the IoC container. The configuration to create a
+ transactional proxy for the manager class shown in the chapter on
+ transaction management is shown below.
+
+ <!-- The rest of the config file is common no matter how many objects you add -->
+ <!-- that you would like to have declarative tx management applied to -->
+
+ <object id="autoProxyCreator"
+ type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop">
+ </object>
+
+ <object id="transactionAdvisor"
+ type="Spring.Transaction.Interceptor.TransactionAttributeSourceAdvisor, Spring.Data">
+ <property name="TransactionInterceptor" ref="transactionInterceptor"/>
+ </object>
+
+
+ <!-- Transaction Interceptor -->
+ <object id="transactionInterceptor"
+ type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
+ <property name="TransactionManager" ref="transactionManager"/>
+ <property name="TransactionAttributeSource" ref="attributeTransactionAttributeSource"/>
+ </object>
+
+ <object id="attributeTransactionAttributeSource"
+ type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data">
+ </object>
+
+
+ Granted this is a bit verbose and hard to grok at first sight -
+ however you only need to grok this once as it is 'boiler plate' XML you
+ can reuse across multiple projects. What these object definitions are
+ doing is to instruct Spring's to look for all objects within the IoC
+ configuration that have the [Transaction] attribute and then apply the
+ AOP transaction interceptor to them based on the transaction options
+ contained in the attribute. The attribute serves both as a pointcut and
+ as the declaration of transactional option information.
+
+ Since this XML fragment is not tied to any specific object
+ references it can be included in its own file and then imported via the
+ <import> element. In examples and test code this XML configuration
+ fragment is named autoDeclarativeServices.xml See for more information.
+
+ The classes and their roles in this configuration fragment are
+ listed below
+
+
+
+ TransactionInterceptor is the AOP advice
+ responsible for performing transaction management
+ functionality.
+
+
+
+ TransactionAttributeSourceAdvisor is an AOP
+ Advisor that holds the TransactionInterceptor, which is the advice,
+ and a pointcut (where to apply the advice), in the form of a
+ TransactionAttributeSource.
+
+
+
+ AttributesTransactionAttributeSource is an
+ implementation of the ITransactionAttributeSource
+ interface that defines where to get the transaction metadata
+ defining the transaction semantics (isolation level, propagation
+ behavior, etc) that should be applied to specific methods of
+ specific classes. The transaction metadata is specified via
+ implementations of the
+ ITransactionAttributeSource interface. This
+ example shows the use of the implementation
+ Spring.Transaction.Interceptor.AttributesTransactionAttributeSource
+ to obtain that information from standard .NET attributes. By the
+ very nature of using standard .NET attributes, the attribute serves
+ double duty in identifying the methods where the transaction
+ semantics apply. Alternative implementations of
+ ITransactionAttributeSource available are
+ MatchAlwaysTransactionAttributeSource,
+ NameMatchTransactionAttributeSource, or
+ MethodMapTransactionAttributeSource.
+
+
+
+ MatchAlwaysTransactionAttributeSource
+ is configured with a ITransactionAttribute instance that is
+ applied to all methods. The shorthand string representation,
+ i.e. PROPAGATION_REQUIRED can be used
+
+
+
+ AttributesTransactionAttributeSource :
+ Use a standard. .NET attributes to specify the transactional
+ information. See TransactionAttribute class
+ for more information.
+
+
+
+ NameMatchTransactionAttributeSource
+ allows ITransactionAttributes to be matched by method name. The
+ NameMap IDictionary property is used to specify the mapping. For
+ example
+
+ <object name="nameMatchTxAttributeSource" type="Spring.Transaction.Interceptor.NameMatchTransactionAttributeSource, Spring.Data"
+ <property name="NameMap">
+ <dictionary>
+ <entry key="Execute" value="PROPAGATION_REQUIRES_NEW, -ApplicationException"/>
+ <entry key="HandleData" value="PROPAGATION_REQUIRED, -DataHandlerException"/>
+ <entry key="Find*" value="ISOLATION_READUNCOMMITTED, -DataHandlerException"/>
+ </dictionary>
+ </property>
+
+</object>
+
+ Key values can be prefixed and/or suffixed with wildcards
+ as well as include the full namespace of the containing
+ class.
+
+
+
+ MethodMapTransactionAttributeSource :
+ Similar to NameMatchTransactionAttributeSource but specifies
+ that only fully qualified method names (i.e. type.method,
+ assembly) and wildcards can be used at the start or end of the
+ method name for matching multiple methods.
+
+
+
+
+
+ DefaultAdvisorAutoProxyCreator: looks for
+ Advisors in the context, and automatically creates proxy objects
+ which are the transactional wrappers
+
+
+
+ Refer to the following section for a more convenient way to
+ achieve the same goal of declarative transaction management using
+ attributes.
+
+
+ Declarative Transactions using TransactionProxyFactoryObject
+
+ The TransactionProxyFactoryObject is easier to use than a
+ ProxyFactoryObject for most cases since the transaction interceptor and
+ transaction attributes are properties of this object. This removes the
+ need to declare them as separate objects. Also, unlike the case with the
+ ProxyFactoryObject, you do not have to give fully qualified method
+ names, just the normal 'short' method name. Wild card matching on the
+ method name is also allowed, which in practice helps to enforce a common
+ naming convention for the methods of your DAOs. The example from chapter
+ 5 is shown here using a TransactionProxyFactoryObject.
+
+
+ <object id="testObjectManager"
+ type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
+
+ <property name="PlatformTransactionManager" ref="adoTransactionManager"/>
+ <property name="Target">
+ <object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
+ <property name="TestObjectDao" ref="testObjectDao"/>
+ </object>
+ </property>
+ <property name="TransactionAttributes">
+ <name-values>
+ <add key="Save*" value="PROPAGATION_REQUIRED"/>
+ <add key="Delete*" value="PROPAGATION_REQUIRED"/>
+ </name-values>
+ </property>
+ </object>
+
+
+
+ Note the use of an inner object definition for the target which
+ will make it impossible to obtain an unproxied reference to the
+ TestObjectManager.
+
+ As can be seen in the above definition, the TransactionAttributes
+ property holds a collection of name/value pairs. The key of each pair is
+ a method or methods (a * wildcard ending is optional) to apply
+ transactional semantics to. Note that the method name is not qualified
+ with a package name, but rather is considered relative to the class of
+ the target object being wrapped. The value portion of the name/value
+ pair is the TransactionAttribute itself that needs to be applied. When
+ specifying it as a string value as in this example, it's in String
+ format as defined by TransactionAttributeConverter. This format
+ is:
+
+ PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2
+
+ Note that the only mandatory portion of the string is the
+ propagation setting. The default transactions semantics which apply are
+ as follows:
+
+
+
+ Exception Handling: All exceptions thrown trigger a
+ rollback.
+
+
+
+ Transactions are read/write
+
+
+
+ Isolation Level:
+ TransactionDefinition.ISOLATION_DEFAULT
+
+
+
+ Timeout: TransactionDefinition.TIMEOUT_DEFAULT
+
+
+
+ Multiple rollback rules can be specified here, comma-separated. A
+ - prefix forces rollback; a + prefix specifies commit. Under the covers
+ the IDictionary of name value pairs will be converted to an instance of
+ NameMatchTransactionAttributeSource
+
+ The string used for PROPAGATION_NAME are those defined on the
+ Spring.Transaction.TransactionPropagation enumeration, namely Required,
+ Supports, Mandatory, RequiresNew, NotSupported, Never, Nested. The
+ string used for ISOLATION_NAME are those defined on the
+ System.Data.IsolationLevel enumberateion, namely ReadCommitted,
+ ReadUncommitted, RepeatableRead, Serializable.
+
+ The TransactionProxyFactoryObject allows you to set optional "pre"
+ and "post" advice, for additional interception behavior, using the
+ "PreInterceptors" and "PostInterceptors" properties. Any number of pre
+ and post advices can be set, and their type may be Advisor (in which
+ case they can contain a pointcut), MethodInterceptor or any advice type
+ supported by the current Spring configuration (such as ThrowsAdvice,
+ AfterReturningAdvice or BeforeAdvice, which are supported by default.)
+ These advices must support a shared-instance model. If you need
+ transactional proxying with advanced AOP features such as stateful
+ mixins, it's normally best to use the generic ProxyFactoryObject, rather
+ than the TransactionProxyFactoryObject convenience proxy creator.
+
+
+
+ Concise proxy definitions
+
+ Using abstract object definitions in conjunction with a
+ TransactionProxyFactoryObject provides you a more concise means to reuse
+ common configuration information instead of duplicating it over and over
+ again with a definition of a TransactionProxyFactoryObject per object.
+ Objects that are to be proxied typically have the same pattern of method
+ names, Save*, Find*, etc. This commonality can be placed in an abstract
+ object definition, which other object definitions refer to and change
+ only the configuration information that is different. An abstract object
+ definition is shown below
+
+ <object id="txProxyTemplate" abstract="true"
+ type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
+
+ <property name="PlatformTransactionManager" ref="adoTransactionManager"/>
+
+ <property name="TransactionAttributes">
+ <name-values>
+ <add key="Save*" value="PROPAGATION_REQUIRED"/>
+ <add key="Delete*" value="PROPAGATION_REQUIRED"/>
+ </name-values>
+ </property>
+ </object>
+
+ Subsequent definitions can refer to this 'base' configuration as
+ shown below
+
+ <object id="testObjectManager" parent="txProxyTemplate">
+ <property name="Target">
+ <object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
+ <property name="TestObjectDao" ref="testObjectDao"/>
+ </object>
+ </property>
+</object>
+
+
+
+ Declarative Transactions using ProxyFactoryObject
+
+ Using the general ProxyFactoryObject to declare transactions gives
+ you a great deal of control over the proxy created since you can specify
+ additional advice, such as for logging or performance. Based on the
+ example shown previously a sample configuration using ProxyFactoryObject
+ is shown below
+
+ <object id="testObjectManagerTarget" type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
+ <property name="TestObjectDao" ref="testObjectDao"/>
+ </object>
+
+ <object id="testObjectManager" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
+
+ <property name="Target" ref="testObjectManagerTarget"/>
+ <property name="ProxyInterfaces">
+ <value>Spring.Data.ITestObjectManager</value>
+ </property>
+ <property name="InterceptorNames">
+ <value>transactionInterceptor</value>
+ </property>
+
+ </object>
+
+ The ProxyFactoryObject will create a proxy for the Target, i.e. a
+ TestObjectManager instance. An inner object definition could also have
+ been used such that it would make it impossible to obtain an unproxied
+ object from the container. The interceptor name refers to the following
+ definition.
+
+ <object id="transactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
+
+ <property name="TransactionManager" ref="adoTransactionManager"/>
+
+ <!-- note do not have converter from string to this property type registered -->
+ <property name="TransactionAttributeSource" ref="methodMapTransactionAttributeSource"/>
+ </object>
+
+ <object name="methodMapTransactionAttributeSource"
+ type="Spring.Transaction.Interceptor.MethodMapTransactionAttributeSource, Spring.Data">
+ <property name="MethodMap">
+ <dictionary>
+ <entry key="Spring.Data.TestObjectManager.SaveTwoTestObjects, Spring.Data.Integration.Tests"
+ value="PROPAGATION_REQUIRED"/>
+ <entry key="Spring.Data.TestObjectManager.DeleteTwoTestObjects, Spring.Data.Integration.Tests"
+ value="PROPAGATION_REQUIRED"/>
+ </dictionary>
+ </property>
+ </object>
+
+ The transaction options for each method are specified using a
+ dictionary containing the class name + method name, assembly as the key
+ and the value is of the form
+
+
+
+ <Propagation Behavior>, <Isolation Level>,
+ <ReadOnly>, -Exception, +Exception
+
+
+
+ All but the propagation behavior are optional. The + and - are
+ used in front of the name of an exception. Minus indicates to rollback
+ if the exception is thrown, the Plus indicates to commit if the
+ exception is thrown.
+
+
+
+
diff --git a/doc/reference/src/index.xml b/doc/reference/src/index.xml
index 58244363..2379e653 100644
--- a/doc/reference/src/index.xml
+++ b/doc/reference/src/index.xml
@@ -55,6 +55,7 @@
+
]>
The Spring.NET Framework
Reference DocumentationVersion 1.3.0
- Last Updated December 15, 2009 (Latest documentation)
+ Last Updated December 17, 2009 (Latest documentation)Mark
@@ -452,8 +453,12 @@
- &xsd-configuration;
- &xml-custom;
- &xsd;
+
+ Appendices
+ &classic-spring;
+ &xsd-configuration;
+ &xml-custom;
+ &xsd;
+
diff --git a/doc/reference/src/orm.xml b/doc/reference/src/orm.xml
index c3f3ab82..cbde9422 100644
--- a/doc/reference/src/orm.xml
+++ b/doc/reference/src/orm.xml
@@ -591,155 +591,6 @@ public class HibernateCustomerDao : ICustomerDao {
-
- The HibernateTemplate for Hibernate
- 1.2
-
- The basic programming model for templating looks as follows for
- methods that can be part of any custom data access object or business
- service. There are no restrictions on the implementation of the
- surrounding object at all, it just needs to provide a Hibernate
- SessionFactory. It can get the latter from anywhere,
- but preferably as an object reference from a Spring IoC container - via
- a simple SessionFactory property setter. The
- following snippets show a DAO definition in a Spring container,
- referencing the above defined SessionFactory, and an
- example for a DAO method implementation.
-
- <objects>
-
- <object id="CustomerDao" type="Spring.Northwind.Dao.NHibernate.HibernateCustomerDao, Spring.Northwind.Dao.NHibernate">
- <property name="SessionFactory" ref="MySessionFactory"/>
- </object>
-
-</objects>
-
-
-
- public class HibernateCustomerDao : ICustomerDao {
-
- private HibernateTemplate hibernateTemplate;
-
- public ISessionFactory SessionFactory
- {
- set { hibernateTemplate = new HibernateTemplate(value); }
- }
-
- public Customer SaveOrUpdate(Customer customer)
- {
- hibernateTemplate.SaveOrUpdate(customer);
- return customer;
- }
-}
-
- The HibernateTemplate class provides many
- methods that mirror the methods exposed on the Hibernate
- Session interface, in addition to a number of
- convenience methods such as the one shown above. If you need access to
- the Session to invoke methods that are not exposed on
- the HibernateTemplate, you can always drop down to a
- callback-based approach like so.
-
- public class HibernateCustomerDao : ICustomerDao {
-
- private HibernateTemplate hibernateTemplate;
-
- public ISessionFactory SessionFactory
- {
- set { hibernateTemplate = new HibernateTemplate(value); }
- }
-
- public Customer SaveOrUpdate(Customer customer)
- {
- return HibernateTemplate.Execute(
- delegate(ISession session)
- {
- // do whatever you want with the session....
- session.SaveOrUpdate(customer);
- return customer;
- }) as Customer;
- }
-
-}
-
- Using the anonymous delegate is particularly convenient when you
- would otherwise be passing various method parameter calls to the
- interface based version of this callback. Furthermore, when using
- generics, you can avoid the typecast and write code like the
- following
-
- IList<Supplier> suppliers = HibernateTemplate.ExecuteFind<Supplier>(
- delegate(ISession session)
- {
- return session.CreateQuery("from Supplier s were s.Code = ?")
- .SetParameter(0, code)
- .List<Supplier>();
- });
-
- where code is a variable in the surrounding block, accessible
- inside the anonymous delegate implementation.
-
- A callback implementation effectively can be used for any
- Hibernate data access. HibernateTemplate will ensure
- that Session instances are properly opened and
- closed, and automatically participate in transactions. The template
- instances are thread-safe and reusable, they can thus be kept as
- instance variables of the surrounding class. For simple single step
- actions like a single Find, Load, SaveOrUpdate, or Delete call,
- HibernateTemplate offers alternative convenience
- methods that can replace such one line callback implementations.
- Furthermore, Spring provides a convenient
- HibernateDaoSupport base class that provides a
- SessionFactory property for receiving a
- SessionFactory and for use by subclasses. In
- combination, this allows for very simple DAO implementations for typical
- requirements:
-
- public class HibernateCustomerDao : HibernateDaoSupport, ICustomerDao
-{
- public Customer SaveOrUpdate(Customer customer)
- {
- HibernateTemplate.SaveOrUpdate(customer);
- return customer;
- }
-}
-
-
-
- Implementing Spring-based DAOs without HibernateTemplate in
- Hibernate 1.2
-
- As an alternative to using Spring's
- HibernateTemplate to implement DAOs, data access code
- can also be written in a more traditional fashion, without wrapping the
- Hibernate access code in a callback, while still respecting and
- participating in Spring's generic DataAccessException
- hierarchy. The HibernateDaoSupport base class offers
- methods to access the current transactional Session
- and to convert exceptions in such a scenario; similar methods are also
- available as static helpers on the
- SessionFactoryUtils class. Note that such code will
- usually pass 'false' as the value of the
- DoGetSession(..) method's
- 'allowCreate' argument, to enforce running within a
- transaction (which avoids the need to close the returned
- Session, as its lifecycle is managed by the
- transaction). Asking for the
-
- public class HibernateProductDao : HibernateDaoSupport, IProductDao {
-
- public Customer SaveOrUpdate(Customer customer)
- {
- ISession session = DoGetSession(false);
- session.SaveOrUpdate(customer);
- return customer;
- }
- }
-}
-
- This code will not translate the Hibernate
- exception to a generic DataAccessException.
- Declarative transaction demarcation
diff --git a/doc/reference/src/transaction.xml b/doc/reference/src/transaction.xml
index 992a3f72..a89d60b0 100644
--- a/doc/reference/src/transaction.xml
+++ b/doc/reference/src/transaction.xml
@@ -439,16 +439,16 @@
lightweight container.
Spring's declarative transaction management is made possible with
- Spring AOP, although, as the transactional aspects code comes with Spring
- and may be used in a boilerplate fashion, AOP concepts do not generally
- have to be understood to make effective use of this code.
+ Spring's aspect-oriented programming (AOP), although, as the transactional
+ aspects code comes with Spring and may be used in a boilerplate fashion,
+ AOP concepts do not generally have to be understood to make effective use
+ of this code.
- The basic approach is to specify transaction behavior (or lack of
- it) down to the individual method level. It is also possible to mark a
- transaction for rollback by setting the 'RollbackOnly' property on the
- ITransactionStatus object returned from the IPlatformTransactionManager
- within a transaction context if necessary. Some of the highlights of
- Spring's declarative transaction management are:
+ The approach is to specify transaction behavior (or lack of it) down
+ to the individual method level. It is also possible to mark a transaction
+ for rollback by calling the SetRollbackOnly()
+ method within a transaction context if necessary. Some of the highlights
+ of Spring's declarative transaction management are:
@@ -482,20 +482,17 @@
- Note rollback rules as configured from XML are still under
- development.
-
The concept of rollback rules is important: they enable us to
specify which exceptions should cause automatic roll back. We specify this
- declaratively, in configuration, not in code. So, while we can still set
- RollbackOnly on the
+ declaratively, in configuration, not in code. So, although you can still
+ call SetRollbackOnly() on the
ITransactionStatus object to roll the current
- transaction back Programatically, most often we can specify a rule that
+ transaction back, most often you can specify a rule that
MyApplicationException must always result in rollback. This has the
- significant advantage that business objects don't need to depend on the
+ significant advantage that business objects do not depend on the
transaction infrastructure. For example, they typically don't need to
- import any Spring APIs, transaction or other. If you would like to
- rollback the transaction programmatically and you are using declarative
+ import any Spring transaction APIs or other Spring APIs. However, to
+ rollback the transaction programmatically when using declarative
transaction management, use the utility methodTransactionInterceptor.CurrentTransactionStatus.SetRollbackOnly();
@@ -510,37 +507,26 @@
Understanding Spring's declarative transaction
implementation
- The aim of this section is to dispel the mystique that is
- sometimes associated with the use of declarative transactions. It is all
- very well for this reference documentation to simply tell you to
- annotate your classes with the Transaction attribute and add some
- boilerplate XML to your IoC configuration, and then expect you to
- understand how it all works. This section will explain the inner
- workings of Spring's declarative transaction infrastructure to help you
- navigate your way back upstream to calmer waters in the event of
- transaction-related issues.
+ It is not sufficient to tell you simply to annotate your classes
+ with the [Transaction] attribute, add the line
+ (<tx:attribute-driven/>) to your configuration,
+ and then expect you to understand how it all works. This section
+ explains the inner workings of the Spring Framework's declarative
+ transaction infrastructure in the event of transaction-related
+ issues.
-
- Looking at the Spring source code is a good way to get a real
- understanding of Spring's transaction support. You should find the API
- documentation informative and complete. We suggest turning the logging
- level to 'DEBUG' in your Spring-enabled application(s) during
- development to better see what goes on under the hood.
-
-
- The most important concepts to grasp with regard to Spring's
- declarative transaction support are that this support is enabled via AOP
- proxies, and that the transactional advice is driven by metadata
- (currently XML- or attribute-based). The combination of a proxy with
- transactional metadata yields an AOP proxy that uses a
- TransactionInterceptor in conjunction with an
- appropriate IPlatformTransactionManager
+ The most important concepts to grasp with regard to the Spring
+ Framework's declarative transaction support are that this support is
+ enabled via AOP proxies, and
+ that the transactional advice is driven by metadata (currently XML- or
+ attribute-based). The combination of AOP with transactional metadata
+ yields an AOP proxy that uses a
+ TransactionInterceptor in conjunction with an
+ appropriate IPlatformTransactionManager
implementation to drive transactions around method invocations.
- Although knowledge of AOP (and specifically Spring AOP) is not
- required in order to use Spring's declarative transaction support, it
- can help. Spring AOP is thoroughly covered in the AOP chapter.
+ Spring AOP is covered in Conceptually, calling a method on a transactional proxy looks like
@@ -551,96 +537,26 @@
-
- The flow of events is the following. First the set of objects you
- would like to apply AOP transactional advice to are identified. There
- are a variety of ways to configure the Spring IoC container to create
- proxies for the defined object definitions. The standard Spring AOP
- based options are
-
-
-
- ProxyFactoryObject. The common properties
- to set are the reference to the object to proxy (the target object)
- and a reference to the transaction advice. See for more details.
-
-
-
- AutoProxy - Defines criteria to select a collection of objects
- to create a transactional AOP proxy.
-
- The AutoProxy options are
-
-
-
- ObjectNameAutoProxyCreator which
- specifies a collection of object names based on wildcard
- matching of object names. See
-
-
-
- DefaultAdvisorAutoProxyCreator which
- specifies one or more "advisors" i.e an object representing an
- aspect, including both an advice and a pointcut targeting it to
- specific joinpoints. See
-
-
-
-
-
- There is also a convenience subclass of
- ProxyFactoryObject, namely
- TransactionProxyFactoryObject, that sets some common
- default values for the specific case of applying transactional
- advice.
-
- The DefaultAdvisorAutoProxyCreator is very
- powerful and is the means by which Spring can be configured to use
- attributes to identify the pointcuts where transaction advice should be
- applied. The advisor that performs that task is
- TransactionAttributeSourceAdvisor.
- Note, think of the word 'Attribute' in this class name not as
- the .NET attribute but as the transaction 'options' you want to
- specify. This name is inherited from the Java version and the name
- will be changed in the RC1 release to avoid confusion since a common
- naming convention when creating classes are .NET attributes is to
- put the word 'Attribute' in the name.
-
-
- Which one of the many options available should you choose for your
- development? That depends, each one has it own set of pro's and con's
- which will be discussed in turn in the following sections.
-
- With the transactional AOP proxy now created we can discuss the
- flow of events in the code as proxied methods are invoked. When the
- method is invoked, before calling the target object's method, a
- transaction is created if one hasn't already been created. Then the
- target method is invoked. If there was an exception throw, the
- transaction is typically rolled back, but it can also be committed if
- the exception type specified in the transaction option, NoRollbackFor,
- matches the thrown exception. If no exception was thrown, that is taken
- as a sign of success and the transaction is committed.
-
- When using other AOP advice with the transactional advice you can
- set the order of the 'interceptor chain' so that, for example,
- performance monitoring advice always precede the transactional
- advice.
- A First Example
+ Example of declarative transaction implementationConsider the following interface. The intent is to convey the
concepts to you so you can concentrate on the transaction usage and not
- have to worry about domain specific details. The
- ITestObjectManager is a poor-mans business service
- layer - the implementation of which will make two DAO calls. Clearly
- this example is overly simplistic from the service layer perspective as
- there isn't any business logic at all!. The 'service' interface is shown
- below.
+ have to worry about domain specific details.
+
+
+ A QuickStart application for declarative transaction management
+ is included in the Spring.NET distribution and is decribed here.
+
+
+ The ITestObjectManager is a poor-mans business
+ service layer - the implementation of which will make two DAO calls.
+ Clearly this example is overly simplistic from the service layer
+ perspective as there isn't any business logic at all!. The 'service'
+ interface is shown below.public interface ITestObjectManager
{
@@ -657,14 +573,14 @@
// Fields/Properties ommited
- [Transaction()]
+ [Transaction]
public void SaveTwoTestObjects(TestObject to1, TestObject to2)
{
TestObjectDao.Create(to1.Name, to1.Age);
TestObjectDao.Create(to2.Name, to1.Age);
}
- [Transaction()]
+ [Transaction]
public void DeleteTwoTestObjects(string name1, string name2)
{
TestObjectDao.Delete(name1);
@@ -773,8 +689,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
<!-- The object that performs multiple data access operations -->
- <object id="testObjectManager"
- type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
+ <object id="testObjectManager" type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
<property name="TestObjectDao" ref="testObjectDao"/>
</object>
@@ -783,144 +698,10 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
This is standard Spring configuration and as such provides you
with the flexibility to parameterize your connection string and to
- easily switch implementations of your DAO objects. The configuration to
- create a transactional proxy for the manager class is shown
- below.
+ easily switch implementations of your DAO objects.
- <!-- The rest of the config file is common no matter how many objects you add -->
- <!-- that you would like to have declarative tx management applied to -->
-
- <object id="autoProxyCreator"
- type="Spring.Aop.Framework.AutoProxy.DefaultAdvisorAutoProxyCreator, Spring.Aop">
- </object>
-
- <object id="transactionAdvisor"
- type="Spring.Transaction.Interceptor.TransactionAttributeSourceAdvisor, Spring.Data">
- <property name="TransactionInterceptor" ref="transactionInterceptor"/>
- </object>
-
-
- <!-- Transaction Interceptor -->
- <object id="transactionInterceptor"
- type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
- <property name="TransactionManager" ref="transactionManager"/>
- <property name="TransactionAttributeSource" ref="attributeTransactionAttributeSource"/>
- </object>
-
- <object id="attributeTransactionAttributeSource"
- type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data">
- </object>
-
-
- Granted this is a bit verbose and hard to grok at first sight -
- however you only need to grok this once as it is 'boiler plate' XML you
- can reuse across multiple projects. What these object definitions are
- doing is to instruct Spring's to look for all objects within the IoC
- configuration that have the [Transaction] attribute and then apply the
- AOP transaction interceptor to them based on the transaction options
- contained in the attribute. The attribute serves both as a pointcut and
- as the declaration of transactional option information.
-
- Since this XML fragment is not tied to any specific object
- references it can be included in its own file and then imported via the
- <import> element. In examples and test code this XML configuration
- fragment is named autoDeclarativeServices.xml See for more information.
-
- The classes and their roles in this configuration fragment are
- listed below
-
-
-
- TransactionInterceptor is the AOP advice
- responsible for performing transaction management
- functionality.
-
-
-
- TransactionAttributeSourceAdvisor is an AOP
- Advisor that holds the TransactionInterceptor, which is the advice,
- and a pointcut (where to apply the advice), in the form of a
- TransactionAttributeSource.
-
-
-
- AttributesTransactionAttributeSource is an
- implementation of the ITransactionAttributeSource
- interface that defines where to get the transaction metadata
- defining the transaction semantics (isolation level, propagation
- behavior, etc) that should be applied to specific methods of
- specific classes. The transaction metadata is specified via
- implementations of the
- ITransactionAttributeSource interface. This
- example shows the use of the implementation
- Spring.Transaction.Interceptor.AttributesTransactionAttributeSource
- to obtain that information from standard .NET attributes. By the
- very nature of using standard .NET attributes, the attribute serves
- double duty in identifying the methods where the transaction
- semantics apply. Alternative implementations of
- ITransactionAttributeSource available are
- MatchAlwaysTransactionAttributeSource,
- NameMatchTransactionAttributeSource, or
- MethodMapTransactionAttributeSource.
-
-
-
- MatchAlwaysTransactionAttributeSource
- is configured with a ITransactionAttribute instance that is
- applied to all methods. The shorthand string representation,
- i.e. PROPAGATION_REQUIRED can be used
-
-
-
- AttributesTransactionAttributeSource :
- Use a standard. .NET attributes to specify the transactional
- information. See TransactionAttribute class
- for more information.
-
-
-
- NameMatchTransactionAttributeSource
- allows ITransactionAttributes to be matched by method name. The
- NameMap IDictionary property is used to specify the mapping. For
- example
-
- <object name="nameMatchTxAttributeSource" type="Spring.Transaction.Interceptor.NameMatchTransactionAttributeSource, Spring.Data"
- <property name="NameMap">
- <dictionary>
- <entry key="Execute" value="PROPAGATION_REQUIRES_NEW, -ApplicationException"/>
- <entry key="HandleData" value="PROPAGATION_REQUIRED, -DataHandlerException"/>
- <entry key="Find*" value="ISOLATION_READUNCOMMITTED, -DataHandlerException"/>
- </dictionary>
- </property>
-
-</object>
-
- Key values can be prefixed and/or suffixed with wildcards
- as well as include the full namespace of the containing
- class.
-
-
-
- MethodMapTransactionAttributeSource :
- Similar to NameMatchTransactionAttributeSource but specifies
- that only fully qualified method names (i.e. type.method,
- assembly) and wildcards can be used at the start or end of the
- method name for matching multiple methods.
-
-
-
-
-
- DefaultAdvisorAutoProxyCreator: looks for
- Advisors in the context, and automatically creates proxy objects
- which are the transactional wrappers
-
-
-
- Refer to the following section for a more convenient way to
- achieve the same goal of declarative transaction management using
- attributes.
+ The following section shows how to configure the declarative
+ transactions using Spring's transaction namespace.
@@ -1554,13 +1335,12 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
if you choose not to use the transaction namespace for declarative
transaction management then you can use 'lower level' object definitions
- to configure declarative transactions. This approach was shown in the
- first example. The use of
- Spring's autoproxy functionality defines criteria to select a collection
- of objects to create a transactional AOP proxy. There are two AutoProxy
- classes that you can use, ObjectNameAutoProxyCreator
- and DefaultAdvisorAutoProxyCreator. If you are using
- the new transaction namespace support you do not need to configure these
+ to configure declarative transactions. The use of Spring's autoproxy
+ functionality defines criteria to select a collection of objects to
+ create a transactional AOP proxy. There are two AutoProxy classes that
+ you can use, ObjectNameAutoProxyCreator and
+ DefaultAdvisorAutoProxyCreator. If you are using the
+ new transaction namespace support you do not need to configure these
objects as a DefaultAdvisorAutoProxyCreator is created 'under the
covers' while parsing the transaction namespace elements
@@ -1593,219 +1373,11 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
Creating transactional proxies with
DefaultAdvisorAutoProxyCreator
- This is a commonly used way to configure declarative
- transactions since it enables you to refer to the transaction
- attribute as the pointcut to use for the transactional advice for any
- object definition defined in the IoC container. An example of this
- configuration approach was shown in Chapter 5.
+ This is not longer a common way to configure declarative
+ transactions but is discussed in the "Classic Spring" appendiex here.
-
-
- Declarative Transactions using
- TransactionProxyFactoryObject
-
- The TransactionProxyFactoryObject is easier to use than a
- ProxyFactoryObject for most cases since the transaction interceptor and
- transaction attributes are properties of this object. This removes the
- need to declare them as separate objects. Also, unlike the case with the
- ProxyFactoryObject, you do not have to give fully qualified method
- names, just the normal 'short' method name. Wild card matching on the
- method name is also allowed, which in practice helps to enforce a common
- naming convention for the methods of your DAOs. The example from chapter
- 5 is shown here using a TransactionProxyFactoryObject.
-
-
- <object id="testObjectManager"
- type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
-
- <property name="PlatformTransactionManager" ref="adoTransactionManager"/>
- <property name="Target">
- <object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
- <property name="TestObjectDao" ref="testObjectDao"/>
- </object>
- </property>
- <property name="TransactionAttributes">
- <name-values>
- <add key="Save*" value="PROPAGATION_REQUIRED"/>
- <add key="Delete*" value="PROPAGATION_REQUIRED"/>
- </name-values>
- </property>
- </object>
-
-
-
- Note the use of an inner object definition for the target which
- will make it impossible to obtain an unproxied reference to the
- TestObjectManager.
-
- As can be seen in the above definition, the TransactionAttributes
- property holds a collection of name/value pairs. The key of each pair is
- a method or methods (a * wildcard ending is optional) to apply
- transactional semantics to. Note that the method name is not qualified
- with a package name, but rather is considered relative to the class of
- the target object being wrapped. The value portion of the name/value
- pair is the TransactionAttribute itself that needs to be applied. When
- specifying it as a string value as in this example, it's in String
- format as defined by TransactionAttributeConverter. This format
- is:
-
- PROPAGATION_NAME,ISOLATION_NAME,readOnly,timeout_NNNN,+Exception1,-Exception2
-
- Note that the only mandatory portion of the string is the
- propagation setting. The default transactions semantics which apply are
- as follows:
-
-
-
- Exception Handling: All exceptions thrown trigger a
- rollback.
-
-
-
- Transactions are read/write
-
-
-
- Isolation Level:
- TransactionDefinition.ISOLATION_DEFAULT
-
-
-
- Timeout: TransactionDefinition.TIMEOUT_DEFAULT
-
-
-
- Multiple rollback rules can be specified here, comma-separated. A
- - prefix forces rollback; a + prefix specifies commit. Under the covers
- the IDictionary of name value pairs will be converted to an instance of
- NameMatchTransactionAttributeSource
-
- The string used for PROPAGATION_NAME are those defined on the
- Spring.Transaction.TransactionPropagation enumeration, namely Required,
- Supports, Mandatory, RequiresNew, NotSupported, Never, Nested. The
- string used for ISOLATION_NAME are those defined on the
- System.Data.IsolationLevel enumberateion, namely ReadCommitted,
- ReadUncommitted, RepeatableRead, Serializable.
-
- The TransactionProxyFactoryObject allows you to set optional "pre"
- and "post" advice, for additional interception behavior, using the
- "PreInterceptors" and "PostInterceptors" properties. Any number of pre
- and post advices can be set, and their type may be Advisor (in which
- case they can contain a pointcut), MethodInterceptor or any advice type
- supported by the current Spring configuration (such as ThrowsAdvice,
- AfterReturningAdvice or BeforeAdvice, which are supported by default.)
- These advices must support a shared-instance model. If you need
- transactional proxying with advanced AOP features such as stateful
- mixins, it's normally best to use the generic ProxyFactoryObject, rather
- than the TransactionProxyFactoryObject convenience proxy creator.
-
-
-
- Concise proxy definitions
-
- Using abstract object definitions in conjunction with a
- TransactionProxyFactoryObject provides you a more concise means to reuse
- common configuration information instead of duplicating it over and over
- again with a definition of a TransactionProxyFactoryObject per object.
- Objects that are to be proxied typically have the same pattern of method
- names, Save*, Find*, etc. This commonality can be placed in an abstract
- object definition, which other object definitions refer to and change
- only the configuration information that is different. An abstract object
- definition is shown below
-
- <object id="txProxyTemplate" abstract="true"
- type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject, Spring.Data">
-
- <property name="PlatformTransactionManager" ref="adoTransactionManager"/>
-
- <property name="TransactionAttributes">
- <name-values>
- <add key="Save*" value="PROPAGATION_REQUIRED"/>
- <add key="Delete*" value="PROPAGATION_REQUIRED"/>
- </name-values>
- </property>
- </object>
-
- Subsequent definitions can refer to this 'base' configuration as
- shown below
-
- <object id="testObjectManager" parent="txProxyTemplate">
- <property name="Target">
- <object type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
- <property name="TestObjectDao" ref="testObjectDao"/>
- </object>
- </property>
-</object>
-
-
-
- Declarative Transactions using ProxyFactoryObject
-
- Using the general ProxyFactoryObject to declare transactions gives
- you a great deal of control over the proxy created since you can specify
- additional advice, such as for logging or performance. Based on the
- example shown previously a sample configuration using ProxyFactoryObject
- is shown below
-
- <object id="testObjectManagerTarget" type="Spring.Data.TestObjectManager, Spring.Data.Integration.Tests">
- <property name="TestObjectDao" ref="testObjectDao"/>
- </object>
-
- <object id="testObjectManager" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
-
- <property name="Target" ref="testObjectManagerTarget"/>
- <property name="ProxyInterfaces">
- <value>Spring.Data.ITestObjectManager</value>
- </property>
- <property name="InterceptorNames">
- <value>transactionInterceptor</value>
- </property>
-
- </object>
-
- The ProxyFactoryObject will create a proxy for the Target, i.e. a
- TestObjectManager instance. An inner object definition could also have
- been used such that it would make it impossible to obtain an unproxied
- object from the container. The interceptor name refers to the following
- definition.
-
- <object id="transactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
-
- <property name="TransactionManager" ref="adoTransactionManager"/>
-
- <!-- note do not have converter from string to this property type registered -->
- <property name="TransactionAttributeSource" ref="methodMapTransactionAttributeSource"/>
- </object>
-
- <object name="methodMapTransactionAttributeSource"
- type="Spring.Transaction.Interceptor.MethodMapTransactionAttributeSource, Spring.Data">
- <property name="MethodMap">
- <dictionary>
- <entry key="Spring.Data.TestObjectManager.SaveTwoTestObjects, Spring.Data.Integration.Tests"
- value="PROPAGATION_REQUIRED"/>
- <entry key="Spring.Data.TestObjectManager.DeleteTwoTestObjects, Spring.Data.Integration.Tests"
- value="PROPAGATION_REQUIRED"/>
- </dictionary>
- </property>
- </object>
-
- The transaction options for each method are specified using a
- dictionary containing the class name + method name, assembly as the key
- and the value is of the form
-
-
-
- <Propagation Behavior>, <Isolation Level>,
- <ReadOnly>, -Exception, +Exception
-
-
-
- All but the propagation behavior are optional. The + and - are
- used in front of the name of an exception. Minus indicates to rollback
- if the exception is thrown, the Plus indicates to commit if the
- exception is thrown.
-