6. There is cross-cutting functionality that does not belong to
specific module or object. Often it should be supported by many
objects from different places (logging, exception handling, audit,
auth, …). Spreading it throughout the project is not a option.
It would be good to handle specific cross-cutting concern in one
place. However pure major paradigms (OOP, procedural,
component-driven) cannot encapsulate and express this logic
efficiently.
Functional Scala-like approach might help through closures-
decorators, however it has own weaknesses.
Sigma Ukraine6
THE PROBLEM
7. Crosscutting concern is decomposed into several notions:
Aspect – crosscutting implementation, regular bean with
method (examples: exception handling)
Join point – usually it represents a method execution.
Pointcut – expression that matches join point.
Advice – join-point and aspect integration, types "around,"
"before" and "after“.
Target Object – object to be advised by one or more aspects.
AOP proxy (or Advised Object ) – proxy with advice calls
Weaving – linking advice with other target objects to create an
advised object (compile or creation stage)
Sigma Ukraine7
AOP BASIC CONCEPTS
9. Spring AOP is implemented in pure Java
Aspect is an ordinary bean with own injection rules
Weaving with Spring AOP is performed during instantiation
time: injection/creation or direct
ApplicationContext.getBean (through Spring DI)
Only Proxy Approach (JDK dynamic proxies or CGLIB)
Spring AOP is based on AspectJ framework interfaces.
Two ways of aspect integration: XML and Annotations
Sigma Ukraine9
SPRING AOP
10. Add Spring references into maven pom file:
Sigma Ukraine10
STEPS TO ADD ASPECT – 1 (3)
( FOR AROUND ADVICE)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
11. Create bean-aspect into project, register it as Spring bean:
Sigma Ukraine11
STEPS TO ADD ASPECT – 1 (3)
( FOR AROUND ADVICE)
package com.xyz.services.aspect;
public class ServiceAspect {
public Object run(ProceedingJoinPoint call) throws Throwable {
// do something, part 1
Object ret = call.proceed();
// do something, part 2
return ret;
}
}
<bean id="AspectBeanReference"
class="com.xyz.services.aspect.ServiceAspect"/>
12. Register Advice and Pointcut:
Sigma Ukraine12
STEPS TO ADD ASPECT – 2 (3)
( FOR AROUND ADVICE)
<aop:config>
<aop:aspect id="MyAspect" ref="AspectBeanReference" order="250">
<aop:pointcut id="MyNameOfPointcut"
expression=
"execution(* com.xyz.services.impl.*ServiceImpl.*(..))"/>
<aop:around pointcut-ref="MyNameOfPointcut" method="run"/>
</aop:aspect>
</aop:config>
<!-- <aop:aspectj-autoproxy/> -->
13. Spring AOP uses AspectJ subset language to express
pointcuts.
Pointcuts might define classes as well as interfaces
Examples
execution(* *.*(..)) – expresses aspect call after execution of any
public method;
execution(* *.set*(..)) – expresses aspect call after execution of any
method which name starts with “set”;
execution(* com.xyz.service.AccountService.*(..)) – expresses
aspect call after execution of any method for class
com.xyz.service.AccountService;
execution(* com.xyz.service.*.*(..)) – expresses aspect call for any
method of objects from package service;
annotation(com.xyz.service.MyAnnotation) - expresses aspect
call for method, whose object support annotation.
Sigma Ukraine13
A FEW WORDS ON POINTCUTS
14. Sigma Ukraine14
ADVICES
BEFORE ADVICE
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
15. Sigma Ukraine15
ADVICES
AFTER RETURNING
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="execution(* com.xyz.myapp.dao.*.*(..))",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}
16. Sigma Ukraine16
ADVICES
AFTER THROWING ADVICE
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="execution(* com.xyz.myapp.dao.*.*(..))",
throwing="ex")
public void doRecoveryActions(Exception ex) {
// ...
}
}
17. Sigma Ukraine17
ADVICES
AFTER (FINALLY) ADVICE
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
@After("execution(* com.xyz.myapp.dao.*.*(..))")
public void doReleaseLock() {
// ...
}
}
18. Sigma Ukraine18
ADVICES
AROUND ADVICE
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
@Around("execution(* com.xyz.myapp.dao.*.*(..))")
public Object doBasicProfiling(ProceedingJoinPoint pjp)
throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
19. Task is to convert exceptions crossing layers.
Define pointcut covering edge components for specific layer.
Define aspect
Sigma Ukraine19
TRANSPARENT EXCEPTION HANDLING
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class ExceptionTranslatorExample {
@Around("execution(* com.xyz.domain.*Repository.*(..)) ")
public Object doBasicProfiling(ProceedingJoinPoint pjp)
throws Throwable {
try{
Object retVal = pjp.proceed();
return retVal;
}
catch (SQLException ex){
throw new DomainException(ex);
}
}
}
20. Define pointcut to cover beans with @Transactional
annotations. Usually it is top edge of application service layer.
Take into account aspect order – transactions should have
bigger value.
Sigma Ukraine20
RE-LAUNCHING BROKEN TRANSACTIONS
@Aspect
public class ExceptionTranslatorExample {
@Around("execution(* com.xyz.applicationServices.*Service.*(..)) ")
public Object doBasicProfiling(ProceedingJoinPoint pjp)
throws Throwable {
int counter = 0;
do{
try{
return pjp.proceed();
}
catch (DeadLockException ex)
if((++counter)==2)
throw ex;
}
while(true);
}
}
22. Any pointcut should be expressed by single
expression.
Any pointcut should be “linearized”.
Do not invent a wheel: use customized Spring
AOP technics like exception handling for Spring
MVC or Spring declarative transactions.
One cross-cutting concern should be matched
to one aspect implementation.
In case of layered architecture and XML
approach treat all aspects from one layer in
one place [like board room].
AOP might be integrated into legacy project, it
should have clear architecture and DI (is it
possible?!).
Sigma Ukraine22
BEST PRACTICES
23. AOP is not silver bullet. Do not use it
everywhere. Excessive AOP usage makes
application even more difficult to
understand than without it.
Take into account overhead (creation&
execution time ). In many cases it might
matter. Use AspectJ bytecode weaving
approach.
Be aware of Spring’s proxy approach.
Spring AOP is based on Spring DI.
Sigma Ukraine23
AOP CONCERNS
24. Sigma Ukraine24
AOP OVERHEAD
5000 (in ms) 50000 (in ms) 500.000 (in ms) 5.000.000 (in ms)
Calling pure math object (Series 1) 46,008952 131,986317 1194,716932 13661,97206
Calling weaved object with empty aspect (Series 2) 55,736513 225,285998 1897,525577 20110,53607
Calling weaved object with math aspect (Series 3) 65,556692 343,241082 3141,977656 32587,01187
0
5000
10000
15000
20000
25000
30000
35000
5000 (in ms) 50000 (in ms) 500.000 (in ms) 5.000.000 (in ms)
Series1
Series2
Series3
Experiment details:
AMD Athlon X4, 3 GHz
25. Sigma Ukraine25
AOP BENCHMARKS
AWBench
(relative %)
aspectwerkz aspectj spring dynaop
before, args()
target()
1 x 1 x 35.5 x 39 x
around x 2, args()
target()
1 x 0.6 x 5.4 x 5.6 x
before, rtti info
access
1 x 1 x 5.5 x 6.7 x
after returning 1 x 1 x 28.5 x 31.5 x
before + after 1 x 1 x 22.2 x 17.2 x
before, args()
primitives
1 x 1 x 35 x 37.5 x
before, args()
objects
1 x 2 x 65 x 69 x
around, rtti info
access
1 x 0.7 x 3.5 x 4.8 x
around, static
info access
1 x 0.3 x 3 x 4.1 x
Source: http://docs.codehaus.org/display/AW/AOP+Benchmark
Рассмотрим классическиКаждый слой, каждая группа компонент, будь то bounded context или некоторая подсистема могут быть свои правила по конвертации excerptinonsи трансляции их в более удобное представлениеPresentaation layer…Многие из вас замечали что тот же Hibernate ....Вообще говоря боксинг исключительных ситуаций это нормальная практика.
Многие из вас сталкивались с уродливыми многочсленными try/catch и ваыполеннием однотипной логики раскиданной по коду
В идеале ыло бы здорово вообще убратьtry/catch и вынести их за пределыМогу сказат ьчто на нашем проекте у нас проактически нету try.catchexceptions. Все вендили между слоями хорошо изолированы конвертационыне правила хорошо инкапсулированы в вентили. И это позводяет хорошо контролировать сложность.И наша система не протекает.
Прошлая задача вводит нам такое понятие как cross-cuttingИтак АОП появляется так где есть cross-cutting functionality
I might say that spring declarative transactions already use AOP approach.
После этого все вызовы методов всех сервисов данного пакета будут декорироваться нашим аспектом.
Spring AOP предлагает вашему вниманию гораздо больший диапозон выражений, упомянутые выражения встречаются чаще всего , и они выходят за рамки этого доклада
Allegory АОП в отличие ест ьчто-то типа портясающей припраы к вашему салату, которая сделает ваш салат неабываемым, но если переборщите то придется выбрасывать.It is possible to prepare doklad “Как я завалил проект используюя Spring AOP”.Если в контролируете аспекты то очекнь вероятно что у вас с первормансом все ок, но если пострадал перфоманкс, это признак того что вы потеряли контроль над аспектами. И аспекты контролируют вас
Могу от себя добавить что у нас на проекте используется порядка 7 разных аспектов. Мы переключилина AspectJ декларативные транзакции и получили выигрыв в производительности 15-20 %.