advice是aspect方法,当特定joinpoint 执行点时advice被触发。JBoss AOP提供了五种advice类型。默认是around advice,它能被应用到所有execution模式上。
public Object [advice name]([Invocation] invocation) throws
Throwable
{
try{
// do something before joinpoint execution
// execute the joinpoint and get its return value
Object returnValue = invocation.invokeNext();
// do something after joinpoint has executed successfully ...
// return a value
return returnValue;
}catch(Exception e){
//handle any exceptions arising from calling the joinpoint
throw e;
}finally{
//Take some action once the joinpoint has completed
successfully or not
}
}
public void [advice name]([annotated parameter], [annotated parameter],...[annotated parameter])
public void [advice name]([annotated parameter], [annotated parameter],...[annotated parameter])
public [return type] [advice name]([annotated parameter],[annotated parameter],...[annotated parameter])
在第一个签名中,after advice不会覆写joinpoint返回值,使用第二个签名,after advice替代jointpoint返回值。
public void [advice name]([annotated parameter], [annotated parameter],...[annotated parameter])
不同与其他advice类型,after-throwing advice有强制annotation参数,次参数是被joinpoint抛出的异常。
public void [advice name]([annotated parameter], [annotated parameter],...[annotated parameter])
public [return type] [advice name]([annotated parameter], [annotated parameter],...[annotated parameter])
除了@Arg,其他所有annotation是但单独唯一的,每个advice最多有一个advice参数。
由于大多数参数代表了上下文的值,所以它们依赖于joinpoint类型。如果advice接受一个上下文的值作为参数,但在joinpoint执行过程中不可得,参数值为null。@return则是一个异类,如果advice有这个参数,它不会拦截不返回值的joinpoint。@Thrown annotation仅对after-throwing和finally advice可用。
public class Aspect{
public void throwing1(@Thrown RuntimeException thrownException){
}
public void throwing2(){
}
}
<aop>
<aspect class="Aspect"/>
<bind pointcut="...">
<throwing aspect="Aspect" name="throwing1"/>
<throwing aspect="Aspect" name="throwing2"/>
</bind>
</aop>
advice throwing1遵循次规则,但是thorwing2不会,因为它不包含@thrown annotation标注的参数。
对于finally advice,@Thrown annotation尽在@Return参数出现时才可用。通过这种方式,finally advice能标识是否返回值有效。如果@thrown参数为null,意味着joinpoint正常返回,@return参数是有效的。否则包含@return参数会被忽略。如果joinpoint没有拦截到异常,finally advice没有接收joinpoint返回值,@thrown参数是可选的,其值为null。public class Aspect{
public void finally1(@Thrown Throwable thrownException){
...
}
public void finally2(){
...
}
public void finally3(@Return int returnedValue, @Thrown
Throwable thrownException){
if (thrownException == null){
//We returned normally, the @Return parameter is valid
int i = returnedValue;
}else{
//An exception happened while invoking the target joinpoint
//The return value is invalid
}
}
public void finally4(@Return int returnedValue){
...
}
}
<aop>
<aspect class="Aspect"/>
<bind pointcut="execution(public int *->*(..))">
<finally aspect="Aspect" name="finally1"/>
<finally aspect="Aspect" name="finally2"/>
<finally aspect="Aspect" name="finally3"/>
<finally aspect="Aspect" name="finally4"/>
</bind>
</aop>
@thrown在advice finally1()和finally2()中不是强制的,且他们没有@return参数,所以这两个advice是有效的。除此之外,finally1()在joinpoint拦截到异常时接收非空异常。
以demo来说明其机制:
public class POJO{
void method(Collection arg0,List arg1, int arg2, String arg3){}
}
<aop>
<aspect class="MyAspect"/>
<bind pointcut="execution(* POJO->method(..))">
<before aspect="MyAspect" name="advice"/>
</bind>
</aop>
Class POJO是仅包含一个方法的java对象,当调用次方法调用前,希望触发MyAspect.advice()。Pojo.method()接收四个参数,它们都能通过@arg参数来获取。假如MyAspect.advice()有以下签名:
public class MyAspect
{
public void advice(@Arg Collection param0, @Arg List param1,
@Arg int param2, @Arg String param3){
}
}
public class MyAspect{
public void advice (@Arg Collection param0, @Arg Collection
param1, @Arg int param2, @Arg String param3){
...
}
}
如果MyAspect.advice()接收一个参数,java.lang.Object
public class MyAspect{
public void advice(@Arg Object param0){
...
}
}
匹配如下:param0 <- arg0,因为joinpoint参数类型没有Object,需要额外的步骤处理:arg0是第一个未匹配的参数,且派生至Object,所以将它赋值给para0。
public class MyAspect{
public void advice (@Arg(index=1) Collection param1){
...
}
}
public class AroundAspect{
public Object trace(MethodInvocation invocation) throws Throwabl{
try{
System.out.println("Entering method: " +invocation.getMethod()");
return invocation.invokeNext(); // proceed to next advice or actual call
}finally{
System.out.println("Leaving method: " +invocation.getMethod()");
}
}
public Object trace(ConstructorInvocation invocation) throwsThrowable{
try{
System.out.println("Entering constructor: " +invocation.getConstructor()");
return invocation.invokeNext(); // proceed to next advice
//or actual call
}finally{
System.out.println("Leaving constructor: " +
invocation.getConstructor()");
}
}
}
class POJO{
public POJO(){}
public someMethod(){}
}
<aop>
<aspect class="AroundAspect"/>
<bind pointcut="all(POJO)">
<advice aspect="AroundAspect" name="trace"/>
</bind>
</aop>
当调用POJO的构造器,Jboss AOP会调用trace(ConstructorInvocation invocation),当调用POJO的方法时,Jboss Aop调用trace(MethodInvoation invocation)。这说明,Jboss AOP会为joinpoint拦截选择最合适的advice method。
public class POJO{
String someMethod(String s){}
}
<aop>
<aspect class="OneAspect"/>
<bind pointcut="execution(* POJO->someMethod(..))">
<after aspect="OneAspect" name="after"/>
</bind>
</aop>
public class OneAspect{
public void after(@JoinPoint MethodJoinPoint mjp){} //1
public String after(@Target POJO pojo, @Return String ret, @ArgString arg0){} //2
}
当Pojo.someMethod()调用时,第一个OneAspect.after()会被选中,因为@JoinPoint的优先级更高。
public class OneAspect{
public void after(@Target POJO pojo){} //1
public String after(@Return String ret, @Arg String arg0){} //2
}
次例,也是第一个会被选中,因为@Target比@Return的优先级高。一次比较advice中的方法的优先级,选出优先级高的。
public class OneAspect
{
public void after(@JoinPoint MethodJoinPoint mjp, @Target POJO pojo){} //1
public String after(@JoinPoint MethodJoinPoint mjp, @Return String ret){} //2
}
advice中的第一个方法匹配更多的参数,所以会选中
public class OneAspect{
public void before(@Arg String s, @Arg int i){} //1
public String before(@Arg String s){} //2
}
public interface POJOInterface{}
public class POJOSuperClass extends java.lang.Object{}
public class POJO extends POJOSuperClass implements POJOInterface{
void method(){}
}
<aop>
<aspect class="OneAspect"/>
<bind pointcut="execution(* POJO->method(..))">
<before aspect="OneAspect" name="before"/>
</bind>
</aop>
public class OneAspect{
public void before(@Target POJO target){} //1
public void before(@Target POJOInterface target){} //2
public void before(@Target POJOSuperClass target){} //3
public void before(@Target Object target){} //4
}
POJO作为joinpoint的目标,OneAspect.before(@Target POJO)的degree为0。OneAspect.before(@Target POJOInterface)和OneAspect.before(@Target POJOSuperClass)的degree为1。OneAspect.before(@Target Object)的degree为2。最后Jboss会选择degree最低的method。
注意,基于@Arg的assignability degree是advice所有@arg参数的degree总和。public class POJO{
public void method(POJO argument0, String argument1, int argument2)
}
<aop>
<aspect class="OneAspect"/>
<bind pointcut="execution(* POJO->method(..))">
<before aspect="OneAspect" name="before"/>
</bind>
</aop>
public class OneAspect{
public void before(@Arg POJO p, @Arg String s, @Arg int i){} //1
public void before(@Arg POJOSuperClass p, @Arg String s, @Arg int i){}//2
public void before(@Arg POJO p, @Arg Object s, @Arg int i){} //3
public void before(@Arg Object p, @Arg Object s, @Arg int i){}//4
}
第一个advice的degree为0+0+0,基本类型没有父类,所以degree为0。
第二个advice的degree为1+0+0。public class POJO{
public Collection method(int arg0, boolean arg1, short arg2) {...}
}
<aop>
<aspect class="OneAspect"/>
<bind pointcut="execution(* POJO->method(..))">
<advice aspect="OneAspect" name="around"/>
</bind>
</aop>
public class OneAspect{
public Collection around(@JoinPoint Invocation inv, @Arg int
param0) throws Throwable {...} //1
public List around(@JoinPoint Invocation inv, @Arg boolean
param1) throws Throwable {...} //2
}
public class OneAspect{
public Collection after(@Arg int param0) {...} //1
public List after(@Arg boolean param1) { ... } //2
public void after(@Arg short param2) { ... }//3
}
因为JoinPoint有返回类型,而第三个advice没有返回类型,被排除规则之外。所以advice的重载有四个规则:
1)presence of annotated parameterpublic class POJO{
public void method(int arg0, long arg1) {...}
}
<aop>
<aspect class="OneAspect"/>
<bind pointcut="execution(* POJO->method(..))">
<before aspect="OneAspect" name="before"/>
</bind>
</aop>
public class OneAspect{
public void advice(@Arg int arg0) {}
public void advice(@Arg long arg1) {}
}