为什么放一起呢,其实他们核心的问题都是一样一样的,就是动态生成字节码。只要搞明白动态生成字节码,其它的就简单了。这也会涉及到类加载,方法区这些知识。
什么是AOP,其本质就是我增强了我原来的代码。本来原来代码只能做A这个操作,我通过AOP,让他不单单做了A,还做了B和C。所以本质就是我在运行的时候改了原来的代码,在他上面加了其它东西。SPRING 的AOP很多人也都用过就不说了,我们就看看AOP的下层动态代理是如何实现的。
先看看动态代理吧。先看段代码,然后再看细节
接口
-
package sty.zchi.proxy;
-
-
public interface Person {
-
String sayHello();
-
}
接口实现
-
package sty.zchi.proxy;
-
-
public class PersonImpl implements Person {
-
@Override
-
public String sayHello() {
-
System.out.println("hello world");
-
return "hello world";
-
}
-
}
代理类
-
package sty.zchi.proxy;
-
-
import java.lang.reflect.InvocationHandler;
-
import java.lang.reflect.Method;
-
-
public class LogHandler implements InvocationHandler {
-
private Object target;
-
-
public LogHandler(Object target) {
-
this.target = target;
-
}
-
@Override
-
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-
System.out.println("before excute");
-
Object result = method.invoke(target, args);
-
return result;
-
}
-
}
主类
-
package sty.zchi.proxy;
-
-
import java.lang.reflect.Proxy;
-
-
public class MainTest {
-
public static void main(String args[]) {
-
Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),
-
new Class[]{Person.class}, new LogHandler(new PersonImpl()));
-
person.sayHello();
-
}
-
}
其实很多人应该都会了,我觉得也没什么好讲的,直接讲这个玩意的本质,然后我们再看看代码。
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)这个代码的就知道我说的是什么?加完后,跑一次,你就会发现字节码被保存到文件里面了。然后我们反编译看一下代码
-
//
-
// Source code recreated from a .class file by IntelliJ IDEA
-
// (powered by FernFlower decompiler)
-
//
-
-
package com.sun.proxy;
-
-
import java.lang.reflect.InvocationHandler;
-
import java.lang.reflect.Method;
-
import java.lang.reflect.Proxy;
-
import java.lang.reflect.UndeclaredThrowableException;
-
import sty.zchi.proxy.Person;
-
-
public final class $Proxy0 extends Proxy implements Person {
-
private static Method m1;
-
private static Method m3;
-
private static Method m2;
-
private static Method m0;
-
-
public $Proxy0(InvocationHandler var1) throws {
-
super(var1);
-
}
-
-
public final boolean equals(Object var1) throws {
-
try {
-
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
-
} catch (RuntimeException | Error var3) {
-
throw var3;
-
} catch (Throwable var4) {
-
throw new UndeclaredThrowableException(var4);
-
}
-
}
-
-
public final String sayHello() throws {
-
try {
-
return (String)super.h.invoke(this, m3, (Object[])null);
-
} catch (RuntimeException | Error var2) {
-
throw var2;
-
} catch (Throwable var3) {
-
throw new UndeclaredThrowableException(var3);
-
}
-
}
-
-
public final String toString() throws {
-
try {
-
return (String)super.h.invoke(this, m2, (Object[])null);
-
} catch (RuntimeException | Error var2) {
-
throw var2;
-
} catch (Throwable var3) {
-
throw new UndeclaredThrowableException(var3);
-
}
-
}
-
-
public final int hashCode() throws {
-
try {
-
return (Integer)super.h.invoke(this, m0, (Object[])null);
-
} catch (RuntimeException | Error var2) {
-
throw var2;
-
} catch (Throwable var3) {
-
throw new UndeclaredThrowableException(var3);
-
}
-
}
-
-
static {
-
try {
-
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
-
m3 = Class.forName("sty.zchi.proxy.Person").getMethod("sayHello");
-
m2 = Class.forName("java.lang.Object").getMethod("toString");
-
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
-
} catch (NoSuchMethodException var2) {
-
throw new NoSuchMethodError(var2.getMessage());
-
} catch (ClassNotFoundException var3) {
-
throw new NoClassDefFoundError(var3.getMessage());
-
}
-
}
-
}
好吧,一看就应该很清楚明白了。
阅读(3302) | 评论(0) | 转发(0) |