Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1390
  • 博文数量: 8
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 90
  • 用 户 组: 普通用户
  • 注册时间: 2023-07-18 09:31
文章分类

全部博文(8)

文章存档

2023年(8)

我的朋友
最近访客

分类: Java

2023-07-21 16:24:05

为什么放一起呢,其实他们核心的问题都是一样一样的,就是动态生成字节码。只要搞明白动态生成字节码,其它的就简单了。这也会涉及到类加载,方法区这些知识。

什么是AOP,其本质就是我增强了我原来的代码。本来原来代码只能做A这个操作,我通过AOP,让他不单单做了A,还做了B和C。所以本质就是我在运行的时候改了原来的代码,在他上面加了其它东西。SPRING 的AOP很多人也都用过就不说了,我们就看看AOP的下层动态代理是如何实现的。

先看看动态代理吧。先看段代码,然后再看细节

接口

点击(此处)折叠或打开

  1. package sty.zchi.proxy;

  2. public interface Person {
  3.     String sayHello();
  4. }
接口实现

点击(此处)折叠或打开

  1. package sty.zchi.proxy;

  2. public class PersonImpl implements Person {
  3.     @Override
  4.     public String sayHello() {
  5.         System.out.println("hello world");
  6.         return "hello world";
  7.     }
  8. }
代理类

点击(此处)折叠或打开

  1. package sty.zchi.proxy;

  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;

  4. public class LogHandler implements InvocationHandler {
  5.     private Object target;

  6.     public LogHandler(Object target) {
  7.         this.target = target;
  8.     }
  9.     @Override
  10.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  11.         System.out.println("before excute");
  12.         Object result = method.invoke(target, args);
  13.         return result;
  14.     }
  15. }
主类

点击(此处)折叠或打开

  1. package sty.zchi.proxy;

  2. import java.lang.reflect.Proxy;

  3. public class MainTest {
  4.     public static void main(String args[]) {
  5.         Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),
  6.                 new Class[]{Person.class}, new LogHandler(new PersonImpl()));
  7.         person.sayHello();
  8.     }
  9. }
其实很多人应该都会了,我觉得也没什么好讲的,直接讲这个玩意的本质,然后我们再看看代码。

JAVA里面的类其实都是类加载器将类定义加载到JVM的方法区(但JDK并没有说明这个类定义可以从哪儿拿,你可以从文件上拿,比如我们各种.class字节码文件,你也可以从网络上读取类定义,甚至,你可以自己在程序里面写字节码,然后让CLASSLOADER把他放到JVM的方法区)。这其实就是本质。

好吧看看代码里面代码一大堆,核心看看Proxy.newProxyInstance到底是干了啥。

1.它调用sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class[], int)方法,生成了代理类的字节码。其中{BANNED}中国{BANNED}中国第一个是类名,这个类名一般是自动生成类似于com.sum.proxy.$Proxy0 。第二个是这个代理类要实现的接口。第三个不太懂,熟悉的同学可以在评论去留言讲讲,我也学习下。
2.字节码生成好以后就调用 java.lang.reflect.Proxy#defineClass0 一个native方法,将字节码加载到方法区,这样一个代理类就完成了。

好了代理类的怎么被制造出来基本明白了,那么接下来为什么对代理类的sayHello调用,为什么会调用到sty.zchi.proxy.LogHandler#invoke上呢?说好的方法签名呢?这玩意其实说白了,你只要把他生成的代理类的字节码反编译后就看懂了。

在前面的主类上加上System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 如果看过sun.misc.ProxyGenerator#generateProxyClass(java.lang.String, java.lang.Class[], int)这个代码的就知道我说的是什么?加完后,跑一次,你就会发现字节码被保存到文件里面了。然后我们反编译看一下代码

点击(此处)折叠或打开

  1. //
  2. // Source code recreated from a .class file by IntelliJ IDEA
  3. // (powered by FernFlower decompiler)
  4. //

  5. package com.sun.proxy;

  6. import java.lang.reflect.InvocationHandler;
  7. import java.lang.reflect.Method;
  8. import java.lang.reflect.Proxy;
  9. import java.lang.reflect.UndeclaredThrowableException;
  10. import sty.zchi.proxy.Person;

  11. public final class $Proxy0 extends Proxy implements Person {
  12.     private static Method m1;
  13.     private static Method m3;
  14.     private static Method m2;
  15.     private static Method m0;

  16.     public $Proxy0(InvocationHandler var1) throws {
  17.         super(var1);
  18.     }

  19.     public final boolean equals(Object var1) throws {
  20.         try {
  21.             return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
  22.         } catch (RuntimeException | Error var3) {
  23.             throw var3;
  24.         } catch (Throwable var4) {
  25.             throw new UndeclaredThrowableException(var4);
  26.         }
  27.     }

  28.     public final String sayHello() throws {
  29.         try {
  30.             return (String)super.h.invoke(this, m3, (Object[])null);
  31.         } catch (RuntimeException | Error var2) {
  32.             throw var2;
  33.         } catch (Throwable var3) {
  34.             throw new UndeclaredThrowableException(var3);
  35.         }
  36.     }

  37.     public final String toString() throws {
  38.         try {
  39.             return (String)super.h.invoke(this, m2, (Object[])null);
  40.         } catch (RuntimeException | Error var2) {
  41.             throw var2;
  42.         } catch (Throwable var3) {
  43.             throw new UndeclaredThrowableException(var3);
  44.         }
  45.     }

  46.     public final int hashCode() throws {
  47.         try {
  48.             return (Integer)super.h.invoke(this, m0, (Object[])null);
  49.         } catch (RuntimeException | Error var2) {
  50.             throw var2;
  51.         } catch (Throwable var3) {
  52.             throw new UndeclaredThrowableException(var3);
  53.         }
  54.     }

  55.     static {
  56.         try {
  57.             m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
  58.             m3 = Class.forName("sty.zchi.proxy.Person").getMethod("sayHello");
  59.             m2 = Class.forName("java.lang.Object").getMethod("toString");
  60.             m0 = Class.forName("java.lang.Object").getMethod("hashCode");
  61.         } catch (NoSuchMethodException var2) {
  62.             throw new NoSuchMethodError(var2.getMessage());
  63.         } catch (ClassNotFoundException var3) {
  64.             throw new NoClassDefFoundError(var3.getMessage());
  65.         }
  66.     }
  67. }
好吧,一看就应该很清楚明白了。

阅读(1099) | 评论(0) | 转发(0) |
0

上一篇:java NiO

下一篇:线程池

给主人留下些什么吧!~~