Spring Framework Module 3 – AOP
2 Spring Framework :: AOP :: Example class UserService { public UserDTO getUser(Integer id) { UserDTO user = userDAO.getUser(id); return user; } } Look at the method to get user by id:
3 Spring Framework :: AOP :: Example public UserDTO getUser(Integer id) { UserDTO user = userDAO.getUser(id); return user; } Look at the method to get user by id: public UserDTO getUser(Integer id) { LOG.debug("Call method getUser with id " + id); UserDTO user = userDAO.getUser(id); LOG.debug(User info is: " + user.toString()); return user; } Add logging:
4 Spring Framework :: AOP :: Example public UserDTO getUser(Integer id) throws ServiceException{ LOG.debug("Call method getUser with id " + id); UserDTO user = null; UserDTO user = userDAO.getUser(id); try { user = userDAO.getUser(id); } catch(SQLException e) { throw new ServiceException(e); } LOG.debug(User info is: " + user.toString()); return user; } Add exception handling:
5 Spring Framework :: AOP :: Example public UserDTO getUser(Integer id) throws ServiceException, AuthException { if (!SecurityContext.getUser().hasRight("GetUser")) throw new AuthException("Permission Denied"); LOG.debug("Call method getUser with id " + id); UserDTO user = null; UserDTO user = userDAO.getUser(id); try { user = userDAO.getUser(id); } catch(SQLException e) { throw new ServiceException(e); } LOG.debug(User info is: " + user.toString()); return user; } Add user rights check:
6 Spring Framework :: AOP :: Example public UserDTO getUser(Integer id) throws ServiceException, AuthException { if (!SecurityContext.getUser().hasRight("GetUser")) throw new AuthException("Permission Denied"); LOG.debug("Call method getUser with id " + id); UserDTO user = null; String cacheKey = "getUser:" + id; UserDTO user = userDAO.getUser(id); try { if (cache.contains(cacheKey)) { user = (UserDTO) cache.get(cacheKey); } else { user = userDAO.getUser(id); cache.put(cacheKey, user); } } catch(SQLException e) { throw new ServiceException(e); } LOG.debug(User info is: " + user.toString()); return user; } Add results caching:
7 Spring Framework :: AOP :: Example What we get: -Large amount of the service code -16 lines instead of one -And the code continues to grow… Types of orthogonal functionality: -Logging -Exception handling -Transactions -Caching -User rights check -And many others... Disadvantages of the service code inside the main code: -The code size is growing -Its more difficult to support -Code duplication Solution: use aspects Take of the orthogonal functionality to the separate classes - aspects Do something before method Call a method ASPECT: Do something after method
8 Spring Framework :: AOP :: Example public UserDTO getUser(Integer id) { UserDTO user = userDAO.getUser(id); return user; } Look at the method to get user by id: public UserDTO getUser(Integer id) { LOG.debug("Call method getUser with id " + id); UserDTO user = userDAO.getUser(id); LOG.debug(User info is: " + user.toString()); return user; } Add advice Logging aspect
9 Spring Framework :: AOP :: Introduction Aspect Oriented Programming (AOP) AOP gives means for implementing orthogonal (crosscutting) functionality
10 Spring Framework :: AOP :: Introduction How can we implement crosscutting logic in RDBMS?
11 Spring Framework :: AOP :: Introduction Example of crosscutting logging based on RDBMS triggers: /* Table level triggers */ CREATE OR REPLACE TRIGGER DistrictUpdatedTrigger AFTER UPDATE ON district BEGIN INSERT INTO info VALUES ('table "district" has changed'); END;
12 Spring Framework :: AOP :: Example class UserDao implements UserDaoIF { public UserDTO getUser(Integer id) { UserDTO user = userDAO.getUser(id); return user; } class UserDao implements UserDaoIF { public UserDTO getUser(Integer id) { UserDTO user = userDAO.getUser(id); return user; public class LoggingAspect *.*User(..))") public void userMethod() { ") public Object log ( ProceedingJoinPoint thisJoinPoint) { String methodName = thisJoinPoint.getSignature().getName(); Object[] methodArgs = thisJoinPoint.getArgs(); LOG.debug("Call method " + methodName + " with args " + methodArgs); Object result = thisJoinPoint.proceed(); LOG.debug("Method " + methodName + " returns " + result); return result; } class UserDaoProxy implements UserDaoIF { public UserDTO getUser(final Integer id) { Aspect logging = new LoggingAspect(); ProceedingJoinPoint joinpoint = new ProceedingJoinPoint() { Object proceed() { return userDao.getUser(id); } }; return logging.log(joinpoint); } class UserDaoProxy implements UserDaoIF { public UserDTO getUser(final Integer id) { Aspect logging = new LoggingAspect(); ProceedingJoinPoint joinpoint = new ProceedingJoinPoint() { Object proceed() { return userDao.getUser(id); } }; return logging.log(joinpoint); }
13 UserService Spring Framework :: AOP :: Introduction UserDAO Application repository 1.Get DAO 2. Call DAO method UserServiceUserDAO Application context 1.DAO injection 2. Call DAO method Working with DAO without IoC and AOP Working with DAO with IoC, but without AOP
14 Logging Advice Spring Framework :: AOP :: Introduction UserService UserDAOProxy Application context 1.DAO injection 2. Call proxy DAO method Working with DAO with IoC and AOP Logging entering into the method UserDAO 3. Call Logging 5. Call advice 4. Call method of UserDAO Logging exiting from the method
15 Advice chain Spring Framework :: AOP :: Introduction UserServiceUserDAOProxy Application advice... advice... 1.DAO injection 2. Call proxy DAO method Working with DAO with IoC and AOP 3. advices 4. Call method of UserDAO 5. advices
16 Spring Framework :: AOP :: Introduction In Spring Framework AOP is implemented by creating proxy object for your service. Standard mechanism of proxy creation from JSE CGLIB proxy
public class LoggingAspect { private final static Logger LOG = *service.*(..))") public void serviceMethod() { ") public Object logWebServiceCall(ProceedingJoinPoint thisJoinPoint) { String methodName = thisJoinPoint.getSignature().getName(); Object[] methodArgs = thisJoinPoint.getArgs(); LOG.debug("Call method " + methodName + " with args " + methodArgs); Object result = thisJoinPoint.proceed(); LOG.debug("Method " + methodName + " returns " + result); return result; } } Spring Framework :: AOP :: Logging advice example
18 <beans xmlns=" xmlns:xsi=" xmlns:aop=" xsi:schemaLocation=" "> Spring Framework :: AOP :: Logging advice example
19 interface UserServiceIF { public UserDTO getUser(Integer id); } class UserService implements UserServiceIF { public UserDTO getUser(Integer id) { UserDTO user = userDAO.getUser(id); return user; } With the use of aspects we can automatically add: - Logging - Exception handling - Transactions - Caching - User rights check - And a lot more... Spring Framework :: AOP :: Logging advice example
20 Spring Framework :: Активация AOP Weaving: - applying the aspect to target object to create new proxy object; There are 2 additional dependencies to perform weaving: aspectjrt.jar aspectjweaver.jar Also you need to initiate the creating of dynamic proxies in the configuration file:
21 Spring Framework :: Активация AOP
22 Spring :: AOP :: Pointcut language execution – defines the pointcut on the base of method signature modifiers-pattern? ret-type-pattern declaring-type-pattern?.name-pattern(param-pattern) throws-pattern?) ? – optional parameter declaring-type-pattern - template for the method and class name Examples: execution (* *(..)) – pointcut attaches to any method with any signature; execution (int *(..)) – pointcut attaches to any method returning int; execution (!static * *(..)) – pointcut attaches to any not static method; execution(* com.package.subpackage.Classname.*(..)) – attaches to every method of com.package.subpackage.Classname class; execution (void Test.foo(int, String)) – pointcut attaches to foo() method of Test class, taking int and String as the parameters; execution (* foo.bar.*.dao.*.update*(..)) – pointcut attaches to any method starting from «update» in package starting from foo.bar and ending on dao.update;
23 bean – attach join points to some Spring bean (or set of beans) bean(*Bean) – defines the jointpoint for all beans with id ending Bean within – attach join point to every method of some class within(com.package.subpackage.*) – any join point (method execution only in Spring AOP) within the package com.package.subpackage this – matches the join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type this(com.package.InterfaceName) – define join points to all methods in classes which implement the interface com.package.InterfaceName target – matches the join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type target(com.package.InterfaceName) – defines all mathods of the object which target object implements com.package.InterfaceName args – match the join points where the arguments are instances of the given types args(String) – define methods with the single argument of String - matching the join points where the subject of the join point (method being executed in Spring AOP) has the given – all the methods marked – all methods in repository Spring :: AOP :: Pointcut
public class SystemArchitecture { /** * A join point is in the web layer if the method is defined in a type in * the com.xyz.someapp.web package or any sub-package under that. public void inWebLayer() {} /** * A join point is in the service layer if the method is defined in a type * in the com.xyz.someapp.service package or any sub-package under that. public void inServiceLayer() {} /** * A join point is in the data access layer if the method is defined in a * type in the com.xyz.someapp.dao package or any sub-package under that. public void inDataAccessLayer() {} /** * A data access operation is the execution of any method defined on a * dao interface. This definition assumes that interfaces are placed in the * "dao" package, and that implementation types are in sub-packages. com.xyz.someapp.dao.*.*(..))") public void dataAccessOperation() {} } Spring :: AOP :: Pointcut
* *(..))") private void anyPublicOperation() private void inTrading() && inTrading()") private void tradingOperation() {} Combining pointcut expressions: Spring :: AOP :: Pointcut Pointcut expressions can be combined using '&&', '||' and '!'. It is also possible to refer to pointcut expressions by name. This example shows three pointcut expressions: anyPublicOperation (which matches if a method execution join point represents the execution of any public method); inTrading (which matches if a method execution is in the trading module), and tradingOperation (which matches if a method execution represents any public method in the trading module).
26 Spring :: AOP :: Advice – executed before joinpoint Theres no possibility not to execute joinpoint, except for throw an – executed after – executed before and after – after success joinpoint execution – method is finished without – in case of exception in (finally) – in any case after the joinpoint;
27 Spring :: AOP :: Advice advice – surrounds the joinpoint Most powerful of all public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { // start stopwatch Object retVal = pjp.proceed(); // stop stopwatch return retVal; }
28 Spring :: AOP :: Advice types Can decide, should we execute joinpoint or return its own public Object accessRightsCheck(ProceedingJoinPoint pjp) throws Throwable { if (currentUser.hasRights()) { return pjp.proceed(); } else { throw new AuthorizationException(); } return null; }
public class AfterThrowingExample pointcut="com.luxoft.example.SystemArchitecture.dataAccessOperation()", throwing="ex") public void doRecoveryActions(DataAccessException ex) { //... } Spring :: AOP :: Use There is no way to return to the calling method or continue processing on the subsequent line However if you handle the exception here, it won't bubble up the chain unless you rethrow it yourself
30 public class AspectA public void doit() public class AspectB public void doit() {} } Spring :: AOP :: Use The order of aspects execution can be defined with use annotation: The order of advices in the aspect are defined by its order in the aspect source code.
31 Any questions!?