1 Star 2 Fork 4

kater / 彻底搞懂Spring AOP

加入 Gitee
与超过 800 万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README.md

彻底搞懂Spring AOP

本项目旨在从AOP生成的class文件入手,完全搞懂AOP(以常规的cglib为基础)。

目的

对于AOP一直的观点都是AOP是动态修改class字节码, 但到底生成了什么样的代码, 仍然是雾里看花, 让我们保存动态生成的class文件到磁盘一探究竟.

运行

运行ProxyFactoryTest的Junit,即可看到生成的class文件(通过两种方式生成,生成的内容一致)

文件一:org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$b6871ed4.class
文件二:gen.class/.....

实现步骤

STEP.0 以如下类作为需要代理的类(TableDao.java)

/// Before表示拦截器栈(不需要关注如何实现的)
@Before(value={LogInterceptor.class, AuthInterceptor.class})
public class TableDao {
    public void create(){
        System.out.println("create() is running...");
    }
    public void delete(){
        System.out.println("delete() is running...");
    }
    public void update(){
        System.out.println("update() is running...");
    }
    
    @Clear(value=AuthInterceptor.class)
    public void query(){
        System.out.println("query() is running...");
    }
}

STEP.1 如何搞到生成的class文件

方法1.(ProxyFactory.java)利用cglib的增强API 即可获得class的字节码, 通过文件流保存即可(保存在工程根目录:org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$b6871ed4.class).

byte[] bytes = Enhancer.getStrategy().generate(en) 

方法2. (ProxyFactoryTest.java)利用cglib提供的保存生成的字节码参数(保存在gen.class目录下):

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "gen.class");

STEP.2 如何看懂生成的class字节码

生成的class文件不一定能通过一般的反编译工具打开(反编译成功的可能不准确),原因未知, 但是我们可以通过eclipse的class字节码解析工具,获得如下结果(重点关注其中一个void create方法,删除一些干扰项):

// Compiled from <generated> (version 1.2 : 46.0, no super bit)
/// **类继承自TableDao,即代理类,这就是为什么能强转为代理类直接使用的原因**
public class org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f extends org.smvc.test.aop.TableDao implements net.sf.cglib.proxy.Factory {
  
  // Field descriptor #9 Z
  private boolean CGLIB$BOUND;
  
  // Field descriptor #11 Ljava/lang/ThreadLocal;
  private static final java.lang.ThreadLocal CGLIB$THREAD_CALLBACKS;
  
  // Field descriptor #13 [Lnet/sf/cglib/proxy/Callback;
  private static final net.sf.cglib.proxy.Callback[] CGLIB$STATIC_CALLBACKS;
  
  // **这里就是我们通过Enhance设定进去的拦截器栈**
  // Field descriptor #15 Lnet/sf/cglib/proxy/MethodInterceptor;
  private net.sf.cglib.proxy.MethodInterceptor CGLIB$CALLBACK_0;
  
  // Field descriptor #26 Ljava/lang/reflect/Method;
  private static final java.lang.reflect.Method CGLIB$create$0$Method;
  
  // Field descriptor #28 Lnet/sf/cglib/proxy/MethodProxy;
  private static final net.sf.cglib.proxy.MethodProxy CGLIB$create$0$Proxy;
  

  
  // Method descriptor #17 ()V
  // Stack: 1, Locals: 1
  final void CGLIB$create$0();
    0  aload_0 [this]
    1  invokespecial org.smvc.test.aop.TableDao.create() : void [34]
    4  return

  
  // Method descriptor #17 ()V
  // Stack: 5, Locals: 1
  /// 代理类的create方法
  public final void create();
     0  aload_0 [this]
     /// **先获取拦截器栈**
     1  getfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$CALLBACK_0 : net.sf.cglib.proxy.MethodInterceptor [36]
     4  dup
     /// **如果拦截器栈不为空**
     5  ifnonnull 17
     8  pop
     9  aload_0 [this]
    10  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$BIND_CALLBACKS(java.lang.Object) : void [40]
    13  aload_0 [this]
    /// **绑定参数,准备调用拦截器栈**
    14  getfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$CALLBACK_0 : net.sf.cglib.proxy.MethodInterceptor [36]
    17  dup
    18  ifnull 37
    21  aload_0 [this]
    22  getstatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$create$0$Method : java.lang.reflect.Method [42]
    25  getstatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$emptyArgs : java.lang.Object[] [44]
    28  getstatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$create$0$Proxy : net.sf.cglib.proxy.MethodProxy [46]
    /// **准备好参数,正好能和Callback类的intercept方法四个参数对应上,调用拦截器栈**
    31  invokeinterface net.sf.cglib.proxy.MethodInterceptor.intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.proxy.MethodProxy) : java.lang.Object [52] [nargs: 5]
    36  return
    /// **否则拦截器栈为空,则直接调用被代理类的真实方法**
    37  aload_0 [this]
    38  invokespecial org.smvc.test.aop.TableDao.create() : void [34]
    41  return

 
  
  // Method descriptor #231 ([Lnet/sf/cglib/proxy/Callback;)V
  // Stack: 1, Locals: 1
  public static void CGLIB$SET_STATIC_CALLBACKS(net.sf.cglib.proxy.Callback[] arg0);
    0  aload_0 [arg0]
    1  putstatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$STATIC_CALLBACKS : net.sf.cglib.proxy.Callback[] [237]
    4  return

  
  // Method descriptor #38 (Ljava/lang/Object;)V
  // Stack: 3, Locals: 2
  private static final void CGLIB$BIND_CALLBACKS(java.lang.Object arg0);
     0  aload_0 [arg0]
     1  checkcast org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f [2]
     4  astore_1
     5  aload_1
     6  getfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$BOUND : boolean [239]
     9  ifne 52
    12  aload_1
    13  iconst_1
    14  putfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$BOUND : boolean [239]
    17  getstatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$THREAD_CALLBACKS : java.lang.ThreadLocal [24]
    20  invokevirtual java.lang.ThreadLocal.get() : java.lang.Object [242]
    23  dup
    24  ifnonnull 39
    27  pop
    28  getstatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$STATIC_CALLBACKS : net.sf.cglib.proxy.Callback[] [237]
    31  dup
    32  ifnonnull 39
    35  pop
    36  goto 52
    39  checkcast net.sf.cglib.proxy.Callback[] [243]
    42  aload_1
    43  swap
    44  iconst_0
    45  aaload
    46  checkcast net.sf.cglib.proxy.MethodInterceptor [48]
    49  putfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$CALLBACK_0 : net.sf.cglib.proxy.MethodInterceptor [36]
    52  return

  
  // Method descriptor #245 ([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;
  // Stack: 2, Locals: 2
  public java.lang.Object newInstance(net.sf.cglib.proxy.Callback[] arg0);
     0  aload_1 [arg0]
     1  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[]) : void [247]
     4  new org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f [2]
     7  dup
     8  invokespecial org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f() [248]
    11  aconst_null
    12  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[]) : void [247]
    15  areturn

  
  // Method descriptor #249 (Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;
  // Stack: 4, Locals: 2
  public java.lang.Object newInstance(net.sf.cglib.proxy.Callback arg0);
     0  iconst_1
     1  anewarray net.sf.cglib.proxy.Callback [251]
     4  dup
     5  iconst_0
     6  aload_1 [arg0]
     7  aastore
     8  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[]) : void [247]
    11  new org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f [2]
    14  dup
    15  invokespecial org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f() [248]
    18  aconst_null
    19  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[]) : void [247]
    22  areturn

  
  // Method descriptor #252 ([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;
  // Stack: 5, Locals: 4
  public java.lang.Object newInstance(java.lang.Class[] arg0, java.lang.Object[] arg1, net.sf.cglib.proxy.Callback[] arg2);
     0  aload_3 [arg2]
     1  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[]) : void [247]
     4  new org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f [2]
     7  dup
     8  aload_1 [arg0]
     9  dup
    10  arraylength
    11  tableswitch default: 35
          case 0: 28
    28  pop
    29  invokespecial org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f() [248]
    32  goto 50
    35  goto 38
    38  pop
    39  new java.lang.IllegalArgumentException [254]
    42  dup
    43  ldc_w <String "Constructor not found"> [256]
    46  invokespecial java.lang.IllegalArgumentException(java.lang.String) [259]
    49  athrow
    50  aconst_null
    51  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[]) : void [247]
    54  areturn

  
  // Method descriptor #261 (I)Lnet/sf/cglib/proxy/Callback;
  // Stack: 2, Locals: 2
  public net.sf.cglib.proxy.Callback getCallback(int arg0);
     0  aload_0 [this]
     1  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$BIND_CALLBACKS(java.lang.Object) : void [40]
     4  aload_0 [this]
     5  iload_1 [arg0]
     6  tableswitch default: 30
          case 0: 24
    24  getfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$CALLBACK_0 : net.sf.cglib.proxy.MethodInterceptor [36]
    27  goto 32
    30  pop
    31  aconst_null
    32  areturn

  
  // Method descriptor #263 (ILnet/sf/cglib/proxy/Callback;)V
  // Stack: 2, Locals: 3
  public void setCallback(int arg0, net.sf.cglib.proxy.Callback arg1);
     0  iload_1 [arg0]
     1  tableswitch default: 31
          case 0: 20
    20  aload_0 [this]
    21  aload_2 [arg1]
    22  checkcast net.sf.cglib.proxy.MethodInterceptor [48]
    25  putfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$CALLBACK_0 : net.sf.cglib.proxy.MethodInterceptor [36]
    28  goto 31
    31  return

  
  // Method descriptor #265 ()[Lnet/sf/cglib/proxy/Callback;
  // Stack: 5, Locals: 1
  public net.sf.cglib.proxy.Callback[] getCallbacks();
     0  aload_0 [this]
     1  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$BIND_CALLBACKS(java.lang.Object) : void [40]
     4  aload_0 [this]
     5  iconst_1
     6  anewarray net.sf.cglib.proxy.Callback [251]
     9  dup
    10  iconst_0
    11  aload_0 [this]
    12  getfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$CALLBACK_0 : net.sf.cglib.proxy.MethodInterceptor [36]
    15  aastore
    16  areturn

  
  // Method descriptor #231 ([Lnet/sf/cglib/proxy/Callback;)V
  // Stack: 5, Locals: 2
  public void setCallbacks(net.sf.cglib.proxy.Callback[] arg0);
     0  aload_0 [this]
     1  aload_1 [arg0]
     2  dup2
     3  iconst_0
     4  aaload
     5  checkcast net.sf.cglib.proxy.MethodInterceptor [48]
     8  putfield org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$CALLBACK_0 : net.sf.cglib.proxy.MethodInterceptor [36]
    11  return

  
  // Method descriptor #17 ()V
  // Stack: 0, Locals: 0
  static {};
    0  invokestatic org.smvc.test.aop.TableDao$$EnhancerByCGLIB$$d519990f.CGLIB$STATICHOOK2() : void [269]
    3  return

}

仓库评论 ( 0 )

你可以在登录后,发表评论

简介

本项目旨在从AOP生成的clas文件入手,完全搞懂AOP。 1、如何搞到生成的class文件 2、如何看懂生成的class字节码 展开 收起
Java
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/1028125449/Spring-AOP.git
git@gitee.com:1028125449/Spring-AOP.git
1028125449
Spring-AOP
彻底搞懂Spring AOP
master

搜索帮助

113223 674803ea 1850385 170725 2838fb2a 1850385