JoyAop Tutorial

Shen Li

 

http://joyaop.sourceforge.net


Introduction. 2

Interceptor 2

Generic Interceptor 2

AOP Alliance Interceptor 3

Abstract Generic Interceptor 4

Decorator 5

Mixin. 6

Interface. 7

Pointcut 7

Regular expression. 7

Interface. 8

Annotation. 8

Configuration. 8

Interceptor 8

Mixin. 8

Interface. 9

Expression. 9

Pointcut 9

Interceptor-Precedence. 10

Full configuration. 11

Run. 12

Summary. 13

 

Introduction

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.

 

Interceptor

JoyAop supports 4 types Interceptor currently:

Generic Interceptor

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).

AOP Alliance Interceptor

  Using the AOP Alliance API. It’s almost identical to the above type, except for the getParameter() method.

 

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();

    }

}

 Abstract Generic Interceptor

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.

Decorator

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.

Mixin

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() {