What
is the difference between concern and cross-cutting concern in Spring AOP?
Concern is behavior which we want to
have in a module of an application.
Concern may be defined as a functionality we want to implement to solve a
specific business problem. E.g. in any eCommerce application different concerns
(or modules) may be inventory management, shipping management, user management
etc.
Cross-cutting concern is a concern
which is applicable throughout the application (or more than one module). e.g. logging , security and data transfer are the concerns
which are needed in almost every module of an application, hence they are
termed as cross-cutting concerns.
Main java based AOP implementations
are listed below :
An advice is the implementation of
cross-cutting concern which you are interested in applying on other modules of
your application. Advices are of mainly 5 types :
- Before advice : Advice that executes before a join point, but which does not have the ability to prevent execution flow proceeding to the join point (unless it throws an exception). To use this advice, use @Before annotation.
- After returning advice : Advice to be executed after a join point completes normally. For example, if a method returns without throwing an exception. To use this advice, use @AfterReturning annotation.
- After throwing advice : Advice to be executed if a method exits by throwing an exception. To use this advice, use @AfterThrowing annotation.
- After advice : Advice to be executed regardless of the means by which a join point exits (normal or exceptional return). To use this advice, use @After annotation.
- Around advice : Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. To use this advice, use @Around annotation.
What
is Joint point and Point cut?
Join point is a point of execution
of the program, such as the execution of a method or the handling of an
exception. In Spring AOP, a join point always represents a method execution.
For example, all the methods defined inside your EmployeeManager
interface cab be considered joint points if you apply any cross-cutting concern
of them.
Pointcut is a predicate or expression that matches join points.
Advice is associated with a pointcut expression and runs at any join point
matched by the pointcut (for example, expression “execution(*
EmployeeManager.getEmployeeById(..))” to match getEmployeeById()
the method in EmployeeManager interface). The concept of
join points as matched by pointcut expressions is central to AOP, and Spring
uses the AspectJ pointcut expression language by default.
There are 7 types of propagation
supported by Spring :
- PROPAGATION_REQUIRED – Support a current transaction; create a new one if none exists.
- PROPAGATION_SUPPORTS – Support a current transaction; execute non-transactionally if none exists.
- PROPAGATION_MANDATORY – Support a current transaction; throw an exception if no current transaction exists.
- PROPAGATION_REQUIRES_NEW – Create a new transaction, suspending the current transaction if one exists.
- PROPAGATION_NOT_SUPPORTED – Do not support a current transaction; rather always execute non-transactionally.
- PROPAGATION_NEVER – Do not support a current transaction; throw an exception if a current transaction exists.
- PROPAGATION_NESTED – Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
In most cases, you may just need to
use the PROPAGATION_REQUIRED.
In Spring's terminology, transaction management can be done in the following ways:
|
Type
|
Definition
|
Way of
implementing
|
|
Declarative Transactions
|
When you do something outside your business logic i.e with
some simple configuration you apply a common functionality across all your
code.
|
Using
@Transactional
annotation |
|
Using xml based aop configuration to have a transactional
advice
|
||
|
Programmatic Transactions
|
When you add code some functionality by urself so that you
could control each and everything by urself. This usually mixes the unrelated
functionality in your business logic.
|
Using
PlatformTransactionManager |
|
Using
TransactionTemplate |
Spring Declarative transaction management
1. Annotation style transaction
To use the annotation style transaction management all you have to do is to add a 3 simple bean configuration in your xml file i.e:- <context:annotation-config/>:
Tells Spring framework to read
@Transactionalannotation - <tx:annotation-driven/>: Automatically adds transaction support which eventually wraps your code in transaction scope
- Initializing DataSourceTransactionManager bean
Xml configuration for enabling @Transactional annotation
16.<context:annotation-config/>
17.<!-- Add this tag to enable annotations transactions -->
18.<tx:annotation-driven transaction-manager="transactionManager"/>
19.<bean id="transactionManager"
20. class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
21. <property name="dataSource" ref="dataSource"></property>
22.</bean>
23.<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
24. <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
25. <property name="url" value="jdbc:mysql://localhost:3306/apu"></property>
26. <property name="username" value="root"></property>
27. <property name="password" value=""></property>
28.</bean>
29.
30.<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
31. <property name="dataSource" ref="dataSource"></property>
32.</bean>
33.<bean id="userDao" class="springjdbc.transactions.declarative.annotations.AnnotatedUserDao">
34. <property name="jdbcTemplate" ref="jdbcTemplate"></property>
35.</bean>
36.NOTE! Dont forget to change the username and password in the above bean accordingly.
Using @Transaction in code
Following is a Dao class that uses@Transactional
annotation to add declarative transactions. @Transactional
at class level wraps all method in transaction scope. The @Transactional annotation has several properties
like readOnly, isolation, propagation,rollbackFor, noRollbackFor etc
that can be used to control how one transaction behaves and communicate with
other transactions. We use readOnly property of @Transactional
to mark the method eligible only for making select queries when @Transactional(readOnly=true) and update, insert
queries in case @Transactional(readOnly=false).
By default readOnly is false, which means you can perform all the CRUD
operations, change it to true will allow only select statements to be executed.
Other very useful properties of @Transactional
is rollbackFor and noRollbackFor. By default Spring rolls back the transaction
for exceptions of type RuntimeException
or unchecked exceptions. AnnotatedUserDao.java
1. /**
2. * @author achauhan
3. */
4. @Transactional
5. public class AnnotatedUserDao implements IUserDao {
6. private JdbcTemplate jdbcTemplate;
7.
8. public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
9. this.jdbcTemplate = jdbcTemplate;
10.}
11.
12.public void deleteUser(int uid) {
13. String delQuery = "delete from users where id = ?";
14. jdbcTemplate.update(delQuery, new Object[] { uid });
15.
16.}
17.
18.public int insertUser(User user) {
19. String inserQuery = "insert into users (username, password, enabled , id) values (?, ?, ?, ?) ";
20. Object[] params = new Object[] { user.getUserName(),
21. user.getPassword(), user.isEnabled(), user.getId() };
22. int[] types = new int[] { Types.VARCHAR, Types.VARCHAR, Types.BIT,
23. Types.INTEGER };
24. int number = jdbcTemplate.update(inserQuery, params, types);
25. return number;
26.}
27.
28.// override the class level transactional behaviour for select method
29.@Transactional(readOnly = true)
30.public User selectUser(int uid) {
31.// for all the RuntimeExceptions the transactions will be automatically
32.// rolled back
33. throw new RuntimeException("A runtime exception");
34.
35.}
36.
37.public int updateUser(User user) throws Exception {
38. throw new Exception("A checked exception");
39.}
40.IMPORTANT! The above methods
selectUser and updateUser
are intentionally left blank so that users could understand the rollback
behaviour of transactions The
selectUser method throws a RuntimeException. When Spring notices that the
method is throwing a RuntimeException
it automatically rolls back the transaction. Contrary to this is the call to updateUser which throws a checked exception. When
spring sees that exception is checked exception, it proceeds to commit the
transactions. To get a deep understanding of what Spring is doing behind the
scenes, you can switch the log4j level to trace and check out the console. Overriding default rollback behaviour
To override the default rollback behaviour, we use the rollbackFor and noRollbackFor properties of@Transactional.
So taking the example of selectUser
method which throws a RuntimeException.
To tell the Spring that it should not roll back the transaction in this case,
we will write : @Transactional(readOnly =
true,noRollbackFor=RuntimeException.class)Now if you call the
selectUser
method, following trace is seen on console. Following is the comparison of console output with default rollback setting and with overriden rollback setting for
selectUser method call. @Transactional(readOnly = true)
13.20:57:29,141 TRACE [TransactionInterceptor] Getting transaction for [springjdbc.IUserDao.selectUser]
14.20:57:29,142 TRACE [TransactionInterceptor] Completing transaction for [springjdbc.IUserDao.selectUser] after exception: java.lang.RuntimeException: A runtime exception
15.20:57:29,142 TRACE [RuleBasedTransactionAttribute] Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: A runtime exception
16.20:57:29,142 TRACE [RuleBasedTransactionAttribute] Winning rollback rule is: null
17.20:57:29,142 TRACE [RuleBasedTransactionAttribute] No relevant rollback rule found: applying default rules
18.20:57:29,142 DEBUG [DataSourceTransactionManager] Initiating transaction rollback
19.
@Transactional(readOnly =
true,noRollbackFor=RuntimeException.class) 13.21:25:07,694 TRACE [TransactionInterceptor] Getting transaction for [springjdbc.IUserDao.selectUser]
14.21:25:07,695 TRACE [TransactionInterceptor] Completing transaction for [springjdbc.IUserDao.selectUser] after exception: java.lang.RuntimeException: A runtime exception
15.21:25:07,695 TRACE [RuleBasedTransactionAttribute] Applying rules to determine whether transaction should rollback on java.lang.RuntimeException: A runtime exception
16.21:25:07,696 TRACE [RuleBasedTransactionAttribute] Winning rollback rule is: NoRollbackRuleAttribute with pattern [java.lang.RuntimeException]
17.21:25:07,697 DEBUG [DataSourceTransactionManager] Initiating transaction commit
18.Our test class is similar to the one we used in JdbcTemplate tutorial.
2. Xml based Transaction configuration
To use the Xml based Spring Transaction management all you have to do is to add 3 simple bean configuration in your xml file i.e:- Initializing DataSourceTransactionManager bean
- <tx:advice />:
Configures the transaction advice. In this advice we configure various
transaction properties for different methods. So what was earlier written
as
@Transactional(readOnly = true)will now be written as<tx:method name="select*" read-only="true" />. - <aop:config/>: Final step is to apply the transaction advice using aop configuration.
<context:annotation-config />
<bean
id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource"
ref="dataSource"></property>
</bean>
<tx:advice
id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="select*"
read-only="true" />
<tx:method name="*"
/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="userDaoTxPointcut"
expression="execution(* springjdbc.IUserDao.*(..))"
/>
<aop:advisor advice-ref="txAdvice"
pointcut-ref="userDaoTxPointcut" />
</aop:config>
<bean
id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="com.mysql.jdbc.Driver"></property>
<property name="url"
value="jdbc:mysql://localhost:3306/apu"></property>
<property name="username"
value="root"></property>
<property name="password"
value=""></property>
</bean>
<bean
id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource"
ref="dataSource"></property>
</bean>
<bean
id="userDao" class="springjdbc.transactions.declarative.xml.UserDao">
<property name="jdbcTemplate"
ref="jdbcTemplate"></property>
</bean>The dao class will be same as the AnnotatedUserDao we have seen above but without Spring
@Transactional
annotation. Ref:-
http://www.simplespringtutorial.com/springDeclarativeTransactions.html
No comments:
Post a Comment