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包。

aop-pic-1.png

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).
 *
 * <p>A runtime joinpoint is an <i>event</i> 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.
 *
 * <p>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.
	 * <p>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.
	 * <p>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.
	 * <p>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.
 *
 * <p>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...
 *
 * <p>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:
 *
 * <pre class=code>
 * 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) {
 *     ...
 *   }
 * }
 * </pre>
 *
 * @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.
 *
 * <p>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):
 *
 * <pre class=code>
 * 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");
 *     }
 *   }
 * }
 * </pre>
 *
 * @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.
 *
 * <p>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)):
 *
 * <pre class=code>
 * 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;
 *   }
 * }
 * </pre>
 *
 * @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.
 *
 * <p>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.
 *
 * <p>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.
	 * <p>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.
 *
 * <p>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.
	 * <p>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包源码的浅析了,希望能给你带来帮助。若有表述不恰当的地方,欢迎指正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值