Spring AOP详解-动态代理源码分析

Spring AOP详解

  • 图解Spring AOP基础概念
    • 1、Spring AOP 是通过动态代理技术实现
      • 1.1 JDK动态代理
      • 1.2 CGLib动态代理
    • 2、Spring AOP 动态代理"增强"织入的时机
      • 2.1 Spring AOP在对目标对象方法织入是在什么时候发生的呢?在编译器?在运行时?
      • 2.2 Spring AOP 中,什么时候为原生对象生成代理对象?

图解Spring AOP基础概念

Spring AOP详解-动态代理源码分析_第1张图片

1、Spring AOP 是通过动态代理技术实现

Spring AOP 只是一个编程思想,切面编程。而实现"切面编程"是通过动态代理技术实现。动态代理技术目前常用的是JDK动态代理、CGlib动态代理技术。这两种动态代理技术的原理不一样。

1.1 JDK动态代理

JDK动态代理,是通过JDK原生的Proxy类实现。若是一个目标对象实现了接口,则Spring AOP默认使用JDK动态代理。如下图所示:Spring AOP 的JDK代理,是通过Proxy实现。

  • 1:要代理的目标 object至少 实现一个接口,则将使用 JDK 动态代理。目标类型实现的所有接口都将被代理。
    被代理所有实现接口的的方法,但并不是每个方法都会被"增强",这就需要看"切点“的"连接点"配置了
@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
public class MyAspect {
   private int someState;
   @Before(com.xyz.myapp.SystemArchitecture.businessService())
   //只有SystemArchitecture接口下的businessService()方法才会被 @Before"增强",而其他方法只是被代理,
   //并没有增强
   public void recordServiceUsage() {
       // ...
   }
}
  • 2:Spring AOP 底层使用JDK动态代理:
    Spring AOP详解-动态代理源码分析_第2张图片
  • 3:JDK动态代理类源码:
//接口
public interface Manager {
  public void modify();
}

//动态代理类源码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//被代理类实现的接口Manager
public final class $Proxy0 extends Proxy implements Manager {
    private static Method m1;
    private static Method m0;
    private static Method m3;
    private static Method m2;
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals",
                new Class[] {
                    Class.forName("java.lang.Object")
                });
            m0 = Class.forName("java.lang.Object").getMethod("hashCode",
                new Class[0]);
           //被代理类实现接口的方法
            m3 = Class.forName("com.ml.test.Manager").getMethod("modify",
                new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString",
                new Class[0]);
        } catch (NoSuchMethodException nosuchmethodexception) {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        } catch (ClassNotFoundException classnotfoundexception) {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
    
   //代理类的构造函数
    public $Proxy0(InvocationHandler invocationhandler) {
        super(invocationhandler);
    }

    @Override
    public final boolean equals(Object obj) {
        try {
            return ((Boolean) super.h.invoke(this, m1, new Object[] {
                    obj
                }))
                .booleanValue();
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    @Override
    public final int hashCode() {
        try {
            return ((Integer) super.h.invoke(this, m0, null)).intValue();
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
    
    //代理类通过字节码生成的,实现接口方法同样的方法
    public final void modify() {
        try {
            ...这里可以加入"前置通知"...
            //执行被代理类的方法
            //从这里就可以看到,最终调用的还是目标对象实现Manager接口的方法。
            super.h.invoke(this, m3, null);
            ...这里可以加入"后置通知"...
            ...这里可以加入"返回通知"...
            return;
        } catch (Error e) {} catch (Throwable throwable) {
            ...这里可以加入"执行错误通知"...
            throw new UndeclaredThrowableException(throwable);
        }finally{
           ...这里可以加入"finally通知"...
       }
    }

    @Override
    public final String toString() {
        try {
            return (String) super.h.invoke(this, m2, null);
        } catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

1.2 CGLib动态代理

  • 1:如果目标 object 没有实现任何接口,那么将创建 CGLIB 代理。
  • 2:若是强制使用CGlib动态代理:
    ①、配置方式:Spring 配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
    ②、注解方式:@EnableAspectJAutoProxy(proxyTargetClass = ture)
  • 3:Cglib动态代理目标对象源码:
package com.zhang.shine.cache;

import java.lang.reflect.Method;
import java.util.Map;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Dispatcher;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;

//Sev是目标对象类,从这里可以看出,gclib是通过继承目标对象类的方式实现动态代理
public class Sev$$EnhancerByCGLIB$$e8033e73 extends Sev
implements SpringProxy, Advised, Factory {
   private boolean CGLIB$BOUND;
   private boolean CGLIB$CONSTRUCTED;
   private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
   private static final Callback[] CGLIB$STATIC_CALLBACKS;
   private MethodInterceptor CGLIB$CALLBACK_0;
   private MethodInterceptor CGLIB$CALLBACK_1;
   private NoOp CGLIB$CALLBACK_2;
   private Dispatcher CGLIB$CALLBACK_3;
   private Dispatcher CGLIB$CALLBACK_4;
   private MethodInterceptor CGLIB$CALLBACK_5;
   private MethodInterceptor CGLIB$CALLBACK_6;
   private static final Method CGLIB$getSort$0$Method;
   private static final MethodProxy CGLIB$getSort$0$Proxy;
   private static final Object[] CGLIB$emptyArgs;
   private static final Method CGLIB$getSort$1$Method;
   private static final MethodProxy CGLIB$getSort$1$Proxy;
   private static final Method CGLIB$hashCode$3$Method;
   private static final MethodProxy CGLIB$hashCode$3$Proxy;
   private static final Method CGLIB$clone$4$Method;
   private static final MethodProxy CGLIB$clone$4$Proxy;
   private static final Method CGLIB$equals$5$Method;
   private static final MethodProxy CGLIB$equals$5$Proxy;
   private static final Method CGLIB$toString$6$Method;
   private static final MethodProxy CGLIB$toString$6$Proxy;

   static void CGLIB$STATICHOOK1() {

       CGLIB$THREAD_CALLBACKS = new ThreadLocal();
       Class localClass;
       CGLIB$emptyArgs = new Object[0];
       ClassLoader tmp27_17 = (localClass = Class.forName("com.zhang.shine.cache.Sev$$EnhancerByCGLIB$$e8033e73")).getClassLoader();

       CGLIB$getSort$0$Proxy = MethodProxy.create(tmp27_17, (e8033e73.CGLIB$getSort$0$Method = Class.forName(
           "com.zhang.shine.cache.Sev").getDeclaredMethod("getSort", new Class[] {
           Integer.TYPE, Integer.TYPE
       })).getDeclaringClass(), localClass, "(II)Ljava/util/Map;", "getSort", "CGLIB$getSort$0");

       ClassLoader tmp74_27 = tmp27_17;
       CGLIB$getSort$1$Proxy = MethodProxy.create(tmp74_27, (e8033e73.CGLIB$getSort$1$Method = Class.forName(
               "com.zhang.shine.cache.Sev").getDeclaredMethod("getSort", new Class[0])).getDeclaringClass(),
           localClass, "()V", "getSort", "CGLIB$getSort$1");

       ClassLoader tmp109_74 = tmp74_27;
       CGLIB$hashCode$3$Proxy = MethodProxy.create(tmp109_74, (e8033e73.CGLIB$hashCode$3$Method = Class.forName(
               "java.lang.Object").getDeclaredMethod("hashCode", new Class[0])).getDeclaringClass(),
           localClass, "()I", "hashCode", "CGLIB$hashCode$3");

       ClassLoader tmp144_109 = tmp109_74;
       CGLIB$clone$4$Proxy = MethodProxy.create(tmp144_109, (e8033e73.CGLIB$clone$4$Method = Class.forName(
               "java.lang.Object").getDeclaredMethod("clone", new Class[0])).getDeclaringClass(), localClass,
           "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");

       ClassLoader tmp179_144 = tmp144_109;
       CGLIB$equals$5$Proxy = MethodProxy.create(tmp179_144, (e8033e73.CGLIB$equals$5$Method = Class.forName(
           "java.lang.Object").getDeclaredMethod("equals", new Class[] {
           Class.forName("java.lang.Object")
       })).getDeclaringClass(), localClass, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$5");

       CGLIB$toString$6$Proxy = MethodProxy.create(tmp179_144, (e8033e73.CGLIB$toString$6$Method = Class.forName(
               "java.lang.Object").getDeclaredMethod("toString", new Class[0])).getDeclaringClass(),
           localClass, "()Ljava/lang/String;", "toString", "CGLIB$toString$6");

       return;
   }
  
   final Map CGLIB$getSort$0(int paramInt1, int paramInt2) {
       //在代理对象中直接调用父类(目标对象)的方法
       return super.getSort(paramInt1, paramInt2);
   }

2、Spring AOP 动态代理"增强"织入的时机

2.1 Spring AOP在对目标对象方法织入是在什么时候发生的呢?在编译器?在运行时?

通过分析动态代理原理和Spring AOP相关源码,可以知道不管是JDK动态代理,还是CGlib动态代理都是在运行时对目标对象进行织入。
1、JDK、Cglib都是通过动态生成xxx.class文件的形式完成对目标对象的代理。
2、Spring AOP是需要与Spring IOC配合使用,在Spring IOC中需要先解析、生成原始的目标对象Bean,在生成Bean对象时,IOC的后置处理器会更具Bean是否被代理,为其生成代理对象。

2.2 Spring AOP 中,什么时候为原生对象生成代理对象?

1、通过Spring AOP是需要与Spring IOC配合使用,在Spring IOC中需要先解析、生成原始的目标对象Bean,在生成Bean对象时,IOC的后置处理器会更具Bean是否被代理,为其生成代理对象。 可以了解到是在Bean初始化时期为其生成动态代理对象。而放入IOC中的也是动态代理对象,原生对象并没有放入IOC容器中。
2、后续通过getBean()获取的Bean都是代理对象。

你可能感兴趣的:(Java编程)