INT-1552 doc polishing
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
<para><emphasis>MessageChannel</emphasis> - Direct interactions with MessageChannel methods (e.g., channel.send(message))</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>Message Publisher</emphasis> - the way to initiate message flow as a bi-product of method invocations on Spring beans</para>
|
||||
<para><emphasis>Message Publisher</emphasis> - the way to initiate message flow as the by-product of method invocations on Spring beans</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>Inbound Channel Adapters/Gateways</emphasis> - the way to initiate message flow based on connecting third-party
|
||||
@@ -38,75 +38,74 @@
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
These 6 cold be split in 2 general categories:
|
||||
These 6 could be split in 2 general categories:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>Message flows initiated by a USER process</emphasis> - Example scenarios in this category
|
||||
would be invoking a Gateway method or explicitly sending a Message to a MessageChannel. In other words these message flows depend on third
|
||||
party process (e.g., some code that we wrote) to be initiated</para>
|
||||
would be invoking a Gateway method or explicitly sending a Message to a MessageChannel. In other words, these message flows depend on a third
|
||||
party process (e.g., some code that we wrote) to be initiated.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><emphasis>Message flows initiated by the DAEMON process</emphasis> - Example scenarios in this category would be a Poller
|
||||
polling for a Message queue to initiate a new Message flow with the polled Message or a Scheduler scheduling the
|
||||
process, by creating a new Message and initiating a message flow at a predefined time</para>
|
||||
<para><emphasis>Message flows initiated by a DAEMON process</emphasis> - Example scenarios in this category would be a Poller
|
||||
polling a Message queue to initiate a new Message flow with the polled Message or a Scheduler scheduling the
|
||||
process by creating a new Message and initiating a message flow at a predefined time.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
Clearly the <emphasis>Gateway Proxy</emphasis>, <emphasis>MessageChannel.send(..)</emphasis> and <emphasis>MessagePublisher</emphasis> are
|
||||
all belong to the 1st category and <emphasis>Inbound Adapters/Gateways</emphasis>, <emphasis>Scheduler</emphasis> and <emphasis>Poller</emphasis> belong to the 2nd.
|
||||
Clearly the <emphasis>Gateway Proxy</emphasis>, <emphasis>MessageChannel.send(..)</emphasis> and <emphasis>MessagePublisher</emphasis>
|
||||
all belong to the 1st category and <emphasis>Inbound Adapters/Gateways</emphasis>, <emphasis>Scheduler</emphasis> and <emphasis>Poller</emphasis>
|
||||
belong to the 2nd.
|
||||
</para>
|
||||
<para>
|
||||
So, how do we address transactional needs in various scenarios within each category and is there a need for Spring Integration
|
||||
to provide something explicitly with regard to transaction for a particular scenario or Spring's Transaction Support could be leveraged instead?.
|
||||
to provide something explicitly with regard to transactions for a particular scenario? Or, can Spring's Transaction Support be leveraged instead?.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
First of all, the first and obvious goal is NOT to re-invent something that has already been invented unless you can provide a beter solution.
|
||||
In our case Spring itself provides a first class support for transaction management. So our goal here is not to provide something new but rather
|
||||
The first and most obvious goal is NOT to re-invent something that has already been invented unless you can provide a better solution.
|
||||
In our case Spring itself provides first class support for transaction management. So our goal here is not to provide something new but rather
|
||||
delegate/use Spring to benefit from the existing support for transactions. In other words as a framework we must expose hooks to the Transaction management functionality
|
||||
provided by Spring. But since Spring Integration configuration is based on Spring Configuration it is not always neccessery to expose these hooks as they already
|
||||
expposed via Spring natively. Remeber every Spring Integration component is a Spring Bean after all.
|
||||
provided by Spring. But since Spring Integration configuration is based on Spring Configuration it is not always necessary to expose these hooks as they
|
||||
are already exposed via Spring natively. Remember every Spring Integration component is a Spring Bean after all.
|
||||
</para>
|
||||
<para>
|
||||
With this goal in mind let's look at the two scenarios.
|
||||
</para>
|
||||
<para>
|
||||
If you think about it, Message flows that are initiated by the <emphasis>USER process</emphasis> (Category 1) and obviously configured in Spring Application Context,
|
||||
are subject to transactional configuration of such process and therefore don't need to be explicitly configured by Spring Integration to support transactions.
|
||||
The transaction could and should be initiated by such process through standard Transaction support provided by Spring and Spring Integration message flow will honor
|
||||
transactional semantics of the components naturally because it is Spring configured. For example; A Gateway or ServiceActivator methods could
|
||||
be annotated with <classname>@Transactional</classname> or <classname>TransactionInterceptor</classname> could be configured in XML configuration
|
||||
with point-cut expression pointing to specific methods that should be transactional.
|
||||
The bottom line you have full control over transaction configuration and boundaries in these scenarios.
|
||||
If you think about it, Message flows that are initiated by the <emphasis>USER process</emphasis> (Category 1) and obviously configured in a Spring Application Context,
|
||||
are subject to transactional configuration of such processes and therefore don't need to be explicitly configured by Spring Integration to support transactions.
|
||||
The transaction could and should be initiated through standard Transaction support provided by Spring. The Spring Integration message flow will honor
|
||||
the transactional semantics of the components naturally because it is Spring configured. For example, a Gateway or ServiceActivator method could
|
||||
be annotated with <classname>@Transactional</classname> or <classname>TransactionInterceptor</classname> could be defined in an XML configuration
|
||||
with a point-cut expression pointing to specific methods that should be transactional.
|
||||
The bottom line is that you have full control over transaction configuration and boundaries in these scenarios.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
However, things are a bit different when it comes to Message flows initiated by the <emphasis>DAEMON process</emphasis> (Category 2).
|
||||
Although configured by the developer these flows do not directly involve human or some other process to be initiated. These are trigger-based flows
|
||||
Although configured by the developer these flows do not directly involve a human or some other process to be initiated. These are trigger-based flows
|
||||
that are initiated by a trigger process (DAEMON process) based on the configuration of such process. For example, we could have a Scheduler
|
||||
initiating a message flow every Friday night of every week. We can also configure a trigger that initiates a Message flow every second, etc.
|
||||
So, we obviously need the same way to let these trigger-based processes know of our intention to make these Message flows transactional so
|
||||
Transaction context could be created whenever a new Message flow is initiated. In other words we need to expose some Transaction configuration, but ONLY enough
|
||||
So, we obviously need a way to let these trigger-based processes know of our intention to make the resulting Message flows transactional so that
|
||||
a Transaction context could be created whenever a new Message flow is initiated. In other words we need to expose some Transaction configuration, but ONLY enough
|
||||
to delegate to Transaction support already provided by Spring (as we do in other scenarios).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Spring Integration provides transactional support for Pollers. Pollers are a special case comoponents becouse
|
||||
Spring Integration provides transactional support for Pollers. Pollers are a special type of component because
|
||||
we can call receive() within that poller task against a resource that is itself transactional thus including <emphasis>receive()</emphasis>
|
||||
call in the the boundaries of the Transaction allowing it to be rolled back in case of a task failure. If we were to add the same support
|
||||
for channels, the added transactions would affect all downstream components starting with that <emphasis>send()</emphasis> call. That is
|
||||
providing a rather wide scope for transaction demarcation without any strong reason especially when Spring already provides several way to
|
||||
address transactional needs of any component downstream. However the <emphasis>receive()</emphasis> method being included in a transaction
|
||||
boundary is the "strong reason" for pollers.
|
||||
|
||||
|
||||
providing a rather wide scope for transaction demarcation without any strong reason especially when Spring already provides several ways to
|
||||
address the transactional needs of any component downstream. However the <emphasis>receive()</emphasis> method being included in a transaction
|
||||
boundary is the "strong reason" for pollers.
|
||||
</para>
|
||||
|
||||
<section id="transaction-poller">
|
||||
<title>Poller Transaction Support</title>
|
||||
<para>
|
||||
Any time you configure a Poller you can provide transactional configuration via <emphasis>transactional</emphasis> element and its attributes:
|
||||
Any time you configure a Poller you can provide transactional configuration via the <emphasis>transactional</emphasis> sub-element and its attributes:
|
||||
<programlisting language="xml"><![CDATA[<poller max-messages-per-poll="1" fixed-rate="1000">
|
||||
<transactional transaction-manager="txManager"
|
||||
isolation="DEFAULT"
|
||||
@@ -114,27 +113,27 @@
|
||||
read-only="true"
|
||||
timeout="1000"/>
|
||||
</poller>]]></programlisting>
|
||||
As you can see this configuration looks evry similar to native Spring transaction configuration. You must still provide reference to Transaction manager and specify
|
||||
transaction attributes or rely on defauls (e.g., if 'transaction-manager'' attribute is not specified then it will default to the bean with the name 'transactionManager').
|
||||
Internally the process would be wrapped in the Spring's native Transaction where <classname>TransactionInterceptor</classname> is responsible to handle transactions.
|
||||
For more information on how to configure Transaction Manager, the types of Transaction Managers (e.g., JTA, Datasource etc.) and other details related to
|
||||
As you can see this configuration looks very similar to native Spring transaction configuration. You must still provide a reference to a Transaction manager and specify
|
||||
transaction attributes or rely on defaults (e.g., if the 'transaction-manager' attribute is not specified, it will default to the bean with the name 'transactionManager').
|
||||
Internally the process would be wrapped in Spring's native Transaction where <classname>TransactionInterceptor</classname> is responsible for handling transactions.
|
||||
For more information on how to configure a Transaction Manager, the types of Transaction Managers (e.g., JTA, Datasource etc.) and other details related to
|
||||
transaction configuration please refer to Spring's Reference manual (Chapter 10 - Transaction Management).
|
||||
</para>
|
||||
<para>
|
||||
With the above configuration all Message flows initiated by this poller will be transactional. For more information and details on
|
||||
With the above configuration all Message flows initiated by this poller will be transactional. For more information and details on a
|
||||
Poller's transactional configuration please refer to section - <emphasis>21.1.1. Polling and Transactions</emphasis>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There times when besides transaction several more cross cutting concerns needs to be addressed when running Poller. To help with that,
|
||||
Poller element defines <emphasis><advice-chain> </emphasis> sub-element which allows you to define a custom chain of Advices
|
||||
to be applied on the Poller. (see section 4.4 for more details)
|
||||
In Spring Integration 2.0 Poller went through the major refactoring effort and is now using proxy mechanism to address transactional
|
||||
concerns as well as other cross cutting concerns, one of the significant changes evolving from this effort is that we
|
||||
made <emphasis><transactional></emphasis> and <emphasis><advice-chain></emphasis> elements mutually exclusive.
|
||||
The rational behind this is; If you need more then one advice, and one of them is Transaction advice, then you can simply
|
||||
Along with transactions, several more cross cutting concerns might need to be addressed when running a Poller. To help with that,
|
||||
the Poller element accepts an <emphasis><advice-chain> </emphasis> sub-element which allows you to define a custom chain of Advice
|
||||
instances to be applied on the Poller. (see section 4.4 for more details)
|
||||
In Spring Integration 2.0, the Poller went through the a refactoring effort and is now using a proxy mechanism to address transactional
|
||||
concerns as well as other cross cutting concerns. One of the significant changes evolving from this effort is that we
|
||||
made <emphasis><transactional></emphasis> and <emphasis><advice-chain></emphasis> elements mutually exclusive.
|
||||
The rationale behind this is that if you need more than one advice, and one of them is Transaction advice, then you can simply
|
||||
include it in the <emphasis><advice-chain></emphasis> with the same convenience as before but with much more control
|
||||
since you now have an option to position any advice in the desired order.
|
||||
since you now have an option to position any advice in the desired order.
|
||||
<programlisting language="xml"><![CDATA[<poller max-messages-per-poll="1" fixed-rate="10000">
|
||||
<advice-chain>
|
||||
<ref bean="txAdvice"/>
|
||||
@@ -153,23 +152,25 @@
|
||||
|
||||
As yo can see from the example above, we have provided a very basic XML-based configuration of Spring Transaction advice - "txAdvice" and
|
||||
included it within the <emphasis><advice-chain></emphasis> defined by the Poller.
|
||||
|
||||
And if you only need to address transactional concerns of the Poller, then you can still use <emphasis><transactional></emphasis> element
|
||||
If you only need to address transactional concerns of the Poller, then you can still use the <emphasis><transactional></emphasis> element
|
||||
as a convinience.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section id="transaction-boundaries">
|
||||
<title>Transaction Boundaries</title>
|
||||
<para>
|
||||
Another important factor that needs to be understood is the boundaries of the Transactions within the Message flow.
|
||||
When transaction is started, transaction context is bound to the current thread. So regardless of how many endpoints and channels you have in your
|
||||
Message flow you transaction context will be preserved as long as you are ensuring that the flow continues on the same thread.
|
||||
As soon as you break it by introducing a <emphasis>Pollable Channel</emphasis> or <emphasis>Executor Channel</emphasis> or initiate a new thread manually in some
|
||||
service, the Transactional boundary will be broken as well. Essentially the Transaction will END right there and if
|
||||
successfull hand of happened between the threads, the flow would be considered a success and COMMIT signal would be sent
|
||||
even though the flow might still result in the exception somewhere downstream. If such flow was synchronous the exception would be thrown back to the
|
||||
initiator of the Message flow who is also the initiator of the transactional context and transaction would result in a ROLLBACK.
|
||||
Another important factor is the boundaries of Transactions within a Message flow.
|
||||
When a transaction is started, the transaction context is bound to the current thread. So regardless of how many endpoints and channels you have in your
|
||||
Message flow your transaction context will be preserved as long as you are ensuring that the flow continues on the same thread.
|
||||
As soon as you break it by introducing a <emphasis>Pollable Channel</emphasis> or <emphasis>Executor Channel</emphasis> or initiate a new thread manually
|
||||
in some service, the Transactional boundary will be broken as well. Essentially the Transaction will END right there, and if
|
||||
a successful handoff has transpired between the threads, the flow would be considered a success and a COMMIT signal would be sent
|
||||
even though the flow will continue and might still result in an Exception somewhere downstream. If such a flow were synchronous, that Exception could
|
||||
be thrown back to the initiator of the Message flow who is also the initiator of the transactional context and the transaction would result in a ROLLBACK.
|
||||
The middle ground is to use transactional channels at any point where a thread boundary is being broken. For example, you can use a Queue-backed Channel
|
||||
that delegates to a transactional MessageStore strategy, or you could use a JMS-backed channel.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user