Spring aop源码浅析(一)

众所周知,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包。

Spring aop源码浅析(一)_第1张图片

aop包

aop包是一个对aop的宽泛定义,包括Advice接口和AspectException异常类。

Advice接口

以下为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类

依旧,以下是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包

intercept包中包含了我们熟知的joinpoint接口(但这和aspectj中的joinpoint根本不一样),以及基于advice接口给出的interceptor相关接口规范和基于joinpoint实现的invocation相关接口规范

Joinpoint接口

以下是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接口

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接口进行继承并制定拦截器的方法规约。官方也给出了构造函数与方法的拦截器接口。

ConstructorInterceptor接口

这个接口是基于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方法,基于对方法的不同实现,可以在创建新对象的构造函数调用前后进行额外的处理。

MethodInterceptor接口

这个接口是基于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接口

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就是一个通过拦截和反射来实现切入程序主体的编程方式。

ConstructorInvocation接口

这个接口是基于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权限检查的。

MethodInvocation接口

这个接口是基于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包源码的浅析了,希望能给你带来帮助。若有表述不恰当的地方,欢迎指正。

你可能感兴趣的:(spring,aop源码浅析,java,aop,spring)