JoyAop Tutorial
Shen Li
JoyAop is a
dynamic AOP framework based on the CGLIB proxies.
JoyAop supports 3
types Aspect currently:
1)
Interceptor. The interceptors could intercept any non-final
methods which could be overridden by CGLIB (Of course non-static,
public…).
2)
Interface. Actually, it’s a kind of Introduction here,
represents the introductions which only have interface.
3)
Mixin. Another kind of Introduction includes both interface
and implementation.
JoyAop
support 2 types Pointcut currently:
1)
Regular expression: Picks the classes or methods by matching
their names.
2)
Interface: Picks the classes by matching their interfaces.
3)
Annotation: Picks the methods by matching their annotations.
Note
This tutorial mainly
focuses on the usage of JoyAop, and rarely explain the concepts.
JoyAop supports 4 types Interceptor currently:
Just like the Interceptor of the other dynamic AOP frameworks, must implement a callback interface, and it is the most efficient type.
package net.sf.joyaop.demo.simple;
import net.sf.joyaop.Interceptor;
import net.sf.joyaop.Invocation;
/**
* @author Shen
Li
*/
public class
FooInterceptor implements
Interceptor {
public
Object intercept(Invocation
invocation) throws
Throwable {
System.out.println();
System.out.println("invoke
FooInterceptor...");
System.out.println("method
name: " + invocation.getMethod().getName());
System.out.println("argument
array length: " + invocation.getArguments().length);
System.out.println("paramter
value: " + invocation.getParameter("paramName"));
System.out.println("proxy
class name: " + invocation.getProxy().getClass().getName());
return invocation.proceed();
}
}
Note the invocation.getParameter(..) method, with it the interceptors
could obtain the parameters defined in the current Jointpoint(see below).
Using the AOP
package net.sf.joyaop.demo.simple;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* @author Shen
Li
*/
public class
AopAllianceFooInterceptor implements MethodInterceptor
{
public
Object invoke(MethodInvocation
invocation) throws
Throwable {
System.out.println();
System.out.println("invoke
AopAllianceFooInterceptor...");
System.out.println("method
name: " + invocation.getMethod().getName());
System.out.println("argument
array length: " + invocation.getArguments().length);
System.out.println("proxy
class name: " + invocation.getThis().getClass().getName());
return invocation.proceed();
}
}
Like the first one, but doesn’t directly use the Invocation object.
package net.sf.joyaop.demo.simple;
import net.sf.joyaop.AbstractInterceptor;
/**
* @author Shen
Li
*/
public abstract
class AbstractFooInterceptor
implements AbstractInterceptor
{
public
Object execute()
throws Throwable
{
System.out.println();
System.out.println("invoke
AbstractFooInterceptor...");
System.out.println("method
name: " + getMethod().getName());
System.out.println("argument
array length: " + getArguments().length);
System.out.println("parameter
value: " + getParameter("paramName"));
System.out.println("proxy
class name: " + getProxy().getClass().getName());
return proceed();
}
}
The AbstractInterceptor interface extends Invocation interface, so it has included the useful methods, such as proceed (), getMethod(), etc. Just declare our interceptors as abstract class, then directly invoke those methods, the framework will do the rest works. This type is slightly slower than the above one.
It mainly comes from the concept of abstract schema. Like the Decorator
pattern of OO, the interceptors (decorators) and their target objects are
required to implement the same interfaces.
Target interface::
package net.sf.joyaop.demo.simple;
/**
* @author Shen
Li
*/
public interface
Foo {
void
foo();
}
Target implementation:
package net.sf.joyaop.demo.simple;
/**
* @author Shen
Li
*/
public abstract
class FooImpl
implements Foo
{
public
void foo()
{
System.out.println();
System.out.println("invoking
Foo.foo()...");
System.out.println("parameter
value: " + getParamName());
}
public
abstract String
getParamName();
}
Decorator:
public abstract
class FooDecorator
implements Foo
{
public
void foo()
{
System.out.println();
System.out.println("invoke
FooDecorator...");
System.out.println("method
name: foo");
System.out.println("argument
array length: 0");
System.out.println("paramter
value: " + getParamName());
System.out.println("proxy class name: " +
getFoo().getClass().getName());
getFoo().foo();
}
protected
abstract Foo
getFoo();
protected
abstract String
getParamName();
}
The target object
has an interface and the decorator also implements that interface. In the above
example we want the decorator to intercept the foo() method of the target
object, we just implement that method, and add the extra code. Then if it needs
to proceed the invocation, we should declare an abstract getter method getFoo()
(must start with “get” and the return type should be the target
interface) , which will be implemented by the framework at runtime and returns
the target object. When using getFoo().foo() in the foo() method of the decorator,
the framework will proceed the
current method invocation. Besides, we can also access the other methods of the
target object by using getFoo().someOtherMethod(). (Not for proceeding
invocation now) But here we have another more simple way, just directly use someOtherMethod()
in the foo() method of the decorator, and the framework will automatically
route the invocation to the target object for us. Note if the someOtherMethod()
method has been declared in the decorator itself (Maybe we want to intercept it
too), which means that method has been overridden, we can’t use the
latter simple way now. (Maybe the rule is like the Java inheritance rule: if
the subclass has overridden the super class’s methods, we should use
super.someMethod() instead of someMethod().)
Then how does the
decorator obtain the Joinpoint’s parameters? Because the decorator
doesn’t implements any framework specific interface as the preceding
generic ones, we should declare another abstract getter method, which follows
the JavaBean standard: “get” + “name of the parameter”.
Then just like the getter method of target object, we simply use getParamName()
to obtain the parameter named paramName.
At last, Interceptor
of this type has the worst performance.
Here we focus on
using the concept of abstract schema to implement Mixin. The target object
could also implement the interfaces of the mixins which will be weaved at
runtime.
Target object
package net.sf.joyaop.demo.simple;
/**
* @author Shen
Li
*/
public abstract
class Target
implements Foo
{
public
void target()
{