Pages

Saturday, 1 March 2014

Lesson 05 - Aspect Oriented Programming

Aspect Oriented Programming (AOP) is a pattern in programming to modularise concerns spans across multiple objects. The word "concern" can be treated as "some sort of functionality" applies to various layers/objects of the application such as logging, security, transaction management (tx) etc... In OOP class is the basic unit while in AOP "aspect" is the basic unit. Spring's IOC container does not depend on AOP so if you don't want to use AOP you can ignore this lesson but (for example) AOP complements IOC to provide very wonderful middleware solution (belive me, you see in tx management lesson how easy its to do things with AOP)

AOP Concepts

First of all,lets understand new AOP terminology (which is slightly confusing) but once we understand this thoroughly then whole AOP concept is like eating a cake. I try to keep same terminology very close to reference documentation to keep it consistent:

Aspect:
Modularisation of a concern that cuts across multiple classes. Logging/Tx Management is a classic example. We implement aspect as regular classes (in schema based approach) or classes with @Aspect annotation (in @AspectJ style)

Join Point:
A point during execution of the program (such as method execution/handling the exception). In Spring AOP, join point is ALWAYS a method execution

Advice:
The actual action taken by an aspect at a given join point.

Pointcut:
an expression/predicate which decides which joint points to consider. Advice is applied at a particular join point matched by given pointcut expression. Say we have 10 method in a class but we want to apply advice to all setter methods then we say pointcut expression as "set*" (something like that) so join points will be a method whose name starts with "set"

Target Object:
Object being advised by one or more aspects. Spring AOP is based on runtime proxies so this object will be always a proxied object.

AOP Proxy:
an object created by AOP framework to implement aspect contracts.in our AOP it will be jdk proxy or CGLIB proxy.

Weaving:
Linking aspects with application objects. in our AOP its always weaving at runtime (in AspectJ it usually done by compile time with the help of special compiler)

Below example gives you an idea of above used terms:

By the way to compile (it won't run right now) you need to keep following pom entries in your pom.xml (maven)


<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.framework.version}</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>

</dependency>

Just before going through more details lets see various types of Advice:

Before Advice:
An Advice the run BEFORE a join point but it can not prevent execution flow (unless there is an exception)

After returning Advice: (see above example)
An advice runs after returning a join point completely (with out raising any exceptions)

After throwing Advice:
An advice that runs if method exists by throwing some exception.

After (finally) Advice:
An advice to be run after method completed its execution (normally/with exception)

Around Advice:
Ad advice that surrounds a join point.It can perform some custom logic before and after join point execution. This can decide whether to proceed for join point execution or completely skip it by returning custom return value or some sort of exception.

Spring AOP currently supports only method execution join points.Field interception is not implemented if you want to implement it consider using languages such as AspectJ. Spring's aim is not to give full blown AOP framework rather it provides close bridge between AOP and spring IOC to solve common enterprise application problems. In Spring AOP we define aspect as regular spring beans, however few limitations of Spring AOP are unable to advise fine grained object (like domain objects) then in those cases consider AspectJ. Remember that AspectJ (full blown AOP framework) and Spring AOP (a proxy based AOP framework) don't compete each other rather complements each other. In Spring AOP you could use classical XML based approach orAspectJ annotation style to write aspects. Spring defaults J2SE proxy mechanism for AOP proxies.This enables any interface to be proxied. Spring can use CGLIB as well this is mainly for classes. If your java object does nt implement any interfaces then CGLIB is the only option. Spring AOP is proxy based to understand full details of it refer this link.

And above examples tried to explain it a bit. Think about how to the same in above case we are not implementing any interface such as UnitConverter. Those are the cases CGLIB comes for rescue. In next two sections let us write some examples while understanding AOP by AspectJ and Schema based approaches.

@AspectJ Support

@Aspectj refers to the style of creating aspect as regular classes with @Aspect annotation. Spring provides support for AspectJ 5 annotations using a library provided by AspectJ for matching pointcut matching and parsing. Remember, still we are using AOP runtime as pure spring aop and no need of special compiler/weaver. To enable @AspectJ aspects in spring you need to enable spring support on @AspectJ aspects, autoproxying beans so that they get advised on target beans. If your configuration is in java use below code or else use xml approach

@Configuration
@EnableAspectJAutoProxy
public class Myconfig {

}
or else if your bean configuration is using xml then use below setting in application context xml.
<aop:aspectj-autoproxy/>

Writing your first Aspect

Once @AspectJ support is enabled, you can create aspects as regular classes and define them as usual spring beans with annotation called @Aspect. Just keeping this annotation does nt get scanned by container, still we need to keep @Component (or other stereotypes like @Service, @Repository, @Controller etc..) for auto detecting. One golden rule is you can not have aspect themselves to be target of advice from another aspects. Hence @Aspect annotation excludes it from auto-proxying. Lets write a simple code to understand the concepts so far... This example should give you high level understand and we dig all details in next sections..

Hope that is very easy to understand..

Understanding/Declaring Pointcuts

As I mentioned, pointcut is a joinpoint (method) of interest to tell where the advice should be applied. Spring supports only method joinpoint. Pointcut definition has 2 parts, a signature (consists of name, parameters) and pointcut expression tells us which method definitions are we are interested in. In @AspectJ style, pointcut signature provided by regular method definition (in above example "pointcutMethod" does the same), usually, such method should have void return type.
@Pointcut (value="execution (* com.mastspring.lesson05.PositiveNumberEvaluator.evaluate())") // Pointcut Expression
public void pointcutMethod() { } // Pointcut Signature
In the above example "execution" is one of the designators. Understanding pointcut designators is quite important. There are various designators explained in next section.

Pointcut Designators
The following are allowable pointcut designators:
  • execution - for all matching method join points. Quite popular designator of all.
  • this - any pointcut defined with "this" matches if Proxy object is an instance of given type.
  • target - any pointcut defined with "target" matches if target object (the original object not the proxy) is an instance of given type.
  • @args - matching to join points where the runtime type of the actual arguments passed have annotations of the given type.
  • @annotation - matching to join points where the the method has the given annotation.
  • args - matching to join points where the arguments are instances of the given types
  • within - limits matching to join points within certain types (simply the execution of a method declared within a matching type when using Spring AOP)
  • @within - limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP)
  • @target - limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type
It is very difficult to under above designators with out an example. So below example covers first 6 designator and we see more examples on last 3 down the line.
Now the above examples explains designator and how to use them. You have seen using one or more designators using "logical and", "logical or", "!" operators as well. It is suggested to create more complex pointcuts from basic/simpler ones. Spring documentation has good list of examples here, You MUST refer them for cleat understanding.

Declaring Advices

Advice is always associated with a pointcut expression. We have Before,After Finally, After Throwing, After Returning, Around advices to use in Spring. As the name indicates Before Advice is indicated using @Before annotation. After Returning advice runs when matched method has returned some value normally (with out any exception). Its denoted by @AfterReturning annotation. We could access the return value of the method as well in the advice. Below example explains it.We CANT return a possibly complete new value after returning advice. After Throwing runs after a matched method thrown an exception and that exception can be caught. This advice is annotated with @AfterThrowing annotation. After Finally is run after matched method completed (either normally/thrown exception). So this advice must be ready to handle both cases. These are usually represented with @After annotation and used to release resources. The most important one left is Around advice. It can run before and after the method execution. If we want to perform some task before and after method call in a thread safe manner then do consider Around advice (represented by @Around annotation). The first parameter to this advice is ProceedingJoinPoint and in the advice body you should call proceed method on this object to continue the method call. In this case you could return complete new value from the advice method. In this advice, calling to proceed method is entirely up to the developer, you could completely skip it if you want. Enough of theory, lets see one big example which has all these advices written using simple "execution" pointcut designator.
This example covers all the theory.


Any advice may declare first parameter to it as JoinPoint (note: for Around advice, first parameter MUST be ProceedingJoinPoint) which provides useful methods such as getThis () (proxy), getTarget() (real target object), getArgs() (arguments passed) and getSignature()(the signature of the method) etc..

We have seen how to capture return value or throws exception in above examples.To make argument values available in advice body, use args designator.If a parameter name is used  in place of a type name in args expression, then the value of corresponding parameter will given to advice body when invoked.

@Before("comm.mastspring.lesson05.TestCode.method123() &&" +
        "args(MyObject,..)")
public void validateAccount(MyObject obj123) {
  // ...
}

Above example serves two way, first one is it matches only method123 of TestCode class and a method which should take MyObject as input and passed in MyObject is given to advice body in its "obj123" parameter. Spring handles generics used in class declarations and method parameters. The parameter binding in advice invocations depends on matching name mentoined in pointcut expressions and parameters of actual methods. Both Pointcut, Advice has a optional "argNames" attribute for this purpose.

@Before(
   value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",
   argNames="bean,auditable")
public void audit(JoinPoint jp, Object bean, Auditable auditable) {
  AuditCode code = auditable.value();
  // ... use code, bean, and jp
}

if you see above example we did nt keep name for first argument since its JoinPoint (you can ignore name of the JoinPoint). rest two parameters are given names as "bean", "auditable". This is due to special treatment was given to JoinPoint arguments. Since AOP does  nt use java reflection to get parameter names, you need to mention parameter name in "argNames" part of the advice and pointcut. Since AOP does  nt use java reflection to get parameter names, you need to mention parameter name in "argNames" part of the advice and pointcut.

when multiple advice wants to run at the same join point then spring follows rules of AspectJ. "on the way in", one with hiher precedence runs first."on the way out" one with lower precedence runs first. But how do we set the precednece? When there is no prcdedence defined there ordering is undefined. But how do we set the precedence? It is based on @Ordered(<ordernumber>) as shown in below example.

Schema Based AOP Approach:

If you are happy with @AsectJ style then you can ignore this section. I would like to show some light on schema based as well here (but not in detail as I prefer annotation style). This style is primarily for users who can not use Java5 or prefer XML based aproach. The same pointcut, advice types are supported here as well. So only we need to know the syntax of aop using XML approach. We use "aop" namespace primarily for this approach and a tag called <aop:config> helps us. An <aop:config> will have pointcut, advisor, aspect elements (in the same order).

Declaring Aspect:
under <aop:config> we use element called <aop:aspect> with bean we intend to back it with "ref" element like below:

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
    </aop:aspect>
</aop:config>
<bean id="aBean" class="...">
</bean>

in this example aBean can use all spring's facilities like dependency injection etc..
Declaring a Pointcut:
A named pointcut is defined under <aop:config> element with "id" and "expression" and later it can be referred in other places

<aop:config>
<aop:pointcut id="myPointCut" expression="execution(* com.mastspring.lesson05.MovieTicketing.getTicket(..))"/>
</aop:config>

Here pointcut expression is written exactly how we did in @AspectJ approach. If you are using JDK 1.5 onwards you could refer "expression" with another @AspectJ pointcut definition like below:

<aop:config>
<aop:pointcut id="myPointCut" expression="com.mastspring.lesson05.MovieTicketingAspect.myPointCut()"/>
</aop:config>

once pointcut is defined, mention it to a aspect:

<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="myPointCut" expression="com.mastspring.lesson05.MovieTicketingAspect.myPointCut()"/>
</aop:aspect>
</aop:config>

Declaring an Aspect:

The same set of 5 types of @AspectJ aspects are available in schem based approach as well. They are referred with <aop:before>, <aop:after>, <aop:after-returning>, <aop:after-throwing>, <around> respectively (names itself suggests what sort of aspects they are). All these elements will be residing under <aop:aspect>. For example, let us take <aop:before> as described below:

<aop:aspect id="beforeExample" ref="aBean">
<aop:before pointcut="execution(* com.xyz.myapp.dao.*.*(..))" method="doAccessCheck"/>
...
</aop:aspect>

In this example, poiNtcut expression is given and "method" attribute holds the method name of "aBean" to denote the actual functionality to be performed (advice code) when this pointcut matches the method. Below example clarifies things better. Though I am not going through other details like parameter name (argNames) etc.. they work exactly you expect to worK in @AspectJ.



In order to implement AOP you have two options Spring AOP or Full AspectJ. When you want to advice only methods which are managed by spring framework then Spring AOP is right choice. Go for FullAspectJ only if advicing is needed for beans not managed by spring container. Once you chose Spring AOP again you have @AspectJ style and schema based approach to define aspects. if you are nt on java 5 (very rare) then schema based approach is the only option you have. but the problem is in xml it does not encapsulate implementation of the requirement in single place. Added to that, XML approach is more limited in what it can express like its not possible to combine named pointcuts declated in xml.



Previous Next

No comments:

Post a Comment