众所周知,AOP(Aspect-Oriented Programming),面向切面编程,是Spring框架三大特性之一。他是基于AOP Alliance组织发布的Java/J2EE AOP标准的一个实现。AOP Alliance通过封装Java的一些reflect(反射)相关接口和类,编写出了一系列AOP相关操作的接口。而spring-aop包则是对这些操作接口的一个具体实现。
由于一些未知原因,spring-aop的1.0版本无法下载javadoc,也无法找到当时使用的AOP Alliance源码。所以以下浅析采用的是spring-aop的5.2.12.RELEASE版本源码。
源码中包含了两部分:一部分是aopalliance组织的规范,一部分是springframework对AOP的具体实现。
这篇文章,将会对AOP规范进行浅析。
下图为aopalliance的所有类与接口,其中包括(形式主义的)aop包和对接口进行一定定义的intercept包。
aop包是一个对aop的宽泛定义,包括Advice接口和AspectException异常类。
以下为Advice的源码:
package org.aopalliance.aop;
/**
* Tag interface for Advice. Implementations can be any type
* of advice, such as Interceptors.
*
* @author Rod Johnson
* @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $
*/
public interface Advice {
}
Advice接口是用作标记一些建议的,内部没有任何方法。
通过继承Advice接口来表明这个接口是对aop实现的一些建议。(为什么不用类继承?因为继承Advice接口的主要目的是做一些aop相关的定义,而类并不是用来做像接口一样的定义规约的,哪怕抽象类也不是)
依旧,以下是AspectException的源码:
package org.aopalliance.aop;
/**
* Superclass for all AOP infrastructure exceptions.
* Unchecked, as such exceptions are fatal and end user
* code shouldn't be forced to catch them.
*
* @author Rod Johnson
* @author Bob Lee
* @author Juergen Hoeller
*/
@SuppressWarnings("serial")
public class AspectException extends RuntimeException {
/**
* Constructor for AspectException.
* @param message the exception message
*/
public AspectException(String message) {
super(message);
}
/**
* Constructor for AspectException.
* @param message the exception message
* @param cause the root cause, if any
*/
public AspectException(String message, Throwable cause) {
super(message, cause);
}
}
AspectException被定义为aop中所有基础异常的父类。由于AspectException是继承于RuntimeExceotion的,而RuntimeException和他的子类在Java异常中是不受约束的(unchecked)。(如果这种异常在方法或构造函数中抛出后并没有对其进行捕获处理,那你也没有必要去用throws子句将异常传达给调用方,而且哪怕你不对抛出这种异常的方法的调用代码进行异常捕获处理,他也会通过编译检测。而这种异常抛出后会直接被JVM捕获,并停止当前线程运行)所以AspectException一旦抛出,说明问题比较严重。所以在异常发生的调用代码也没有必要去强行捕获处理这个异常。
总而言之,这是一个为了做aop框架实现时能防止使用者做出违规操作而制定的异常基类。
intercept包中包含了我们熟知的joinpoint接口(但这和aspectj中的joinpoint根本不一样),以及基于advice接口给出的interceptor相关接口规范和基于joinpoint实现的invocation相关接口规范
以下是aopalliance里的joinpoint源码:
package org.aopalliance.intercept;
import java.lang.reflect.AccessibleObject;
/**
* This interface represents a generic runtime joinpoint (in the AOP
* terminology).
*
* A runtime joinpoint is an event that occurs on a static
* joinpoint (i.e. a location in a the program). For instance, an
* invocation is the runtime joinpoint on a method (static joinpoint).
* The static part of a given joinpoint can be generically retrieved
* using the {@link #getStaticPart()} method.
*
*
In the context of an interception framework, a runtime joinpoint
* is then the reification of an access to an accessible object (a
* method, a constructor, a field), i.e. the static part of the
* joinpoint. It is passed to the interceptors that are installed on
* the static joinpoint.
*
* @author Rod Johnson
* @see Interceptor
*/
public interface Joinpoint {
/**
* Proceed to the next interceptor in the chain.
* The implementation and the semantics of this method depends
* on the actual joinpoint type (see the children interfaces).
* @return see the children interfaces' proceed definition
* @throws Throwable if the joinpoint throws an exception
*/
Object proceed() throws Throwable;
/**
* Return the object that holds the current joinpoint's static part.
* For instance, the target object for an invocation.
* @return the object (can be null if the accessible object is static)
*/
Object getThis();
/**
* Return the static part of this joinpoint.
* The static part is an accessible object on which a chain of
* interceptors are installed.
*/
AccessibleObject getStaticPart();
}
joinpoint,是在静态的(固定的)地方,比如方法上加的一个连接点。然后就可以通过用拦截器拦截来获取当前连接点,从而对连接的方法(或别的什么东西)进行操作。那么操作的方法这里给出了三个:proceed()——跳转到拦截链中的下一个拦截器;getThis()——获取当前接入方法的静态部分(调用的对象之类),如果可获取到的对象是静态的,那么将会返回null;getStaticPart()——在有拦截链的情况下获取到getThis()获取不到的静态对象。其中,AccessibleObject是java反射中的一个对象类型,可以在反射的时候让一些本没有权限访问的对象变得能访问(通过屏蔽java的权限检查),并进行一些操作。
Interceptor接口继承于Advice接口,以下是源码:
package org.aopalliance.intercept;
import org.aopalliance.aop.Advice;
/**
* This interface represents a generic interceptor.
*
* A generic interceptor can intercept runtime events that occur
* within a base program. Those events are materialized by (reified
* in) joinpoints. Runtime joinpoints can be invocations, field
* access, exceptions...
*
*
This interface is not used directly. Use the sub-interfaces
* to intercept specific events. For instance, the following class
* implements some specific interceptors in order to implement a
* debugger:
*
*
* class DebuggingInterceptor implements MethodInterceptor,
* ConstructorInterceptor {
*
* Object invoke(MethodInvocation i) throws Throwable {
* debug(i.getMethod(), i.getThis(), i.getArgs());
* return i.proceed();
* }
*
* Object construct(ConstructorInvocation i) throws Throwable {
* debug(i.getConstructor(), i.getThis(), i.getArgs());
* return i.proceed();
* }
*
* void debug(AccessibleObject ao, Object this, Object value) {
* ...
* }
* }
*
*
* @author Rod Johnson
* @see Joinpoint
*/
public interface Interceptor extends Advice {
}
显然,这个接口是一个规约描述接口。他里面没有任何方法规约,只是告诉我们Interceptor(拦截器)是一个可以通过invocations(调用)、filed access(字段访问)、exceptions(异常)等来具体化操作拦截程序运行时的事件的一个东西。而要使用拦截器的话,需要对Interceptor接口进行继承并制定拦截器的方法规约。官方也给出了构造函数与方法的拦截器接口。
这个接口是基于Interceptor接口的构造函数拦截器接口实现,以下是源码:
package org.aopalliance.intercept;
/**
* Intercepts the construction of a new object.
*
* The user should implement the {@link
* #construct(ConstructorInvocation)} method to modify the original
* behavior. E.g. the following class implements a singleton
* interceptor (allows only one unique instance for the intercepted
* class):
*
*
* class DebuggingInterceptor implements ConstructorInterceptor {
* Object instance=null;
*
* Object construct(ConstructorInvocation i) throws Throwable {
* if(instance==null) {
* return instance=i.proceed();
* } else {
* throw new Exception("singleton does not allow multiple instance");
* }
* }
* }
*
*
* @author Rod Johnson
*/
public interface ConstructorInterceptor extends Interceptor {
/**
* Implement this method to perform extra treatments before and
* after the construction of a new object. Polite implementations
* would certainly like to invoke {@link Joinpoint#proceed()}.
* @param invocation the construction joinpoint
* @return the newly created object, which is also the result of
* the call to {@link Joinpoint#proceed()}; might be replaced by
* the interceptor
* @throws Throwable if the interceptors or the target object
* throws an exception
*/
Object construct(ConstructorInvocation invocation) throws Throwable;
}
这个接口提供了一个construct方法,基于对方法的不同实现,可以在创建新对象的构造函数调用前后进行额外的处理。
这个接口是基于Interceptor接口的方法拦截器接口实现,以下是源码:
package org.aopalliance.intercept;
/**
* Intercepts calls on an interface on its way to the target. These
* are nested "on top" of the target.
*
* The user should implement the {@link #invoke(MethodInvocation)}
* method to modify the original behavior. E.g. the following class
* implements a tracing interceptor (traces all the calls on the
* intercepted method(s)):
*
*
* class TracingInterceptor implements MethodInterceptor {
* Object invoke(MethodInvocation i) throws Throwable {
* System.out.println("method "+i.getMethod()+" is called on "+
* i.getThis()+" with args "+i.getArguments());
* Object ret=i.proceed();
* System.out.println("method "+i.getMethod()+" returns "+ret);
* return ret;
* }
* }
*
*
* @author Rod Johnson
*/
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
/**
* Implement this method to perform extra treatments before and
* after the invocation. Polite implementations would certainly
* like to invoke {@link Joinpoint#proceed()}.
* @param invocation the method invocation joinpoint
* @return the result of the call to {@link Joinpoint#proceed()};
* might be intercepted by the interceptor
* @throws Throwable if the interceptors or the target object
* throws an exception
*/
Object invoke(MethodInvocation invocation) throws Throwable;
}
这个接口提供了一个invoke方法,基于对方法的不同实现,可以在调用(接入点处的方法的调用)前后进行额外的处理。
Invocation接口是一个继承于joinpoint的接口,以下是源码:
package org.aopalliance.intercept;
/**
* This interface represents an invocation in the program.
*
* An invocation is a joinpoint and can be intercepted by an
* interceptor.
*
* @author Rod Johnson
*/
public interface Invocation extends Joinpoint {
/**
* Get the arguments as an array object.
* It is possible to change element values within this
* array to change the arguments.
* @return the argument of the invocation
*/
Object[] getArguments();
}
其实调用的话只是joinpoint的一种,他里面提供了一个getArguments方法,用于获取连接点的参数并进行修改。具体的使用,还是需要配合拦截器来使用的。因为aop就是一个通过拦截和反射来实现切入程序主体的编程方式。
这个接口是基于Invocation接口的构造函数调用接口实现,以下是源码:
package org.aopalliance.intercept;
import java.lang.reflect.Constructor;
/**
* Description of an invocation to a constructor, given to an
* interceptor upon constructor-call.
*
* A constructor invocation is a joinpoint and can be intercepted
* by a constructor interceptor.
*
* @author Rod Johnson
* @see ConstructorInterceptor
*/
public interface ConstructorInvocation extends Invocation {
/**
* Get the constructor being called.
* This method is a friendly implementation of the
* {@link Joinpoint#getStaticPart()} method (same result).
* @return the constructor being called
*/
Constructor<?> getConstructor();
}
这个接口提供了getConstructor方法,用于在构造函数的拦截器中拦截调用的构造函数,而且这种拦截是屏蔽了java权限检查的。
这个接口是基于Invocation接口的方法调用接口实现,以下是源码:
package org.aopalliance.intercept;
import java.lang.reflect.Method;
/**
* Description of an invocation to a method, given to an interceptor
* upon method-call.
*
* A method invocation is a joinpoint and can be intercepted by a
* method interceptor.
*
* @author Rod Johnson
* @see MethodInterceptor
*/
public interface MethodInvocation extends Invocation {
/**
* Get the method being called.
* This method is a friendly implementation of the
* {@link Joinpoint#getStaticPart()} method (same result).
* @return the method being called
*/
Method getMethod();
}
这个接口提供了getMethod方法,用于在方法的拦截器中拦截调用的方法。这种拦截也是屏蔽了java权限检查的。
以上就是对spring-aop包中的org.aopalliance包源码的浅析了,希望能给你带来帮助。若有表述不恰当的地方,欢迎指正。