首页 >> 大全

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

2023-10-22 大全 26 作者:考证青年

0、前言 在上篇文章 《设计思想》AOP设计基本原理中阐述了 AOP 的基本原理以及基本机制,本文将深入源码,详细阐述整个 AOP实现的整个过程。

读完本文,你将了解到:

1、内部创建代理对象的过程

2、 AOP的核心---

3、基于JDK面向接口的动态代理生成代理对象

4、基于Cglib子类继承方式的动态代理生成代理对象

5、各种是的执行顺序是如何和方法调用进行结合的?

6、与的结合------的条件执行

7、总结

1、内部创建代理对象的过程

在的底层,如果我们配置了代理模式,会为每一个Bean创建一个对应的的来创建某个对象的代理对象。

假定我们现在有一个接口及其实现类,我们打算创建一个代理类,在执行的方法时的各个阶段,插入对应的业务代码。

package org.luanlouis.meditations.thinkinginspring.aop;/*** 售票服务* Created by louis on 2016/4/14.*/
public interface TicketService {//售票public void sellTicket();//问询public void inquire();//退票public void withdraw();
}

package org.luanlouis.meditations.thinkinginspring.aop;/*** RailwayStation 实现 TicketService* Created by louis on 2016/4/14.*/
public class RailwayStation implements TicketService {public void sellTicket(){System.out.println("售票............");}public void inquire() {System.out.println("问询.............");}public void withdraw() {System.out.println("退票.............");}
}

package org.luanlouis.meditations.thinkinginspring.aop;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;/*** 执行RealSubject对象的方法之前的处理意见* Created by louis on 2016/4/14.*/
public class TicketServiceBeforeAdvice implements MethodBeforeAdvice {public void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("BEFORE_ADVICE: 欢迎光临代售点....");}
}

package org.luanlouis.meditations.thinkinginspring.aop;import org.springframework.aop.AfterReturningAdvice;import java.lang.reflect.Method;/*** 返回结果时后的处理意见* Created by louis on 2016/4/14.*/
public class TicketServiceAfterReturningAdvice implements AfterReturningAdvice {@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("AFTER_RETURNING:本次服务已结束....");}
}

package org.luanlouis.meditations.thinkinginspring.aop;import org.springframework.aop.ThrowsAdvice;import java.lang.reflect.Method;/*** 抛出异常时的处理意见* Created by louis on 2016/4/14.*/
public class TicketServiceThrowsAdvice implements ThrowsAdvice {public void afterThrowing(Exception ex){System.out.println("AFTER_THROWING....");}public void afterThrowing(Method method, Object[] args, Object target, Exception ex){System.out.println("调用过程出错啦!!!!!");}} 

package org.luanlouis.meditations.thinkinginspring.aop;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.aspectj.AspectJAroundAdvice;/**** AroundAdvice* Created by louis on 2016/4/15.*/
public class TicketServiceAroundAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("AROUND_ADVICE:BEGIN....");Object returnValue = invocation.proceed();System.out.println("AROUND_ADVICE:END.....");return returnValue;}
}

_spring实现原理_《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

现在,我们来手动使用来创建Proxy对象,并将相应的几种不同的加入这个proxy对应的各个执行阶段中:

package org.luanlouis.meditations.thinkinginspring.aop;import org.aopalliance.aop.Advice;
import org.springframework.aop.framework.ProxyFactoryBean;/*** 通过ProxyFactoryBean 手动创建 代理对象* Created by louis on 2016/4/14.*/
public class App {public static void main(String[] args) throws Exception {//1.针对不同的时期类型,提供不同的AdviceAdvice beforeAdvice = new TicketServiceBeforeAdvice();Advice afterReturningAdvice = new TicketServiceAfterReturningAdvice();Advice aroundAdvice = new TicketServiceAroundAdvice();Advice throwsAdvice = new TicketServiceThrowsAdvice();RailwayStation railwayStation = new RailwayStation();//2.创建ProxyFactoryBean,用以创建指定对象的Proxy对象ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();//3.设置Proxy的接口proxyFactoryBean.setInterfaces(TicketService.class);//4. 设置RealSubjectproxyFactoryBean.setTarget(railwayStation);//5.使用JDK基于接口实现机制的动态代理生成Proxy代理对象,如果想使用CGLIB,需要将这个flag设置成trueproxyFactoryBean.setProxyTargetClass(true);//6. 添加不同的AdviceproxyFactoryBean.addAdvice(afterReturningAdvice);proxyFactoryBean.addAdvice(aroundAdvice);proxyFactoryBean.addAdvice(throwsAdvice);proxyFactoryBean.addAdvice(beforeAdvice);proxyFactoryBean.setProxyTargetClass(false);//7通过ProxyFactoryBean生成Proxy对象TicketService ticketService = (TicketService) proxyFactoryBean.getObject();ticketService.sellTicket();}}

不出意外的话,你会得到如下的输出结果:

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)_spring实现原理_

你会看到,我们成功地创建了一个通过一个和 真实的实例对象创建出了对应的代理对象,并将各个加入到proxy代理对象中。

你会发现,在调用的()之前,成功插入了逻辑,而调用的()之后,逻辑也成功插入了。

也成功包裹了()方法,只不过这个发生的时机有点让人感到迷惑。实际上,这个背后的执行逻辑隐藏了 AOP关于AOP的关于调度最为核心的算法机制,这个将在本文后面详细阐述。

另外,本例中是通过JDK的针对接口的动态代理模式生成代理对象的,具体机制,请看下面关于的介绍。

2、 AOP的核心---

上面我们通过了纯手动使用实现了AOP的功能。现在来分析一下上面的代码:我们为提供了如下信息:

1). Proxy应该感兴趣的列表;

2). 真正的实例对象引用;

3).告诉使用基于接口实现的JDK动态代理机制实现proxy:

4). Proxy应该具备的接口:;

根据这些信息,就能给我们提供我们想要的Proxy对象了!那么,帮我们做了什么?

spring实现原理_《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)_

使用工厂Bean模式创建每一个Proxy,对应每一个不同的Class类型,在中都会有一个相对应的. 以下是的类图。

_《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)_spring实现原理

如上所示,对于生成Proxy的工厂Bean而言,它要知道对其感兴趣的信息,而这类的信息,被维护到中。可以根据特定的类名和方法名返回对应的,用以表示需要执行的串。

3、基于JDK面向接口的动态代理生成代理对象

类实现了,能够返回Proxy,并且,其自身也实现了角色。也就是说,当我们使用proxy时,我们对proxy对象调用的方法,都最终被转到这个类的()方法中。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {//省略若干.../** Proxy的配置信息,这里主要提供Advisor列表,并用于返回AdviceChain */private final AdvisedSupport advised;/*** Construct a new JdkDynamicAopProxy for the given AOP configuration.* @param config the AOP configuration as AdvisedSupport object* @throws AopConfigException if the config is invalid. We try to throw an informative* exception in this case, rather than let a mysterious failure happen later.*/public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {Assert.notNull(config, "AdvisedSupport must not be null");if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {throw new AopConfigException("No advisors and no TargetSource specified");}this.advised = config;}@Overridepublic Object getProxy() {return getProxy(ClassUtils.getDefaultClassLoader());}//返回代理实例对象@Overridepublic Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());}Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);//这里的InvocationHandler设置成了当前实例对象,即对这个proxy调用的任何方法,都会调用这个类的invoke()方法//这里的invoke方法被调用,动态查找Advice列表,组成ReflectMethodInvocationreturn Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);}/*** 对当前proxy调用其上的任何方法,都将转到这个方法上* Implementation of {@code InvocationHandler.invoke}.* 

Callers will see exactly the exception thrown by the target,* unless a hook method throws an exception.*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodInvocation invocation;Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;Class targetClass = null;Object target = null;try {if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {// The target does not implement the equals(Object) method itself.return equals(args[0]);}if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {// The target does not implement the hashCode() method itself.return hashCode();}if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) {// Service invocations on ProxyConfig with the proxy config...return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);}Object retVal;if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// May be null. Get as late as possible to minimize the time we "own" the target,// in case it comes from a pool.target = targetSource.getTarget();if (target != null) {targetClass = target.getClass();}// Get the interception chain for this method.获取当前调用方法的拦截链List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// Check whether we have any advice. If we don't, we can fallback on direct// reflective invocation of the target, and avoid creating a MethodInvocation.//如果没有拦截链,则直接调用Joinpoint连接点的方法。if (chain.isEmpty()) {// We can skip creating a MethodInvocation: just invoke the target directly// Note that the final invoker must be an InvokerInterceptor so we know it does// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);}else {// We need to create a method invocation...//根据给定的拦截链和方法调用信息,创建新的MethodInvocation对象,整个拦截链的工作逻辑都在这个ReflectiveMethodInvocation里 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.retVal = invocation.proceed();}// Massage return value if necessary.Class returnType = method.getReturnType();if (retVal != null && retVal == target && returnType.isInstance(proxy) &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {// Special case: it returned "this" and the return type of the method// is type-compatible. Note that we can't help if the target sets// a reference to itself in another returned object.retVal = proxy;}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);}return retVal;}finally {if (target != null && !targetSource.isStatic()) {// Must have come from TargetSource.targetSource.releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}} }

4、基于Cglib子类继承方式的动态代理生成代理对象

基于Cglib子类继承方式的动态代理生成代理对象:

package org.springframework.aop.framework;
/*** CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.** 

Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on* Spring's own internally repackaged version of CGLIB 3..*/ @SuppressWarnings("serial") class CglibAopProxy implements AopProxy, Serializable {// Constants for CGLIB callback array indicesprivate static final int AOP_PROXY = 0;private static final int INVOKE_TARGET = 1;private static final int NO_OVERRIDE = 2;private static final int DISPATCH_TARGET = 3;private static final int DISPATCH_ADVISED = 4;private static final int INVOKE_EQUALS = 5;private static final int INVOKE_HASHCODE = 6;/** Logger available to subclasses; static to optimize serialization */protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);/** Keeps track of the Classes that we have validated for final methods */private static final Map, Boolean> validatedClasses = new WeakHashMap, Boolean>();/** The configuration used to configure this proxy */protected final AdvisedSupport advised;protected Object[] constructorArgs;protected Class[] constructorArgTypes;/** Dispatcher used for methods on Advised */private final transient AdvisedDispatcher advisedDispatcher;private transient Map fixedInterceptorMap;private transient int fixedInterceptorOffset;/*** Create a new CglibAopProxy for the given AOP configuration.* @param config the AOP configuration as AdvisedSupport object* @throws AopConfigException if the config is invalid. We try to throw an informative* exception in this case, rather than let a mysterious failure happen later.*/public CglibAopProxy(AdvisedSupport config) throws AopConfigException {Assert.notNull(config, "AdvisedSupport must not be null");if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {throw new AopConfigException("No advisors and no TargetSource specified");}this.advised = config;this.advisedDispatcher = new AdvisedDispatcher(this.advised);}/*** Set constructor arguments to use for creating the proxy.* @param constructorArgs the constructor argument values* @param constructorArgTypes the constructor argument types*/public void setConstructorArguments(Object[] constructorArgs, Class[] constructorArgTypes) {if (constructorArgs == null || constructorArgTypes == null) {throw new IllegalArgumentException("Both 'constructorArgs' and 'constructorArgTypes' need to be specified");}if (constructorArgs.length != constructorArgTypes.length) {throw new IllegalArgumentException("Number of 'constructorArgs' (" + constructorArgs.length +") must match number of 'constructorArgTypes' (" + constructorArgTypes.length + ")");}this.constructorArgs = constructorArgs;this.constructorArgTypes = constructorArgTypes;}@Overridepublic Object getProxy() {return getProxy(null);}@Overridepublic Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());}try {Class rootClass = this.advised.getTargetClass();Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");Class proxySuperClass = rootClass;if (ClassUtils.isCglibProxyClass(rootClass)) {proxySuperClass = rootClass.getSuperclass();Class[] additionalInterfaces = rootClass.getInterfaces();for (Class additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface);}}// Validate the class, writing log messages as necessary.validateClassIfNecessary(proxySuperClass, classLoader);// Configure CGLIB Enhancer...Enhancer enhancer = createEnhancer();if (classLoader != null) {enhancer.setClassLoader(classLoader);if (classLoader instanceof SmartClassLoader &&((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {enhancer.setUseCache(false);}}enhancer.setSuperclass(proxySuperClass);enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));Callback[] callbacks = getCallbacks(rootClass);Class[] types = new Class[callbacks.length];for (int x = 0; x < types.length; x++) {types[x] = callbacks[x].getClass();}// fixedInterceptorMap only populated at this point, after getCallbacks call aboveenhancer.setCallbackFilter(new ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));enhancer.setCallbackTypes(types);// Generate the proxy class and create a proxy instance.return createProxyClassAndInstance(enhancer, callbacks);}catch (CodeGenerationException ex) {throw new AopConfigException("Could not generate CGLIB subclass of class [" +this.advised.getTargetClass() + "]: " +"Common causes of this problem include using a final class or a non-visible class",ex);}catch (IllegalArgumentException ex) {throw new AopConfigException("Could not generate CGLIB subclass of class [" +this.advised.getTargetClass() + "]: " +"Common causes of this problem include using a final class or a non-visible class",ex);}catch (Exception ex) {// TargetSource.getTarget() failedthrow new AopConfigException("Unexpected AOP exception", ex);}}protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {enhancer.setInterceptDuringConstruction(false);enhancer.setCallbacks(callbacks);return (this.constructorArgs != null ?enhancer.create(this.constructorArgTypes, this.constructorArgs) :enhancer.create());}/*** Creates the CGLIB {@link Enhancer}. Subclasses may wish to override this to return a custom* {@link Enhancer} implementation.*/protected Enhancer createEnhancer() {return new Enhancer();}private Callback[] getCallbacks(Class rootClass) throws Exception {// Parameters used for optimisation choices...boolean exposeProxy = this.advised.isExposeProxy();boolean isFrozen = this.advised.isFrozen();boolean isStatic = this.advised.getTargetSource().isStatic();// Choose an "aop" interceptor (used for AOP calls).Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);// Choose a "straight to target" interceptor. (used for calls that are// unadvised but can return this). May be required to expose the proxy.Callback targetInterceptor;if (exposeProxy) {targetInterceptor = isStatic ?new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());}else {targetInterceptor = isStatic ?new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :new DynamicUnadvisedInterceptor(this.advised.getTargetSource());}// Choose a "direct to target" dispatcher (used for// unadvised calls to static targets that cannot return this).Callback targetDispatcher = isStatic ?new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();Callback[] mainCallbacks = new Callback[] {aopInterceptor, // for normal advicetargetInterceptor, // invoke target without considering advice, if optimizednew SerializableNoOp(), // no override for methods mapped to thistargetDispatcher, this.advisedDispatcher,new EqualsInterceptor(this.advised),new HashCodeInterceptor(this.advised)};Callback[] callbacks;// If the target is a static one and the advice chain is frozen,// then we can make some optimisations by sending the AOP calls// direct to the target using the fixed chain for that method.if (isStatic && isFrozen) {Method[] methods = rootClass.getMethods();Callback[] fixedCallbacks = new Callback[methods.length];this.fixedInterceptorMap = new HashMap(methods.length);// TODO: small memory optimisation here (can skip creation for methods with no advice)for (int x = 0; x < methods.length; x++) {List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());this.fixedInterceptorMap.put(methods[x].toString(), x);}// Now copy both the callbacks from mainCallbacks// and fixedCallbacks into the callbacks array.callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);this.fixedInterceptorOffset = mainCallbacks.length;}else {callbacks = mainCallbacks;}return callbacks;}/*** General purpose AOP callback. Used when the target is dynamic or when the* proxy is not frozen.*/private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {private final AdvisedSupport advised;public DynamicAdvisedInterceptor(AdvisedSupport advised) {this.advised = advised;}@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null;boolean setProxyContext = false;Class targetClass = null;Object target = null;try {if (this.advised.exposeProxy) {// Make invocation available if necessary.oldProxy = AopContext.setCurrentProxy(proxy);setProxyContext = true;}// May be null. Get as late as possible to minimize the time we// "own" the target, in case it comes from a pool...target = getTarget();if (target != null) {targetClass = target.getClass();}List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);Object retVal;// Check whether we only have one InvokerInterceptor: that is,// no real advice, but just reflective invocation of the target.if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {// We can skip creating a MethodInvocation: just invoke the target directly.// Note that the final invoker must be an InvokerInterceptor, so we know// it does nothing but a reflective operation on the target, and no hot// swapping or fancy proxying.Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);retVal = methodProxy.invoke(target, argsToUse);}else {// We need to create a method invocation...retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}retVal = processReturnType(proxy, target, method, retVal);return retVal;}finally {if (target != null) {releaseTarget(target);}if (setProxyContext) {// Restore old proxy.AopContext.setCurrentProxy(oldProxy);}}}//省略...}/*** Implementation of AOP Alliance MethodInvocation used by this AOP proxy.*/private static class CglibMethodInvocation extends ReflectiveMethodInvocation {private final MethodProxy methodProxy;private final boolean publicMethod;public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,Class targetClass, List interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);this.methodProxy = methodProxy;this.publicMethod = Modifier.isPublic(method.getModifiers());}/*** Gives a marginal performance improvement versus using reflection to* invoke the target when invoking public methods.*/@Overrideprotected Object invokeJoinpoint() throws Throwable {if (this.publicMethod) {return this.methodProxy.invoke(this.target, this.arguments);}else {return super.invokeJoinpoint();}}}}

5、各种是的执行顺序是如何和方法调用进行结合的?

和只是创建代理方式的两种方式而已,实际上我们为方法调用添加的各种的执行逻辑都是统一的。在的底层,会把我们定义的各个分别 包裹成一个 ,这些按照加入顺序,构成一个.

比如我们上述的代码:

        //5. 添加不同的AdviceproxyFactoryBean.addAdvice(afterReturningAdvice);proxyFactoryBean.addAdvice(aroundAdvice);proxyFactoryBean.addAdvice(throwsAdvice);proxyFactoryBean.addAdvice(beforeAdvice);proxyFactoryBean.setProxyTargetClass(false);//通过ProxyFactoryBean生成TicketService ticketService = (TicketService) proxyFactoryBean.getObject();ticketService.sellTicket();

当我们调用 .()时,会把这个方法调用转换成一个对象,然后结合上述的我们添加的各种,组成一个:

_spring实现原理_《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

各种本质而言是一个方法调用拦截器,现在让我们看看各个拦截器都干了什么?

spring实现原理__《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

/*** 包裹MethodBeforeAdvice的方法拦截器* Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}.* Used internally by the AOP framework; application developers should not need* to use this class directly.** @author Rod Johnson*/
@SuppressWarnings("serial")
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {private MethodBeforeAdvice advice;/*** Create a new MethodBeforeAdviceInterceptor for the given advice.* @param advice the MethodBeforeAdvice to wrap*/public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {//在调用方法之前,先执行BeforeAdvicethis.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );return mi.proceed();}}

/*** 包裹AfterReturningAdvice的方法拦截器* Interceptor to wrap am {@link org.springframework.aop.AfterReturningAdvice}.* Used internally by the AOP framework; application developers should not need* to use this class directly.** @author Rod Johnson*/
@SuppressWarnings("serial")
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {private final AfterReturningAdvice advice;/*** Create a new AfterReturningAdviceInterceptor for the given advice.* @param advice the AfterReturningAdvice to wrap*/public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {Assert.notNull(advice, "Advice must not be null");this.advice = advice;}@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {//先调用invocationObject retVal = mi.proceed();//调用成功后,调用AfterReturningAdvicethis.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;}}

/*** Interceptor to wrap an after-throwing advice.** 

The signatures on handler methods on the {@code ThrowsAdvice}* implementation method argument must be of the form:
** {@code void afterThrowing([Method, args, target], ThrowableSubclass);}**

Only the last argument is required.**

Some examples of valid methods would be:**

public void afterThrowing(Exception ex)

public void afterThrowing(RemoteException)

public void afterThrowing(Method method, Object[] args, Object target, Exception ex)

public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)

**

This is a class that need not be used by users。** @ Rod * @ */ class tor , { final = ""; final Log = 。(tor。class); final ;/** on , keyed by class */ final Map, > = new , >();/*** a new tor for the given 。

* @param the that the * ( a {@link org。。aop。}* )*/ tor( ) {。(, " must not be null");this。 = ;[] = 。()。();for ( : ) {//定义的方法是方法if (。()。() &&(。()。

== 1 || 。()。 == 4) &&。class。(。()[。()。 - 1])) {// Have an 。。put(。()[。()。 - 1], );if (。()) {。debug("Found : " + );}}}if (this。。()) {throw new tion("At least one must be found in class [" + 。

() + "]");}} int t() { this。。size();}/*** the 。 Can null if not found。* @param the * @ a for the given type*/ ( ) {Class = 。();if (。()) {。trace(" to find for of type [" + 。() + "]");} = this。

。get();while ( == null && != 。class) { = 。(); = this。。get();}if ( != null && 。()) {。debug("Found for of type [" + 。() + "]: " + );} ;}@ ( mi) {//使用大的try,先执行代码,捕获异常try { mi。();}catch ( ex) {//获取异常处理方法 = (ex);//调用异常处理方法if ( != null) {(mi, ex, );}throw ex;}} void ( mi, ex, ) {[] ;if (。

()。 == 1) { = new [] { ex };}else { = new [] {mi。(), mi。(), mi。(), ex};}try {。(this。, );}catch (ption ) {throw 。();}}}

关于,其本身就是一个,所以不需要额外做转换了。

细心的你会发现,在拦截器串中,每个拦截器最后都会调用的()方法。如果按照简单的拦截器的执行串来执行的话,的()方法至少要执行N次(N表示拦截器的个数),因为每个拦截器都会调用一次()方法。更直观地讲,比如我们调用了.()方法,那么,按照这个逻辑,我们会打印出四条记录:

售票............
售票............
售票............
售票............

这样我们肯定不是我们需要的结果!!!!因为按照我们的理解,只应该有一条"售票............"才对。真实的的方法调用过程能够控制这个逻辑按照我们的思路执行,将这个整个方法调用过程连同若干个组成的拦截器链组合成对象,让我们来看看这一执行逻辑是怎么控制的:

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {protected final Object proxy;protected final Object target;protected final Method method;protected Object[] arguments;private final Class targetClass;/*** Lazily initialized map of user-specific attributes for this invocation.*/private Map userAttributes;/*** List of MethodInterceptor and InterceptorAndDynamicMethodMatcher* that need dynamic checks.*/protected final List interceptorsAndDynamicMethodMatchers;/*** Index from 0 of the current interceptor we're invoking.* -1 until we invoke: then the current interceptor.*/private int currentInterceptorIndex = -1;/*** Construct a new ReflectiveMethodInvocation with the given arguments.* @param proxy the proxy object that the invocation was made on* @param target the target object to invoke* @param method the method to invoke* @param arguments the arguments to invoke the method with* @param targetClass the target class, for MethodMatcher invocations* @param interceptorsAndDynamicMethodMatchers interceptors that should be applied,* along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime.* MethodMatchers included in this struct must already have been found to have matched* as far as was possibly statically. Passing an array might be about 10% faster,* but would complicate the code. And it would work only for static pointcuts.*/protected ReflectiveMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,Class targetClass, List interceptorsAndDynamicMethodMatchers) {this.proxy = proxy;//proxy对象this.target = target;//真实的realSubject对象this.targetClass = targetClass;//被代理的类类型this.method = BridgeMethodResolver.findBridgedMethod(method);//方法引用this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);//调用参数this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;//Advice拦截器链}@Overridepublic final Object getProxy() {return this.proxy;}@Overridepublic final Object getThis() {return this.target;}@Overridepublic final AccessibleObject getStaticPart() {return this.method;}/*** Return the method invoked on the proxied interface.* May or may not correspond with a method invoked on an underlying* implementation of that interface.*/@Overridepublic final Method getMethod() {return this.method;}@Overridepublic final Object[] getArguments() {return (this.arguments != null ? this.arguments : new Object[0]);}@Overridepublic void setArguments(Object... arguments) {this.arguments = arguments;}@Overridepublic Object proceed() throws Throwable {//	没有拦截器,则直接调用Joinpoint上的method,即直接调用MethodInvocation We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}// 取得第拦截器链上第N个拦截器 Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);//PointcutInterceptor会走这个逻辑if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;//当前拦截器是符合拦截规则,每个拦截器可以定义是否特定的类和方法名是否符合拦截规则//实际上PointCut定义的方法签名最后会转换成这个MethodMatcher,并置于拦截器中if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {//符合拦截规则,调用拦截器invoke()	return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.// 当前方法不需要拦截器操作,则直接往前推进return proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.//直接调用拦截器,return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}/*** Invoke the joinpoint using reflection.* Subclasses can override this to use custom invocation.* @return the return value of the joinpoint* @throws Throwable if invoking the joinpoint resulted in an exception*/protected Object invokeJoinpoint() throws Throwable {return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);}

上述的代码比较冗杂,解释起来比较繁琐,请看下面一张图,你就知道这段代码的思路了:

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)_spring实现原理_

实例分析

根据上面的执行链上的逻辑,我们将我们上面举的例子的输出结果在整理一下:

拦截器的添加顺序:

        proxyFactoryBean.addAdvice(afterReturningAdvice);proxyFactoryBean.addAdvice(aroundAdvice);proxyFactoryBean.addAdvice(throwsAdvice);proxyFactoryBean.addAdvice(beforeAdvice);

第一个拦截器:

第一个添加的是,它所处的位置是第一个拦截器,执行的操作就是:

	@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {Object retVal = mi.proceed();this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());return retVal;}

也就是说,先完成的()方法再执行相应的;而调用了mi.()方法,导致了当前的调用链后移,进行和后续的操作,也就是说,只能等到整个拦截器链上所有执行完毕后才会生效,所以: :本次服务已结束.... 这句话排在了最后:

_spring实现原理_《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

第二个拦截器:

    @Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("AROUND_ADVICE:BEGIN....");Object returnValue = invocation.proceed();System.out.println("AROUND_ADVICE:END.....");return returnValue;}

现在执行到了第二个拦截器,首先输出了":BEGIN......",接着调用.(),等到剩余的执行完后,再输出":END.....":

_《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)_spring实现原理

第三个拦截器::

拦截器的处理模式是:

	@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {try {//先执行invocation.proceed();	return mi.proceed();}catch (Throwable ex) {//捕捉错误,调用afterThrowing()方法Method handlerMethod = getExceptionHandler(ex);if (handlerMethod != null) {invokeHandlerMethod(mi, ex, handlerMethod);}throw ex;}}

上述的逻辑是,先执行.();如果这个过程中抛出异常,则调用。

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)_spring实现原理_

第四个拦截器::

这个拦截器的工作逻辑如下:

	@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );//先执行Advicereturn mi.proceed();//后执行Invocation}

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)_spring实现原理_

综上所有的拦截器过程,我们就能理解,为什么我们刚开始的输出为什么是下面这样了:

spring实现原理_《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)_

6、与的结合------的条件执行

上面我们提供了几个,你会发现,这些是无条件地加入了我们创建的对象中。无论调用的任何方法,这些都会被触发到。

那么,我们可否告诉,只让它对特定的方法或特定类起作用呢? 这个实际上是要求我们添加一个过滤器,如果满足条件,则生效,否则无效。将这个过滤器抽象成如下的接口:

public interface MethodMatcher {/*** 提供方法签名和所属的Class类型,判断是否支持 * Perform static checking whether the given method matches. If this* returns {@code false} or if the {@link #isRuntime()} method* returns {@code false}, no runtime check (i.e. no.* {@link #matches(java.lang.reflect.Method, Class, Object[])} call) will be made.* @param method the candidate method* @param targetClass the target class (may be {@code null}, in which case* the candidate class must be taken to be the method's declaring class)* @return whether or not this method matches statically*/boolean matches(Method method, Class targetClass);/*** Is this MethodMatcher dynamic, that is, must a final call be made on the* {@link #matches(java.lang.reflect.Method, Class, Object[])} method at* runtime even if the 2-arg matches method returns {@code true}?* 

Can be invoked when an AOP proxy is created, and need not be invoked* again before each method invocation,* @return whether or not a runtime match via the 3-arg* {@link #matches(java.lang.reflect.Method, Class, Object[])} method* is required if static matching passed*/boolean isRuntime();/*** Check whether there a runtime (dynamic) match for this method,* which must have matched statically.*

This method is invoked only if the 2-arg matches method returns* {@code true} for the given method and target class, and if the* {@link #isRuntime()} method returns {@code true}. Invoked* immediately before potential running of the advice, after any* advice earlier in the advice chain has run.* @param method the candidate method* @param targetClass the target class (may be {@code null}, in which case* the candidate class must be taken to be the method's declaring class)* @param args arguments to the method* @return whether there's a runtime match* @see MethodMatcher#matches(Method, Class)*/boolean matches(Method method, Class targetClass, Object... args);/*** Canonical instance that matches all methods.*/MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;}

将这个匹配器和拦截器 结合到一起,就构成了一个新的类 :

/*** Internal framework class, combining a MethodInterceptor instance* with a MethodMatcher for use as an element in the advisor chain.** @author Rod Johnson*/
class InterceptorAndDynamicMethodMatcher {final MethodInterceptor interceptor;final MethodMatcher methodMatcher;public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {this.interceptor = interceptor;this.methodMatcher = methodMatcher;}}

我们再将上述的包含整个拦截器执行链逻辑的实现的核心代码在过一遍:

	@Overridepublic Object proceed() throws Throwable {//	We start with an index of -1 and increment early.if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);//起到一定的过滤作用,如果不匹配,则直接skipif (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {// Evaluate dynamic method matcher here: static part will already have// been evaluated and found to match.InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;//满足匹配规则,则拦截器Advice生效if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {return dm.interceptor.invoke(this);}else {// Dynamic matching failed.// Skip this interceptor and invoke the next in the chain.//拦截器尚未生效,直接skipreturn proceed();}}else {// It's an interceptor, so we just invoke it: The pointcut will have// been evaluated statically before this object was constructed.return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}

实战:

我们现在实现一个,表示拥有某个的。

package org.luanlouis.meditations.thinkinginspring.aop;import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;/*** 实现一个PointcutAdvisor,通过提供的Pointcut,对Advice的执行进行过滤* Created by louis on 2016/4/16.*/
public class FilteredAdvisor implements PointcutAdvisor {private Pointcut pointcut;private Advice advice;public FilteredAdvisor(Pointcut pointcut, Advice advice) {this.pointcut = pointcut;this.advice = advice;}/*** Get the Pointcut that drives this advisor.*/@Overridepublic Pointcut getPointcut() {return pointcut;}@Overridepublic Advice getAdvice() {return advice;}@Overridepublic boolean isPerInstance() {return false;}
}

package org.luanlouis.meditations.thinkinginspring.aop;import org.aopalliance.aop.Advice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactoryBean;/*** 通过ProxyFactoryBean 手动创建 代理对象* Created by louis on 2016/4/14.*/
public class App {public static void main(String[] args) throws Exception {//1.针对不同的时期类型,提供不同的AdviceAdvice beforeAdvice = new TicketServiceBeforeAdvice();Advice afterReturningAdvice = new TicketServiceAfterReturningAdvice();Advice aroundAdvice = new TicketServiceAroundAdvice();Advice throwsAdvice = new TicketServiceThrowsAdvice();RailwayStation railwayStation = new RailwayStation();//2.创建ProxyFactoryBean,用以创建指定对象的Proxy对象ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();//3.设置Proxy的接口proxyFactoryBean.setInterfaces(TicketService.class);//4. 设置RealSubjectproxyFactoryBean.setTarget(railwayStation);//5.使用JDK基于接口实现机制的动态代理生成Proxy代理对象,如果想使用CGLIB,需要将这个flag设置成trueproxyFactoryBean.setProxyTargetClass(true);//5. 添加不同的AdviceproxyFactoryBean.addAdvice(afterReturningAdvice);proxyFactoryBean.addAdvice(aroundAdvice);proxyFactoryBean.addAdvice(throwsAdvice);//proxyFactoryBean.addAdvice(beforeAdvice);proxyFactoryBean.setProxyTargetClass(false);//手动创建一个pointcut,专门拦截sellTicket方法AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();pointcut.setExpression("execution( * sellTicket(..))");//传入创建的beforeAdvice和pointcutFilteredAdvisor sellBeforeAdvior = new FilteredAdvisor(pointcut,beforeAdvice);//添加到FactoryBean中proxyFactoryBean.addAdvisor(sellBeforeAdvior);//通过ProxyFactoryBean生成TicketService ticketService = (TicketService) proxyFactoryBean.getObject();ticketService.sellTicket();System.out.println("---------------------------");ticketService.inquire();}}

这个时候,你会看到输出:

《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)__spring实现原理

从结果中你可以清晰地看到,我们可以对某一个(即)添加一个限制,这样就可以针对指定的方法执行了!本例中使用了,实际上,带底层代码中,会将转换成 参与关于拦截器链的执行逻辑:

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {@Overridepublic List getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, Class targetClass) {// This is somewhat tricky... We have to process introductions first,// but we need to preserve order in the ultimate list.List interceptorList = new ArrayList(config.getAdvisors().length);Class actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();for (Advisor advisor : config.getAdvisors()) {//PointcutAdvisor向 InterceptorAndDynamicMethodMatcher 的转换  if (advisor instanceof PointcutAdvisor) {// Add it conditionally.PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {MethodInterceptor[] interceptors = registry.getInterceptors(advisor);MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {if (mm.isRuntime()) {// Creating a new object instance in the getInterceptors() method// isn't a problem as we normally cache created chains.for (MethodInterceptor interceptor : interceptors) {interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));}}else {interceptorList.addAll(Arrays.asList(interceptors));}}}}else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor;if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}else {Interceptor[] interceptors = registry.getInterceptors(advisor);interceptorList.addAll(Arrays.asList(interceptors));}}return interceptorList;}/*** Determine whether the Advisors contain matching introductions.*/private static boolean hasMatchingIntroductions(Advised config, Class actualClass) {for (int i = 0; i < config.getAdvisors().length; i++) {Advisor advisor = config.getAdvisors()[i];if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor;if (ia.getClassFilter().matches(actualClass)) {return true;}}}return false;}}

7、总结

至此,你已经了解了的AOP的精髓,以及的整个工作机制。我个人认为,想要理解 AOP,你需要从 开始,逐步地分析整个代理的构建过程:

1. 代理对象是怎么生成的(JDK or Cglib)

2. 链(即拦截器链)的构造过程以及执行机制

3. 如何在上添加,并且这个是如何工作的(实际上起到的过滤作用)

最后再讲一下性能问题,如上面描述的,创建Proxy的过程逻辑虽然很清晰,但是你也看到,对于我们每一个方法调用,都会经过非常复杂的层层拦截判断,是否需要拦截处理,这个开销是非常大的。记得的介绍,如果使用的AOP,对项目而言会造成10%的性能消耗,So,用AOP之前要仔细考虑一下性能问题~~~~~

作者的话

本文使用的源码,已经托管到上,读者可以自行clone查看测验~

源码地址: ,请fetch : aop- 分支~

本文关于 AOP的设计原理仅是本人个人的见解和看法,如有任何疑问和错误,请不吝指出,敬请赐教,共同进步!

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了