`
dwj147258
  • 浏览: 194069 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

spring aop原理

阅读更多

0、前言

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

 

    

读完本文,你将了解到
1、Spring内部创建代理对象的过程
2、Spring AOP的核心---ProxyFactoryBean
3、基于JDK面向接口的动态代理JdkDynamicAopProxy生成代理对象
4、基于Cglib子类继承方式的动态代理CglibAopProxy生成代理对象
5、各种Advice是的执行顺序是如何和方法调用进行结合的?
6、PointCut与Advice的结合------Adivce的条件执行
7、总结

 

 

 

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

 

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

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

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. /** 
  4.  * 售票服务 
  5.  * Created by louis on 2016/4/14. 
  6.  */  
  7. public interface TicketService {  
  8.   
  9.     //售票  
  10.     public void sellTicket();  
  11.   
  12.     //问询  
  13.     public void inquire();  
  14.   
  15.     //退票  
  16.     public void withdraw();  
  17. }  

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. /** 
  4.  * RailwayStation 实现 TicketService 
  5.  * Created by louis on 2016/4/14. 
  6.  */  
  7. public class RailwayStation implements TicketService {  
  8.   
  9.     public void sellTicket(){  
  10.         System.out.println("售票............");  
  11.     }  
  12.   
  13.     public void inquire() {  
  14.         System.out.println("问询.............");  
  15.     }  
  16.   
  17.     public void withdraw() {  
  18.         System.out.println("退票.............");  
  19.     }  
  20. }  

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.springframework.aop.MethodBeforeAdvice;  
  4.   
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 执行RealSubject对象的方法之前的处理意见 
  9.  * Created by louis on 2016/4/14. 
  10.  */  
  11. public class TicketServiceBeforeAdvice implements MethodBeforeAdvice {  
  12.   
  13.     public void before(Method method, Object[] args, Object target) throws Throwable {  
  14.         System.out.println("BEFORE_ADVICE: 欢迎光临代售点....");  
  15.     }  
  16. }  

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.springframework.aop.AfterReturningAdvice;  
  4.   
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 返回结果时后的处理意见 
  9.  * Created by louis on 2016/4/14. 
  10.  */  
  11. public class TicketServiceAfterReturningAdvice implements AfterReturningAdvice {  
  12.     @Override  
  13.     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {  
  14.         System.out.println("AFTER_RETURNING:本次服务已结束....");  
  15.     }  
  16. }  

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.springframework.aop.ThrowsAdvice;  
  4.   
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 抛出异常时的处理意见 
  9.  * Created by louis on 2016/4/14. 
  10.  */  
  11. public class TicketServiceThrowsAdvice implements ThrowsAdvice {  
  12.   
  13.     public void afterThrowing(Exception ex){  
  14.         System.out.println("AFTER_THROWING....");  
  15.     }  
  16.     public void afterThrowing(Method method, Object[] args, Object target, Exception ex){  
  17.         System.out.println("调用过程出错啦!!!!!");  
  18.     }  
  19.   
  20. }   

 

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.aopalliance.intercept.MethodInterceptor;  
  4. import org.aopalliance.intercept.MethodInvocation;  
  5. import org.springframework.aop.aspectj.AspectJAroundAdvice;  
  6.   
  7. /** 
  8.  * 
  9.  * AroundAdvice 
  10.  * Created by louis on 2016/4/15. 
  11.  */  
  12. public class TicketServiceAroundAdvice implements MethodInterceptor {  
  13.     @Override  
  14.     public Object invoke(MethodInvocation invocation) throws Throwable {  
  15.         System.out.println("AROUND_ADVICE:BEGIN....");  
  16.         Object returnValue = invocation.proceed();  
  17.         System.out.println("AROUND_ADVICE:END.....");  
  18.         return returnValue;  
  19.     }  
  20. }  


 

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

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.aopalliance.aop.Advice;  
  4. import org.springframework.aop.framework.ProxyFactoryBean;  
  5.   
  6. /** 
  7.  * 通过ProxyFactoryBean 手动创建 代理对象 
  8.  * Created by louis on 2016/4/14. 
  9.  */  
  10. public class App {  
  11.   
  12.     public static void main(String[] args) throws Exception {  
  13.   
  14.         //1.针对不同的时期类型,提供不同的Advice  
  15.         Advice beforeAdvice = new TicketServiceBeforeAdvice();  
  16.         Advice afterReturningAdvice = new TicketServiceAfterReturningAdvice();  
  17.         Advice aroundAdvice = new TicketServiceAroundAdvice();  
  18.         Advice throwsAdvice = new TicketServiceThrowsAdvice();  
  19.   
  20.         RailwayStation railwayStation = new RailwayStation();  
  21.   
  22.         //2.创建ProxyFactoryBean,用以创建指定对象的Proxy对象  
  23.         ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();  
  24.        //3.设置Proxy的接口  
  25.         proxyFactoryBean.setInterfaces(TicketService.class);  
  26.         //4. 设置RealSubject  
  27.         proxyFactoryBean.setTarget(railwayStation);  
  28.         //5.使用JDK基于接口实现机制的动态代理生成Proxy代理对象,如果想使用CGLIB,需要将这个flag设置成true  
  29.         proxyFactoryBean.setProxyTargetClass(true);  
  30.   
  31.         //6. 添加不同的Advice  
  32.   
  33.         proxyFactoryBean.addAdvice(afterReturningAdvice);  
  34.         proxyFactoryBean.addAdvice(aroundAdvice);  
  35.         proxyFactoryBean.addAdvice(throwsAdvice);  
  36.         proxyFactoryBean.addAdvice(beforeAdvice);  
  37.         proxyFactoryBean.setProxyTargetClass(false);  
  38.         //7通过ProxyFactoryBean生成Proxy对象  
  39.         TicketService ticketService = (TicketService) proxyFactoryBean.getObject();  
  40.         ticketService.sellTicket();  
  41.   
  42.     }  
  43.   
  44.   
  45. }  


 

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

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

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

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

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

 

2、Spring AOP的核心---ProxyFactoryBean

 

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

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

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

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

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

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

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

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

 

 

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

 

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

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {  
  2.         //省略若干...  
  3.     /** Proxy的配置信息,这里主要提供Advisor列表,并用于返回AdviceChain */  
  4.     private final AdvisedSupport advised;  
  5.   
  6.     /** 
  7.      * Construct a new JdkDynamicAopProxy for the given AOP configuration. 
  8.      * @param config the AOP configuration as AdvisedSupport object 
  9.      * @throws AopConfigException if the config is invalid. We try to throw an informative 
  10.      * exception in this case, rather than let a mysterious failure happen later. 
  11.      */  
  12.     public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {  
  13.         Assert.notNull(config, "AdvisedSupport must not be null");  
  14.         if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {  
  15.             throw new AopConfigException("No advisors and no TargetSource specified");  
  16.         }  
  17.         this.advised = config;  
  18.     }  
  19.   
  20.   
  21.     @Override  
  22.     public Object getProxy() {  
  23.         return getProxy(ClassUtils.getDefaultClassLoader());  
  24.     }  
  25.         //返回代理实例对象  
  26.     @Override  
  27.     public Object getProxy(ClassLoader classLoader) {  
  28.         if (logger.isDebugEnabled()) {  
  29.             logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());  
  30.         }  
  31.         Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);  
  32.         findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);  
  33.                 //这里的InvocationHandler设置成了当前实例对象,即对这个proxy调用的任何方法,都会调用这个类的invoke()方法  
  34.                 //这里的invoke方法被调用,动态查找Advice列表,组成ReflectMethodInvocation  
  35.         return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);  
  36.     }  
  37.     /** 
  38.      * 对当前proxy调用其上的任何方法,都将转到这个方法上 
  39.          * Implementation of {@code InvocationHandler.invoke}. 
  40.      * <p>Callers will see exactly the exception thrown by the target, 
  41.      * unless a hook method throws an exception. 
  42.      */  
  43.     @Override  
  44.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  45.         MethodInvocation invocation;  
  46.         Object oldProxy = null;  
  47.         boolean setProxyContext = false;  
  48.   
  49.         TargetSource targetSource = this.advised.targetSource;  
  50.         Class<?> targetClass = null;  
  51.         Object target = null;  
  52.   
  53.         try {  
  54.             if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {  
  55.                 // The target does not implement the equals(Object) method itself.  
  56.                 return equals(args[0]);  
  57.             }  
  58.             if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {  
  59.                 // The target does not implement the hashCode() method itself.  
  60.                 return hashCode();  
  61.             }  
  62.             if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&  
  63.                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {  
  64.                 // Service invocations on ProxyConfig with the proxy config...  
  65.                 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);  
  66.             }  
  67.   
  68.             Object retVal;  
  69.   
  70.             if (this.advised.exposeProxy) {  
  71.                 // Make invocation available if necessary.  
  72.                 oldProxy = AopContext.setCurrentProxy(proxy);  
  73.                 setProxyContext = true;  
  74.             }  
  75.   
  76.             // May be null. Get as late as possible to minimize the time we "own" the target,  
  77.             // in case it comes from a pool.  
  78.             target = targetSource.getTarget();  
  79.             if (target != null) {  
  80.                 targetClass = target.getClass();  
  81.             }  
  82.   
  83.             // Get the interception chain for this method.获取当前调用方法的拦截链  
  84.             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  
  85.   
  86.             // Check whether we have any advice. If we don't, we can fallback on direct  
  87.             // reflective invocation of the target, and avoid creating a MethodInvocation.  
  88.                         //如果没有拦截链,则直接调用Joinpoint连接点的方法。  
  89.             if (chain.isEmpty()) {  
  90.                 // We can skip creating a MethodInvocation: just invoke the target directly  
  91.                 // Note that the final invoker must be an InvokerInterceptor so we know it does  
  92.                 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.  
  93.                 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);  
  94.                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);  
  95.             }  
  96.             else {  
  97.                 // We need to create a method invocation...  
  98.                                 //根据给定的拦截链和方法调用信息,创建新的MethodInvocation对象,整个拦截链的工作逻辑都在这个ReflectiveMethodInvocation里   
  99.                 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);  
  100.                 // Proceed to the joinpoint through the interceptor chain.  
  101.                 retVal = invocation.proceed();  
  102.             }  
  103.   
  104.             // Massage return value if necessary.  
  105.             Class<?> returnType = method.getReturnType();  
  106.             if (retVal != null && retVal == target && returnType.isInstance(proxy) &&  
  107.                     !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {  
  108.                 // Special case: it returned "this" and the return type of the method  
  109.                 // is type-compatible. Note that we can't help if the target sets  
  110.                 // a reference to itself in another returned object.  
  111.                 retVal = proxy;  
  112.             }  
  113.             else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {  
  114.                 throw new AopInvocationException(  
  115.                         "Null return value from advice does not match primitive return type for: " + method);  
  116.             }  
  117.             return retVal;  
  118.         }  
  119.         finally {  
  120.             if (target != null && !targetSource.isStatic()) {  
  121.                 // Must have come from TargetSource.  
  122.                 targetSource.releaseTarget(target);  
  123.             }  
  124.             if (setProxyContext) {  
  125.                 // Restore old proxy.  
  126.                 AopContext.setCurrentProxy(oldProxy);  
  127.             }  
  128.         }  
  129.     }  
  130. }  

 

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

 

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

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.springframework.aop.framework;  
  2. /** 
  3.  * CGLIB-based {@link AopProxy} implementation for the Spring AOP framework. 
  4.  * 
  5.  * <p>Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on 
  6.  * Spring's own internally repackaged version of CGLIB 3.</i>. 
  7.  */  
  8. @SuppressWarnings("serial")  
  9. class CglibAopProxy implements AopProxy, Serializable {  
  10.   
  11.     // Constants for CGLIB callback array indices  
  12.     private static final int AOP_PROXY = 0;  
  13.     private static final int INVOKE_TARGET = 1;  
  14.     private static final int NO_OVERRIDE = 2;  
  15.     private static final int DISPATCH_TARGET = 3;  
  16.     private static final int DISPATCH_ADVISED = 4;  
  17.     private static final int INVOKE_EQUALS = 5;  
  18.     private static final int INVOKE_HASHCODE = 6;  
  19.   
  20.   
  21.     /** Logger available to subclasses; static to optimize serialization */  
  22.     protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);  
  23.   
  24.     /** Keeps track of the Classes that we have validated for final methods */  
  25.     private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<Class<?>, Boolean>();  
  26.   
  27.   
  28.     /** The configuration used to configure this proxy */  
  29.     protected final AdvisedSupport advised;  
  30.   
  31.     protected Object[] constructorArgs;  
  32.   
  33.     protected Class<?>[] constructorArgTypes;  
  34.   
  35.     /** Dispatcher used for methods on Advised */  
  36.     private final transient AdvisedDispatcher advisedDispatcher;  
  37.   
  38.     private transient Map<String, Integer> fixedInterceptorMap;  
  39.   
  40.     private transient int fixedInterceptorOffset;  
  41.   
  42.   
  43.     /** 
  44.      * Create a new CglibAopProxy for the given AOP configuration. 
  45.      * @param config the AOP configuration as AdvisedSupport object 
  46.      * @throws AopConfigException if the config is invalid. We try to throw an informative 
  47.      * exception in this case, rather than let a mysterious failure happen later. 
  48.      */  
  49.     public CglibAopProxy(AdvisedSupport config) throws AopConfigException {  
  50.         Assert.notNull(config, "AdvisedSupport must not be null");  
  51.         if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {  
  52.             throw new AopConfigException("No advisors and no TargetSource specified");  
  53.         }  
  54.         this.advised = config;  
  55.         this.advisedDispatcher = new AdvisedDispatcher(this.advised);  
  56.     }  
  57.   
  58.     /** 
  59.      * Set constructor arguments to use for creating the proxy. 
  60.      * @param constructorArgs the constructor argument values 
  61.      * @param constructorArgTypes the constructor argument types 
  62.      */  
  63.     public void setConstructorArguments(Object[] constructorArgs, Class<?>[] constructorArgTypes) {  
  64.         if (constructorArgs == null || constructorArgTypes == null) {  
  65.             throw new IllegalArgumentException("Both 'constructorArgs' and 'constructorArgTypes' need to be specified");  
  66.         }  
  67.         if (constructorArgs.length != constructorArgTypes.length) {  
  68.             throw new IllegalArgumentException("Number of 'constructorArgs' (" + constructorArgs.length +  
  69.                     ") must match number of 'constructorArgTypes' (" + constructorArgTypes.length + ")");  
  70.         }  
  71.         this.constructorArgs = constructorArgs;  
  72.         this.constructorArgTypes = constructorArgTypes;  
  73.     }  
  74.   
  75.   
  76.     @Override  
  77.     public Object getProxy() {  
  78.         return getProxy(null);  
  79.     }  
  80.   
  81.     @Override  
  82.     public Object getProxy(ClassLoader classLoader) {  
  83.         if (logger.isDebugEnabled()) {  
  84.             logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());  
  85.         }  
  86.   
  87.         try {  
  88.             Class<?> rootClass = this.advised.getTargetClass();  
  89.             Assert.state(rootClass != null"Target class must be available for creating a CGLIB proxy");  
  90.   
  91.             Class<?> proxySuperClass = rootClass;  
  92.             if (ClassUtils.isCglibProxyClass(rootClass)) {  
  93.                 proxySuperClass = rootClass.getSuperclass();  
  94.                 Class<?>[] additionalInterfaces = rootClass.getInterfaces();  
  95.                 for (Class<?> additionalInterface : additionalInterfaces) {  
  96.                     this.advised.addInterface(additionalInterface);  
  97.                 }  
  98.             }  
  99.   
  100.             // Validate the class, writing log messages as necessary.  
  101.             validateClassIfNecessary(proxySuperClass, classLoader);  
  102.   
  103.             // Configure CGLIB Enhancer...  
  104.             Enhancer enhancer = createEnhancer();  
  105.             if (classLoader != null) {  
  106.                 enhancer.setClassLoader(classLoader);  
  107.                 if (classLoader instanceof SmartClassLoader &&  
  108.                         ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {  
  109.                     enhancer.setUseCache(false);  
  110.                 }  
  111.             }  
  112.             enhancer.setSuperclass(proxySuperClass);  
  113.             enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));  
  114.             enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);  
  115.             enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));  
  116.   
  117.             Callback[] callbacks = getCallbacks(rootClass);  
  118.             Class<?>[] types = new Class<?>[callbacks.length];  
  119.             for (int x = 0; x < types.length; x++) {  
  120.                 types[x] = callbacks[x].getClass();  
  121.             }  
  122.             // fixedInterceptorMap only populated at this point, after getCallbacks call above  
  123.             enhancer.setCallbackFilter(new ProxyCallbackFilter(  
  124.                     this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));  
  125.             enhancer.setCallbackTypes(types);  
  126.   
  127.             // Generate the proxy class and create a proxy instance.  
  128.             return createProxyClassAndInstance(enhancer, callbacks);  
  129.         }  
  130.         catch (CodeGenerationException ex) {  
  131.             throw new AopConfigException("Could not generate CGLIB subclass of class [" +  
  132.                     this.advised.getTargetClass() + "]: " +  
  133.                     "Common causes of this problem include using a final class or a non-visible class",  
  134.                     ex);  
  135.         }  
  136.         catch (IllegalArgumentException ex) {  
  137.             throw new AopConfigException("Could not generate CGLIB subclass of class [" +  
  138.                     this.advised.getTargetClass() + "]: " +  
  139.                     "Common causes of this problem include using a final class or a non-visible class",  
  140.                     ex);  
  141.         }  
  142.         catch (Exception ex) {  
  143.             // TargetSource.getTarget() failed  
  144.             throw new AopConfigException("Unexpected AOP exception", ex);  
  145.         }  
  146.     }  
  147.   
  148.     protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {  
  149.         enhancer.setInterceptDuringConstruction(false);  
  150.         enhancer.setCallbacks(callbacks);  
  151.         return (this.constructorArgs != null ?  
  152.                 enhancer.create(this.constructorArgTypes, this.constructorArgs) :  
  153.                 enhancer.create());  
  154.     }  
  155.   
  156.     /** 
  157.      * Creates the CGLIB {@link Enhancer}. Subclasses may wish to override this to return a custom 
  158.      * {@link Enhancer} implementation. 
  159.      */  
  160.     protected Enhancer createEnhancer() {  
  161.         return new Enhancer();  
  162.     }  
  163.   
  164.   
  165.   
  166.     private Callback[] getCallbacks(Class<?> rootClass) throws Exception {  
  167.         // Parameters used for optimisation choices...  
  168.         boolean exposeProxy = this.advised.isExposeProxy();  
  169.         boolean isFrozen = this.advised.isFrozen();  
  170.         boolean isStatic = this.advised.getTargetSource().isStatic();  
  171.   
  172.         // Choose an "aop" interceptor (used for AOP calls).  
  173.         Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);  
  174.   
  175.         // Choose a "straight to target" interceptor. (used for calls that are  
  176.         // unadvised but can return this). May be required to expose the proxy.  
  177.         Callback targetInterceptor;  
  178.         if (exposeProxy) {  
  179.             targetInterceptor = isStatic ?  
  180.                     new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :  
  181.                     new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());  
  182.         }  
  183.         else {  
  184.             targetInterceptor = isStatic ?  
  185.                     new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :  
  186.                     new DynamicUnadvisedInterceptor(this.advised.getTargetSource());  
  187.         }  
  188.   
  189.         // Choose a "direct to target" dispatcher (used for  
  190.         // unadvised calls to static targets that cannot return this).  
  191.         Callback targetDispatcher = isStatic ?  
  192.                 new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();  
  193.   
  194.         Callback[] mainCallbacks = new Callback[] {  
  195.                 aopInterceptor,  // for normal advice  
  196.                 targetInterceptor,  // invoke target without considering advice, if optimized  
  197.                 new SerializableNoOp(),  // no override for methods mapped to this  
  198.                 targetDispatcher, this.advisedDispatcher,  
  199.                 new EqualsInterceptor(this.advised),  
  200.                 new HashCodeInterceptor(this.advised)  
  201.         };  
  202.   
  203.         Callback[] callbacks;  
  204.   
  205.         // If the target is a static one and the advice chain is frozen,  
  206.         // then we can make some optimisations by sending the AOP calls  
  207.         // direct to the target using the fixed chain for that method.  
  208.         if (isStatic && isFrozen) {  
  209.             Method[] methods = rootClass.getMethods();  
  210.             Callback[] fixedCallbacks = new Callback[methods.length];  
  211.             this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);  
  212.   
  213.             // TODO: small memory optimisation here (can skip creation for methods with no advice)  
  214.             for (int x = 0; x < methods.length; x++) {  
  215.                 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);  
  216.                 fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(  
  217.                         chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());  
  218.                 this.fixedInterceptorMap.put(methods[x].toString(), x);  
  219.             }  
  220.   
  221.             // Now copy both the callbacks from mainCallbacks  
  222.             // and fixedCallbacks into the callbacks array.  
  223.             callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];  
  224.             System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);  
  225.             System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);  
  226.             this.fixedInterceptorOffset = mainCallbacks.length;  
  227.         }  
  228.         else {  
  229.             callbacks = mainCallbacks;  
  230.         }  
  231.         return callbacks;  
  232.     }  
  233.   
  234.   
  235.     /** 
  236.      * General purpose AOP callback. Used when the target is dynamic or when the 
  237.      * proxy is not frozen. 
  238.      */  
  239.     private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {  
  240.   
  241.         private final AdvisedSupport advised;  
  242.   
  243.         public DynamicAdvisedInterceptor(AdvisedSupport advised) {  
  244.             this.advised = advised;  
  245.         }  
  246.   
  247.         @Override  
  248.         public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
  249.             Object oldProxy = null;  
  250.             boolean setProxyContext = false;  
  251.             Class<?> targetClass = null;  
  252.             Object target = null;  
  253.             try {  
  254.                 if (this.advised.exposeProxy) {  
  255.                     // Make invocation available if necessary.  
  256.                     oldProxy = AopContext.setCurrentProxy(proxy);  
  257.                     setProxyContext = true;  
  258.                 }  
  259.                 // May be null. Get as late as possible to minimize the time we  
  260.                 // "own" the target, in case it comes from a pool...  
  261.                 target = getTarget();  
  262.                 if (target != null) {  
  263.                     targetClass = target.getClass();  
  264.                 }  
  265.                 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  
  266.                 Object retVal;  
  267.                 // Check whether we only have one InvokerInterceptor: that is,  
  268.                 // no real advice, but just reflective invocation of the target.  
  269.                 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {  
  270.                     // We can skip creating a MethodInvocation: just invoke the target directly.  
  271.                     // Note that the final invoker must be an InvokerInterceptor, so we know  
  272.                     // it does nothing but a reflective operation on the target, and no hot  
  273.                     // swapping or fancy proxying.  
  274.                     Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);  
  275.                     retVal = methodProxy.invoke(target, argsToUse);  
  276.                 }  
  277.                 else {  
  278.                     // We need to create a method invocation...  
  279.                     retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();  
  280.                 }  
  281.                 retVal = processReturnType(proxy, target, method, retVal);  
  282.                 return retVal;  
  283.             }  
  284.             finally {  
  285.                 if (target != null) {  
  286.                     releaseTarget(target);  
  287.                 }  
  288.                 if (setProxyContext) {  
  289.                     // Restore old proxy.  
  290.                     AopContext.setCurrentProxy(oldProxy);  
  291.                 }  
  292.             }  
  293.         }  
  294.         //省略...  
  295.     }  
  296.   
  297.   
  298.     /** 
  299.      * Implementation of AOP Alliance MethodInvocation used by this AOP proxy. 
  300.      */  
  301.     private static class CglibMethodInvocation extends ReflectiveMethodInvocation {  
  302.   
  303.         private final MethodProxy methodProxy;  
  304.   
  305.         private final boolean publicMethod;  
  306.   
  307.         public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,  
  308.                 Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {  
  309.   
  310.             super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);  
  311.             this.methodProxy = methodProxy;  
  312.             this.publicMethod = Modifier.isPublic(method.getModifiers());  
  313.         }  
  314.   
  315.         /** 
  316.          * Gives a marginal performance improvement versus using reflection to 
  317.          * invoke the target when invoking public methods. 
  318.          */  
  319.         @Override  
  320.         protected Object invokeJoinpoint() throws Throwable {  
  321.             if (this.publicMethod) {  
  322.                 return this.methodProxy.invoke(this.target, this.arguments);  
  323.             }  
  324.             else {  
  325.                 return super.invokeJoinpoint();  
  326.             }  
  327.         }  
  328.     }  
  329.   
  330. }  

 

 

 

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

 

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

比如我们上述的代码:

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. //5. 添加不同的Advice  
  2.   
  3. proxyFactoryBean.addAdvice(afterReturningAdvice);  
  4. proxyFactoryBean.addAdvice(aroundAdvice);  
  5. proxyFactoryBean.addAdvice(throwsAdvice);  
  6. proxyFactoryBean.addAdvice(beforeAdvice);  
  7. proxyFactoryBean.setProxyTargetClass(false);  
  8. //通过ProxyFactoryBean生成  
  9. TicketService ticketService = (TicketService) proxyFactoryBean.getObject();  
  10. ticketService.sellTicket();  

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

 

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

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 包裹MethodBeforeAdvice的方法拦截器 
  3.  * Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}. 
  4.  * Used internally by the AOP framework; application developers should not need 
  5.  * to use this class directly. 
  6.  * 
  7.  * @author Rod Johnson 
  8.  */  
  9. @SuppressWarnings("serial")  
  10. public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {  
  11.   
  12.     private MethodBeforeAdvice advice;  
  13.   
  14.   
  15.     /** 
  16.      * Create a new MethodBeforeAdviceInterceptor for the given advice. 
  17.      * @param advice the MethodBeforeAdvice to wrap 
  18.      */  
  19.     public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {  
  20.         Assert.notNull(advice, "Advice must not be null");  
  21.         this.advice = advice;  
  22.     }  
  23.   
  24.     @Override  
  25.     public Object invoke(MethodInvocation mi) throws Throwable {  
  26.         //在调用方法之前,先执行BeforeAdvice  
  27.         this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );  
  28.         return mi.proceed();  
  29.     }  
  30.   
  31. }  

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 包裹AfterReturningAdvice的方法拦截器 
  3.  * Interceptor to wrap am {@link org.springframework.aop.AfterReturningAdvice}. 
  4.  * Used internally by the AOP framework; application developers should not need 
  5.  * to use this class directly. 
  6.  * 
  7.  * @author Rod Johnson 
  8.  */  
  9. @SuppressWarnings("serial")  
  10. public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {  
  11.   
  12.     private final AfterReturningAdvice advice;  
  13.   
  14.   
  15.     /** 
  16.      * Create a new AfterReturningAdviceInterceptor for the given advice. 
  17.      * @param advice the AfterReturningAdvice to wrap 
  18.      */  
  19.     public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {  
  20.         Assert.notNull(advice, "Advice must not be null");  
  21.         this.advice = advice;  
  22.     }  
  23.   
  24.     @Override  
  25.     public Object invoke(MethodInvocation mi) throws Throwable {  
  26.         //先调用invocation  
  27.         Object retVal = mi.proceed();  
  28.         //调用成功后,调用AfterReturningAdvice  
  29.         this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());  
  30.         return retVal;  
  31.     }  
  32.   
  33. }  

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Interceptor to wrap an after-throwing advice. 
  3.  * 
  4.  * <p>The signatures on handler methods on the {@code ThrowsAdvice} 
  5.  * implementation method argument must be of the form:<br> 
  6.  * 
  7.  * {@code void afterThrowing([Method, args, target], ThrowableSubclass);} 
  8.  * 
  9.  * <p>Only the last argument is required. 
  10.  * 
  11.  * <p>Some examples of valid methods would be: 
  12.  * 
  13.  * <pre class="code">public void afterThrowing(Exception ex)</pre> 
  14.  * <pre class="code">public void afterThrowing(RemoteException)</pre> 
  15.  * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, Exception ex)</pre> 
  16.  * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)</pre> 
  17.  * 
  18.  * <p>This is a framework class that need not be used directly by Spring users. 
  19.  * 
  20.  * @author Rod Johnson 
  21.  * @author Juergen Hoeller 
  22.  */  
  23. public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {  
  24.   
  25.     private static final String AFTER_THROWING = "afterThrowing";  
  26.   
  27.     private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);  
  28.   
  29.   
  30.     private final Object throwsAdvice;  
  31.   
  32.     /** Methods on throws advice, keyed by exception class */  
  33.     private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<Class<?>, Method>();  
  34.   
  35.   
  36.     /** 
  37.      * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice. 
  38.      * @param throwsAdvice the advice object that defines the exception 
  39.      * handler methods (usually a {@link org.springframework.aop.ThrowsAdvice} 
  40.      * implementation) 
  41.      */  
  42.     public ThrowsAdviceInterceptor(Object throwsAdvice) {  
  43.         Assert.notNull(throwsAdvice, "Advice must not be null");  
  44.         this.throwsAdvice = throwsAdvice;  
  45.   
  46.         Method[] methods = throwsAdvice.getClass().getMethods();  
  47.         for (Method method : methods) {  
  48.             //ThrowsAdvice定义的afterThrowing方法是Handler方法  
  49.             if (method.getName().equals(AFTER_THROWING) &&  
  50.                     (method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) &&  
  51.                     Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1])  
  52.                 ) {  
  53.                 // Have an exception handler  
  54.                 this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method);  
  55.                 if (logger.isDebugEnabled()) {  
  56.                     logger.debug("Found exception handler method: " + method);  
  57.                 }  
  58.             }  
  59.         }  
  60.   
  61.         if (this.exceptionHandlerMap.isEmpty()) {  
  62.             throw new IllegalArgumentException(  
  63.                     "At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");  
  64.         }  
  65.     }  
  66.   
  67.     public int getHandlerMethodCount() {  
  68.         return this.exceptionHandlerMap.size();  
  69.     }  
  70.   
  71.     /** 
  72.      * Determine the exception handle method. Can return null if not found. 
  73.      * @param exception the exception thrown 
  74.      * @return a handler for the given exception type 
  75.      */  
  76.     private Method getExceptionHandler(Throwable exception) {  
  77.         Class<?> exceptionClass = exception.getClass();  
  78.         if (logger.isTraceEnabled()) {  
  79.             logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]");  
  80.         }  
  81.         Method handler = this.exceptionHandlerMap.get(exceptionClass);  
  82.         while (handler == null && exceptionClass != Throwable.class) {  
  83.             exceptionClass = exceptionClass.getSuperclass();  
  84.             handler = this.exceptionHandlerMap.get(exceptionClass);  
  85.         }  
  86.         if (handler != null && logger.isDebugEnabled()) {  
  87.             logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler);  
  88.         }  
  89.         return handler;  
  90.     }  
  91.   
  92.     @Override  
  93.     public Object invoke(MethodInvocation mi) throws Throwable {  
  94.         //使用大的try,先执行代码,捕获异常  
  95.         try {  
  96.             return mi.proceed();  
  97.         }  
  98.         catch (Throwable ex) {  
  99.             //获取异常处理方法  
  100.             Method handlerMethod = getExceptionHandler(ex);  
  101.             //调用异常处理方法  
  102.             if (handlerMethod != null) {  
  103.                 invokeHandlerMethod(mi, ex, handlerMethod);  
  104.             }  
  105.             throw ex;  
  106.         }  
  107.     }  
  108.   
  109.     private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {  
  110.         Object[] handlerArgs;  
  111.         if (method.getParameterTypes().length == 1) {  
  112.             handlerArgs = new Object[] { ex };  
  113.         }  
  114.         else {  
  115.             handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};  
  116.         }  
  117.         try {  
  118.             method.invoke(this.throwsAdvice, handlerArgs);  
  119.         }  
  120.         catch (InvocationTargetException targetEx) {  
  121.             throw targetEx.getTargetException();  
  122.         }  
  123.     }  
  124.   
  125. }  

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

 

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

 

[plain] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. 售票............  
  2. 售票............  
  3. 售票............  
  4. 售票............  
这样我们肯定不是我们需要的结果!!!!因为按照我们的理解,只应该有一条"售票............"才对。真实的Spring的方法调用过程能够控制这个逻辑按照我们的思路执行,Spring将这个整个方法调用过程连同若干个Advice组成的拦截器链组合成ReflectiveMethodInvocation对象,让我们来看看这一执行逻辑是怎么控制的:

 

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {  
  2.   
  3.     protected final Object proxy;  
  4.   
  5.     protected final Object target;  
  6.   
  7.     protected final Method method;  
  8.   
  9.     protected Object[] arguments;  
  10.   
  11.     private final Class<?> targetClass;  
  12.   
  13.     /** 
  14.      * Lazily initialized map of user-specific attributes for this invocation. 
  15.      */  
  16.     private Map<String, Object> userAttributes;  
  17.   
  18.     /** 
  19.      * List of MethodInterceptor and InterceptorAndDynamicMethodMatcher 
  20.      * that need dynamic checks. 
  21.      */  
  22.     protected final List<?> interceptorsAndDynamicMethodMatchers;  
  23.   
  24.     /** 
  25.      * Index from 0 of the current interceptor we're invoking. 
  26.      * -1 until we invoke: then the current interceptor. 
  27.      */  
  28.     private int currentInterceptorIndex = -1;  
  29.   
  30.   
  31.     /** 
  32.      * Construct a new ReflectiveMethodInvocation with the given arguments. 
  33.      * @param proxy the proxy object that the invocation was made on 
  34.      * @param target the target object to invoke 
  35.      * @param method the method to invoke 
  36.      * @param arguments the arguments to invoke the method with 
  37.      * @param targetClass the target class, for MethodMatcher invocations 
  38.      * @param interceptorsAndDynamicMethodMatchers interceptors that should be applied, 
  39.      * along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime. 
  40.      * MethodMatchers included in this struct must already have been found to have matched 
  41.      * as far as was possibly statically. Passing an array might be about 10% faster, 
  42.      * but would complicate the code. And it would work only for static pointcuts. 
  43.      */  
  44.     protected ReflectiveMethodInvocation(  
  45.             Object proxy, Object target, Method method, Object[] arguments,  
  46.             Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {  
  47.   
  48.         this.proxy = proxy;//proxy对象  
  49.         this.target = target;//真实的realSubject对象  
  50.         this.targetClass = targetClass;//被代理的类类型  
  51.         this.method = BridgeMethodResolver.findBridgedMethod(method);//方法引用  
  52.         this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);//调用参数  
  53.         this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;//Advice拦截器链  
  54.     }  
  55.   
  56.   
  57.     @Override  
  58.     public final Object getProxy() {  
  59.         return this.proxy;  
  60.     }  
  61.   
  62.     @Override  
  63.     public final Object getThis() {  
  64.         return this.target;  
  65.     }  
  66.   
  67.     @Override  
  68.     public final AccessibleObject getStaticPart() {  
  69.         return this.method;  
  70.     }  
  71.   
  72.     /** 
  73.      * Return the method invoked on the proxied interface. 
  74.      * May or may not correspond with a method invoked on an underlying 
  75.      * implementation of that interface. 
  76.      */  
  77.     @Override  
  78.     public final Method getMethod() {  
  79.         return this.method;  
  80.     }  
  81.   
  82.     @Override  
  83.     public final Object[] getArguments() {  
  84.         return (this.arguments != null ? this.arguments : new Object[0]);  
  85.     }  
  86.   
  87.     @Override  
  88.     public void setArguments(Object... arguments) {  
  89.         this.arguments = arguments;  
  90.     }  
  91.   
  92.   
  93.     @Override  
  94.     public Object proceed() throws Throwable {  
  95.         //  没有拦截器,则直接调用Joinpoint上的method,即直接调用MethodInvocation We start with an index of -1 and increment early.  
  96.         if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {  
  97.             return invokeJoinpoint();  
  98.         }  
  99.                 // 取得第拦截器链上第N个拦截器   
  100.         Object interceptorOrInterceptionAdvice =  
  101.                 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
  102.         //PointcutInterceptor会走这个逻辑  
  103.                 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  
  104.             // Evaluate dynamic method matcher here: static part will already have  
  105.             // been evaluated and found to match.  
  106.             InterceptorAndDynamicMethodMatcher dm =  
  107.                     (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  
  108.             //当前拦截器是符合拦截规则,每个拦截器可以定义是否特定的类和方法名是否符合拦截规则  
  109.                         //实际上PointCut定义的方法签名最后会转换成这个MethodMatcher,并置于拦截器中  
  110.                         if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  
  111.                  //符合拦截规则,调用拦截器invoke()   
  112.                              return dm.interceptor.invoke(this);  
  113.             }  
  114.             else {  
  115.                 // Dynamic matching failed.  
  116.                 // Skip this interceptor and invoke the next in the chain.  
  117.                                 // 当前方法不需要拦截器操作,则直接往前推进  
  118.                                 return proceed();  
  119.             }  
  120.         }  
  121.         else {  
  122.             // It's an interceptor, so we just invoke it: The pointcut will have  
  123.             // been evaluated statically before this object was constructed.  
  124.                         //直接调用拦截器,  
  125.                         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
  126.         }  
  127.     }  
  128.   
  129.     /** 
  130.      * Invoke the joinpoint using reflection. 
  131.      * Subclasses can override this to use custom invocation. 
  132.      * @return the return value of the joinpoint 
  133.      * @throws Throwable if invoking the joinpoint resulted in an exception 
  134.      */  
  135.     protected Object invokeJoinpoint() throws Throwable {  
  136.         return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);  
  137.     }  

 

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

 

实例分析

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

Advice拦截器的添加顺序:

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. proxyFactoryBean.addAdvice(afterReturningAdvice);  
  2. proxyFactoryBean.addAdvice(aroundAdvice);  
  3. proxyFactoryBean.addAdvice(throwsAdvice);  
  4. proxyFactoryBean.addAdvice(beforeAdvice);  
第一个拦截器:AfterReturningAdvice

 

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

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public Object invoke(MethodInvocation mi) throws Throwable {  
  3.     Object retVal = mi.proceed();  
  4.     this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());  
  5.     return retVal;  
  6. }  
也就是说,先完成MethodInvocation的proceed()方法再执行相应的advice;而调用了mi.proceed()方法,导致了当前的调用链后移,进行和后续的操作,也就是说,AfterReturningAdvice只能等到整个拦截器链上所有执行完毕后才会生效,所以:AFTER_RETURNING:本次服务已结束.... 这句话排在了最后:

 

第二个拦截器:AroundAdvice

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public Object invoke(MethodInvocation invocation) throws Throwable {  
  3.     System.out.println("AROUND_ADVICE:BEGIN....");  
  4.     Object returnValue = invocation.proceed();  
  5.     System.out.println("AROUND_ADVICE:END.....");  
  6.     return returnValue;  
  7. }  
现在执行到了第二个拦截器,首先输出了"AROUND_ADVICE:BEGIN......",接着调用Invocation.proceed(),等到剩余的执行完后,再输出"AROUND_ADVICE:END.....":

 

 

第三个拦截器:ThrowsAdvice:

ThrowsAdvice拦截器的处理模式是:

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public Object invoke(MethodInvocation mi) throws Throwable {  
  3.     try {  
  4.            //先执行invocation.proceed();     
  5.                       return mi.proceed();  
  6.     }  
  7.     catch (Throwable ex) {  
  8.                       //捕捉错误,调用afterThrowing()方法  
  9.                        Method handlerMethod = getExceptionHandler(ex);  
  10.         if (handlerMethod != null) {  
  11.             invokeHandlerMethod(mi, ex, handlerMethod);  
  12.         }  
  13.         throw ex;  
  14.     }  
  15. }  

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

 

第四个拦截器:BeforeAdvice:

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

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public Object invoke(MethodInvocation mi) throws Throwable {  
  3.     this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );//先执行Advice  
  4.     return mi.proceed();//后执行Invocation  
  5. }  

 

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

 

 

6、PointCut与Advice的结合------Adivce的条件执行

 

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

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

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. public interface MethodMatcher {  
  2.   
  3.     /** 
  4.      * 提供方法签名和所属的Class类型,判断是否支持  
  5.          * Perform static checking whether the given method matches. If this 
  6.      * returns {@code false} or if the {@link #isRuntime()} method 
  7.      * returns {@code false}, no runtime check (i.e. no. 
  8.      * {@link #matches(java.lang.reflect.Method, Class, Object[])} call) will be made. 
  9.      * @param method the candidate method 
  10.      * @param targetClass the target class (may be {@code null}, in which case 
  11.      * the candidate class must be taken to be the method's declaring class) 
  12.      * @return whether or not this method matches statically 
  13.      */  
  14.     boolean matches(Method method, Class<?> targetClass);  
  15.   
  16.     /** 
  17.      * Is this MethodMatcher dynamic, that is, must a final call be made on the 
  18.      * {@link #matches(java.lang.reflect.Method, Class, Object[])} method at 
  19.      * runtime even if the 2-arg matches method returns {@code true}? 
  20.      * <p>Can be invoked when an AOP proxy is created, and need not be invoked 
  21.      * again before each method invocation, 
  22.      * @return whether or not a runtime match via the 3-arg 
  23.      * {@link #matches(java.lang.reflect.Method, Class, Object[])} method 
  24.      * is required if static matching passed 
  25.      */  
  26.     boolean isRuntime();  
  27.   
  28.     /** 
  29.      * Check whether there a runtime (dynamic) match for this method, 
  30.      * which must have matched statically. 
  31.      * <p>This method is invoked only if the 2-arg matches method returns 
  32.      * {@code true} for the given method and target class, and if the 
  33.      * {@link #isRuntime()} method returns {@code true}. Invoked 
  34.      * immediately before potential running of the advice, after any 
  35.      * advice earlier in the advice chain has run. 
  36.      * @param method the candidate method 
  37.      * @param targetClass the target class (may be {@code null}, in which case 
  38.      * the candidate class must be taken to be the method's declaring class) 
  39.      * @param args arguments to the method 
  40.      * @return whether there's a runtime match 
  41.      * @see MethodMatcher#matches(Method, Class) 
  42.      */  
  43.     boolean matches(Method method, Class<?> targetClass, Object... args);  
  44.   
  45.   
  46.     /** 
  47.      * Canonical instance that matches all methods. 
  48.      */  
  49.     MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;  
  50.   
  51. }  

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

 

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Internal framework class, combining a MethodInterceptor instance 
  3.  * with a MethodMatcher for use as an element in the advisor chain. 
  4.  * 
  5.  * @author Rod Johnson 
  6.  */  
  7. class InterceptorAndDynamicMethodMatcher {  
  8.   
  9.     final MethodInterceptor interceptor;  
  10.   
  11.     final MethodMatcher methodMatcher;  
  12.   
  13.     public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {  
  14.         this.interceptor = interceptor;  
  15.         this.methodMatcher = methodMatcher;  
  16.     }  
  17.   
  18. }  
我们再将上述的包含整个拦截器执行链逻辑的ReflectiveMethodInvocation实现的核心代码在过一遍:

 

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public Object proceed() throws Throwable {  
  3.     //  We start with an index of -1 and increment early.  
  4.     if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {  
  5.         return invokeJoinpoint();  
  6.     }  
  7.   
  8.     Object interceptorOrInterceptionAdvice =  
  9.             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
  10.     //起到一定的过滤作用,如果不匹配,则直接skip  
  11.                if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  
  12.         // Evaluate dynamic method matcher here: static part will already have  
  13.         // been evaluated and found to match.  
  14.         InterceptorAndDynamicMethodMatcher dm =  
  15.                 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  
  16.         //满足匹配规则,则拦截器Advice生效  
  17.                        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  
  18.             return dm.interceptor.invoke(this);  
  19.         }  
  20.         else {  
  21.             // Dynamic matching failed.  
  22.             // Skip this interceptor and invoke the next in the chain.  
  23.                                //拦截器尚未生效,直接skip  
  24.                                return proceed();  
  25.         }  
  26.     }  
  27.     else {  
  28.         // It's an interceptor, so we just invoke it: The pointcut will have  
  29.         // been evaluated statically before this object was constructed.  
  30.         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
  31.     }  
  32. }  

实战:

 

我们现在实现一个PointcutAdisor,PointcutAdvisor表示拥有某个Pointcut的Advisor。

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.aopalliance.aop.Advice;  
  4. import org.springframework.aop.Pointcut;  
  5. import org.springframework.aop.PointcutAdvisor;  
  6.   
  7. /** 
  8.  * 实现一个PointcutAdvisor,通过提供的Pointcut,对Advice的执行进行过滤 
  9.  * Created by louis on 2016/4/16. 
  10.  */  
  11. public class FilteredAdvisor implements PointcutAdvisor {  
  12.   
  13.     private Pointcut pointcut;  
  14.     private Advice advice;  
  15.   
  16.     public FilteredAdvisor(Pointcut pointcut, Advice advice) {  
  17.         this.pointcut = pointcut;  
  18.         this.advice = advice;  
  19.     }  
  20.   
  21.     /** 
  22.      * Get the Pointcut that drives this advisor. 
  23.      */  
  24.     @Override  
  25.     public Pointcut getPointcut() {  
  26.         return pointcut;  
  27.     }  
  28.   
  29.     @Override  
  30.     public Advice getAdvice() {  
  31.         return advice;  
  32.     }  
  33.   
  34.     @Override  
  35.     public boolean isPerInstance() {  
  36.         return false;  
  37.     }  
  38. }  

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.aopalliance.aop.Advice;  
  4. import org.springframework.aop.aspectj.AspectJExpressionPointcut;  
  5. import org.springframework.aop.framework.ProxyFactoryBean;  
  6.   
  7. /** 
  8.  * 通过ProxyFactoryBean 手动创建 代理对象 
  9.  * Created by louis on 2016/4/14. 
  10.  */  
  11. public class App {  
  12.   
  13.     public static void main(String[] args) throws Exception {  
  14.   
  15.         //1.针对不同的时期类型,提供不同的Advice  
  16.         Advice beforeAdvice = new TicketServiceBeforeAdvice();  
  17.         Advice afterReturningAdvice = new TicketServiceAfterReturningAdvice();  
  18.         Advice aroundAdvice = new TicketServiceAroundAdvice();  
  19.         Advice throwsAdvice = new TicketServiceThrowsAdvice();  
  20.   
  21.         RailwayStation railwayStation = new RailwayStation();  
  22.   
  23.         //2.创建ProxyFactoryBean,用以创建指定对象的Proxy对象  
  24.         ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();  
  25.        //3.设置Proxy的接口  
  26.         proxyFactoryBean.setInterfaces(TicketService.class);  
  27.         //4. 设置RealSubject  
  28.         proxyFactoryBean.setTarget(railwayStation);  
  29.         //5.使用JDK基于接口实现机制的动态代理生成Proxy代理对象,如果想使用CGLIB,需要将这个flag设置成true  
  30.         proxyFactoryBean.setProxyTargetClass(true);  
  31.   
  32.         //5. 添加不同的Advice  
  33.   
  34.         proxyFactoryBean.addAdvice(afterReturningAdvice);  
  35.         proxyFactoryBean.addAdvice(aroundAdvice);  
  36.         proxyFactoryBean.addAdvice(throwsAdvice);  
  37.         //proxyFactoryBean.addAdvice(beforeAdvice);  
  38.         proxyFactoryBean.setProxyTargetClass(false);  
  39.   
  40.         //手动创建一个pointcut,专门拦截sellTicket方法  
  41.         AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();  
  42.         pointcut.setExpression("execution( * sellTicket(..))");  
  43.         //传入创建的beforeAdvice和pointcut  
  44.         FilteredAdvisor sellBeforeAdvior = new FilteredAdvisor(pointcut,beforeAdvice);  
  45.         //添加到FactoryBean中  
  46.         proxyFactoryBean.addAdvisor(sellBeforeAdvior);  
  47.           
  48.         //通过ProxyFactoryBean生成  
  49.         TicketService ticketService = (TicketService) proxyFactoryBean.getObject();  
  50.         ticketService.sellTicket();  
  51.         System.out.println("---------------------------");  
  52.         ticketService.inquire();  
  53.   
  54.     }  
  55.   
  56.   
  57. }  

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

 

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

 

[java] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {  
  2.   
  3.     @Override  
  4.     public List<Object> getInterceptorsAndDynamicInterceptionAdvice(  
  5.             Advised config, Method method, Class<?> targetClass) {  
  6.   
  7.         // This is somewhat tricky... We have to process introductions first,  
  8.         // but we need to preserve order in the ultimate list.  
  9.         List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);  
  10.         Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());  
  11.         boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);  
  12.         AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();  
  13.                   
  14.         for (Advisor advisor : config.getAdvisors()) {  
  15.                                 //PointcutAdvisor向 InterceptorAndDynamicMethodMatcher 的转换    
  16.                                if (advisor instanceof PointcutAdvisor) {  
  17.                 // Add it conditionally.  
  18.                 PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;  
  19.                 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {  
  20.                     MethodInterceptor[] interceptors = registry.getInterceptors(advisor);  
  21.                     MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();  
  22.                     if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {  
  23.                         if (mm.isRuntime()) {  
  24.                             // Creating a new object instance in the getInterceptors() method  
  25.                             // isn't a problem as we normally cache created chains.  
  26.                             for (MethodInterceptor interceptor : interceptors) {  
  27.                                 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));  
  28.                             }  
  29.                         }  
  30.                         else {  
  31.                             interceptorList.addAll(Arrays.asList(interceptors));  
  32.                         }  
  33.                     }  
  34.                 }  
  35.             }  
  36.             else if (advisor instanceof IntroductionAdvisor) {  
  37.                 IntroductionAdvisor ia = (IntroductionAdvisor) advisor;  
  38.                 if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {  
  39.                     Interceptor[] interceptors = registry.getInterceptors(advisor);  
  40.                     interceptorList.addAll(Arrays.asList(interceptors));  
  41.                 }  
  42.             }  
  43.             else {  
  44.                 Interceptor[] interceptors = registry.getInterceptors(advisor);  
  45.                 interceptorList.addAll(Arrays.asList(interceptors));  
  46.             }  
  47.         }  
  48.   
  49.         return interceptorList;  
  50.     }  
  51.   
  52.     /** 
  53.      * Determine whether the Advisors contain matching introductions. 
  54.      */  
  55.     private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {  
  56.         for (int i = 0; i < config.getAdvisors().length; i++) {  
  57.             Advisor advisor = config.getAdvisors()[i];  
  58.             if (advisor instanceof IntroductionAdvisor) {  
  59.                 IntroductionAdvisor ia = (IntroductionAdvisor) advisor;  
  60.                 if (ia.getClassFilter().matches(actualClass)) {  
  61.                     return true;  
  62.                 }  
  63.             }  
  64.         }  
  65.         return false;  
  66.     }  
  67.   
  68. }  


 

 

7、总结

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

 

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

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

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

      

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

分享到:
评论

相关推荐

    Spring AOP面向方面编程原理:AOP概念

    ### Spring AOP面向方面编程原理:AOP概念详解 #### 一、引言 随着软件系统的日益复杂,传统的面向对象编程(OOP)...对于希望深入了解Spring AOP原理与实践的读者来说,掌握以上概念将是开启面向方面编程之旅的第一步。

    代理模式与动态代理--Spring AOP原理.doc

    代理模式与动态代理--Spring AOP原理.doc

    spring aop实现原理

    NULL 博文链接:https://zhang-yingjie-qq-com.iteye.com/blog/319927

    spring aop 原理解析

    【Spring AOP 原理解析】 Spring AOP(面向切面编程)是Spring框架的重要组成部分,它允许开发者定义“切面”来封装系统中的交叉关注点,如日志、事务管理、安全性等,从而提高代码的可复用性和可维护性。在Spring ...

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    面向切面编程(AOP)是一种编程范式,旨在将横切关注点(如日志、安全等)与业务逻辑分离,从而提高模块化。...利用Java反射机制和Spring AOP框架,开发者可以方便地实现AOP,从而提升代码的模块化和可维护性。

    Java动态代理(Spring Aop原理)

    2. Spring AOP原理: - Spring AOP是基于动态代理实现的,它可以在不修改原有代码的情况下,为方法添加日志、事务管理等横切关注点。Spring支持两种类型的代理:JDK动态代理和CGLIB代理。 - JDK动态代理适用于目标...

    spring ioc和aop原理流程图(详细)

    Spring 框架是Java开发中的核心框架,它主要由两个关键部分组成:IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)。这两个概念是Spring框架的核心特性,极大地简化了企业...

    Spring AOP实现机制

    **Spring AOP 实现机制详解** Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的...

    SpringAOP原理及拦截器.pdf

    Spring AOP是Spring框架的重要组成部分,它允许开发者在不修改原有代码的情况下,插入额外的功能。 在Spring AOP中,以下几个核心概念至关重要: 1. **方面(Aspect)**:方面是关注点的模块化,比如事务管理就是...

    SpringAOP原理及拦截器.doc

    Spring AOP,全称为Spring的面向切面编程,是一种编程范式,旨在将核心业务逻辑与横切关注点(如事务管理、日志记录、安全控制...通过熟练掌握AOP的原理和实践,开发者能够更高效地构建模块化的、松散耦合的软件系统。

    SpringAOP原理及拦截器.docx

    Spring AOP,全称为面向方面的编程,是一种编程范式,旨在解决传统面向对象编程中横切关注点(如事务管理、日志记录等)分散在各个类中的问题,从而提高代码的可读性和可维护性。Spring框架是AOP技术的一个重要实现...

    Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现.doc

    Spring AOP 实现原理详解之 AOP 切面的实现 Spring AOP 是基于 IOC 的 Bean 加载来实现的,本文主要介绍 Spring AOP 原理解析的切面实现过程。AOP 切面的实现是将切面类的所有切面方法根据使用的注解生成对应 ...

    简单spring aop 例子

    本示例将简要介绍如何在Spring应用中实现AOP,通过实际的代码示例帮助理解其工作原理。 首先,我们要理解AOP的核心概念。AOP是一种编程范式,它允许开发者定义“切面”(Aspects),这些切面封装了特定的关注点,如...

    Spring AOP 原理剖析,这一篇就够

    Spring AOP 学习记录 AOP(面向切面编程)方面的知识又是看了忘忘了看,今天有空记录下AOP的知识点。主要分为以下几方面: ​ 1、AOP相关术语 ​ 2、基础知识及示例 ​ 3、增强分类 1、AOP相关术语 连接点...

    模拟spring aop技术

    同时,这也是理解Spring AOP原理和实践的一个重要步骤。 总之,Spring AOP通过模拟真实世界的切面编程,使得我们可以更优雅地处理系统中的通用功能,如日志记录、性能监控、事务管理等,从而降低代码的复杂度,提高...

    死磕Spring之AOP篇 - Spring AOP两种代理对象的拦截处理(csdn)————程序.pdf

    在深入理解 Spring AOP 的源码时,需要熟悉 Spring IoC 的工作原理,以及 AOP 相关的概念,如切点表达式、通知类型等。了解这些基础知识可以帮助我们更好地掌握 Spring AOP 的实现细节。在分析源码时,可以参考作者...

    spring aop 自定义注解保存操作日志到mysql数据库 源码

    一、适合人群 1、具备一定Java编程基础,初级开发者 ...(需要知道原理的请看spring aop源码,此处不做赘述) 3、可在现有源码上快速进行功能扩展 4、spring boot,mybatis,druid,spring aop的使用

    JDK动态代理 spring aop 的原理

    现在让我们深入探讨JDK动态代理和Spring AOP的原理。 首先,JDK动态代理基于Java的反射机制,通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类用于创建一个代理对象,...

    实验2 Spring AOP源码

    1、 理解Spring AOP原理和基本概念; 2、掌握基于XML/注解方式的AOP编程; 二:实验内容 1、 定义交易接口: public interface Transaction{ public void income(float amount);//收入 public void expenditure...

Global site tag (gtag.js) - Google Analytics