一:前提
Spring中最重要的两种思想:控制反转IOC(Inversion of Control)和面向切面编程AOP(Aspect-Oriented Programming),而AOP最重要的原理就是动态代理,今天我们谈一下动态代理。动态代理顾名思义是代替别人做某些事,它自己不干,让代理帮他做。别的不多说,直接上代码(举的例子可能不恰当)!
二:基于JDK的动态代理
1:因为Java的动态代理是基于接口的,所以先定义一个顶级接口Person
package dynamicProxy.jdkDynamic;
/**
* 顶级接口
*/
public interface Person {
public void speak();
}
2:写一个Person的实现类GuangDongPerson
package dynamicProxy.jdkDynamic;
/**
* 实现类
* */
public class GuangDongPerson implements Person {
@Override
public void speak() {
System.out.println("我说的是~¥#~&~#");
}
}
3:找一个翻译作为代理类,进行翻译普通话。
package dynamicProxy.jdkDynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Translation implements InvocationHandler {
private Person target;
public Translation(Person target) {
this.target = target;
}
public static Object getInstance(Person target){
Class<? extends Person> clazz = target.getClass();
System.out.println(clazz.getName());
Object poxy = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new Translation(target));
System.out.println(poxy.getClass().getName());
return poxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是翻译,你说话我翻译,请说话!");
Object invoke = method.invoke(target,args);
System.out.println("他说的是xxxxxxxxxx");
return invoke;
}
}
说明:
1:Proxy.newInstance()方法
* 第一个参数为目标类的类加载器
* 第二个参数为目标类的接口集合,JDK动态代理目标类必须实现一个接口,这是为了保证生成的代理类和目标类之前的强一致性关系
* 第三个参数为InvocationHandler接口的实现类,这里直接通过匿名内部类实现,重写了invoke方法
2:InvocationHandler接口实现类
* 实现该类必须重写invoke()方法,动态代理实现在代理类中该接口的实现类调用该方法,并在该方法中反射执行该方法完成整个动态代理流程;
* 第一个参数为生成的动态代理对象;
* 第二个参数为动态代理在客户端执行的方法;
* 第三个参数为该方法的参数列表;
* 通过反射来完成方法调用;
4:测试类
package dynamicProxy.jdkDynamic;
import dynamicProxy.jdkDynamic.custom.TLGuangDongPerson;
import dynamicProxy.jdkDynamic.custom.TLPerson;
import dynamicProxy.jdkDynamic.custom.TLTranslation;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws Exception{
Person translationInstance = (Person)Translation.getInstance(new GuangDongPerson());
translationInstance.speak();
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
FileOutputStream outputStream = new FileOutputStream("E:\\$Proxy0.class");
outputStream.write(bytes);
outputStream.close();
// TLPerson translationInstance = (TLPerson)TLTranslation.getInstance(new TLGuangDongPerson());
// translationInstance.speak();
//
// byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
// FileOutputStream outputStream = new FileOutputStream("E:\\$Proxy0.class");
// outputStream.write(bytes);
// outputStream.close();
}
}
5:测试结果
dynamicProxy.jdkDynamic.Test
//未被代理之前的类
dynamicProxy.jdkDynamic.GuangDongPerson
//代理之后的类
com.sun.proxy.$Proxy0
我是翻译,你说话我翻译,请说话!
我说的是~¥#~&~#
他说的是xxxxxxxxxx
Process finished with exit code 0
注:看到上面的输出,可以很明显的看代理之后的类编程了$Proxy0,下面是此类的反编译结果
import dynamicProxy.jdkDynamic.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m2;
private static Method m3;
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 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 void speak() throws {
try {
super.h.invoke(this, m3, (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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("dynamicProxy.jdkDynamic.Person").getMethod("speak");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
总结:Java动态代理使用反射机制进行代理,可以看到该虚拟类继承Proxy类并实现了目标类顶层接口,并反射获取了目标类中的所有方法的Method对象,同时,虚拟类也同时重写了目标类的所有方法,并通过super.h.invoke(this, m3, (Object[])null)的方式进行调用。
三:手写实现JDK动态代理
步骤:
1:TLPerson类,定义newInstance()方法,进行代理对象创建
- 在该方法中首先需要输出代理类的.java文件
- 编译该.java文件生成.class文件
- 通过类加载器加载该.class文件
- 生成该.class文件的事例对象作为代理对象返回
2:TLInvocationHandler接口,定义invoke()方法,在代理类中进行目标方法调用
- 在.java文件中,定义构造器,传递该类引用
- 通过SelfInvocationHandler实现类对象调用invoke()方法,实现代理方式的方法调用
3:TLClassLoader,自定义类加载器,继承JDK的ClassLoader类,实现自定义的加载方式
具体操作:
1:创建顶级接口
package dynamicProxy.jdkDynamic.custom;
public interface TLPerson {
public void speak();
}
2:创建实现类
package dynamicProxy.jdkDynamic.custom;
public class TLGuangDongPerson implements TLPerson{
@Override
public void speak() {
System.out.println("我说的是~¥#~&~#");
}
}
3:使用自己的TLClassLoader代替JDK的ClassLoader,重写findClass(String name)方法。
package dynamicProxy.jdkDynamic.custom;
import dynamicProxy.custom.SelfClassLoader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
public class TLClassLoader extends ClassLoader {
private File classPathFile;
public TLClassLoader() {
String classPath = TLClassLoader.class.getResource("").getPath();
this.classPathFile = new File(classPath);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = TLClassLoader.class.getPackage().getName() + "." + name;
if (null != classPathFile) {
File classFile = new File(classPathFile, name + ".class");
if (classFile.exists()) {
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
return defineClass(className, out.toByteArray(), 0, out.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != in) {
in.close();
}
if (null != out) {
out.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return null;
}
}
4:使用自己的TLInvocationHandler代替JDK的InvocationHandler,重写invoke(Object proxy, Method method, Object[] args)方法。
package dynamicProxy.jdkDynamic.custom;
import java.lang.reflect.Method;
public interface TLInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
5:使用自己的TLProxy代替JDK的Proxy
package dynamicProxy.jdkDynamic.custom;
import com.sun.org.apache.regexp.internal.RE;
import dynamicProxy.custom.SelfInvocationHandler;
import dynamicProxy.custom.SelfProxy;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TLProxy {
private static final String LN = "\r\n";
public static Object newProxyInstance(TLClassLoader loader, Class<?>[] interfaces, TLInvocationHandler h) throws Exception {
// 动态生成源代码
String srcClass = generateSrc(interfaces);
// 输出Java文件
String filePath = TLProxy.class.getResource("").getPath() + "$ProxyO.java";
System.out.println(filePath);
FileWriter fileWriter = new FileWriter(filePath);
fileWriter.write(srcClass);
fileWriter.flush();
fileWriter.close();
// 编译Java文件为class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable iterable = fileManager.getJavaFileObjects(filePath);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, iterable);
task.call();
fileManager.close();
// 加载编译生成的class文件到JVM
Class<?> proxyClass = loader.findClass("$ProxyO");
Constructor<?> constructor = proxyClass.getConstructor(TLInvocationHandler.class);
// 删掉虚拟代理类
File file = new File(filePath);
file.delete();
// 返回字节码重组以后的代理对象
return constructor.newInstance(h);
}
private static String generateSrc(Class<?>[] interfaces) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("package dynamicProxy.jdkDynamic.custom;" + LN );
stringBuilder.append("import dynamicProxy.jdkDynamic.custom.TLPerson;" + LN);
stringBuilder.append("import java.lang.reflect.Method;" + LN);
stringBuilder.append("public class $ProxyO implements " + interfaces[0].getName() + "{" + LN);
stringBuilder.append("TLInvocationHandler h;" + LN);
stringBuilder.append("public $ProxyO(TLInvocationHandler h) {" + LN);
stringBuilder.append("this.h = h;" + LN);
stringBuilder.append("}" + LN);
for (Method method : interfaces[0].getMethods()) {
stringBuilder.append("public " + method.getReturnType().getName() + " " + method.getName() + "() {" + LN);
stringBuilder.append("try {" + LN);
stringBuilder.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\", new Class[]{});" + LN);
stringBuilder.append("this.h.invoke(this, m, null);" + LN);
stringBuilder.append("} catch(Throwable able) {" + LN);
stringBuilder.append("able.getMessage();" + LN);
stringBuilder.append("}" + LN);
stringBuilder.append("}" + LN );
}
stringBuilder.append("}" + LN);
return stringBuilder.toString();
}
}
6:创建手写翻译类
package dynamicProxy.jdkDynamic.custom;
import dynamicProxy.jdkDynamic.Translation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TLTranslation implements TLInvocationHandler {
private TLPerson target;
public TLTranslation(TLPerson target) {
this.target = target;
}
public static Object getInstance(TLPerson target) {
try {
Class<? extends TLPerson> clazz = target.getClass();
System.out.println(clazz.getName());
Object poxy = TLProxy.newProxyInstance(new TLClassLoader(), clazz.getInterfaces(), new TLTranslation(target));
System.out.println(poxy.getClass().getName());
return poxy;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println("我是翻译,你说话我翻译,请说话!");
Object invoke = method.invoke(target,args);
System.out.println("他说的是xxxxxxxxxx");
return invoke;
}
}
7:测试类
package dynamicProxy.jdkDynamic;
import dynamicProxy.jdkDynamic.custom.TLGuangDongPerson;
import dynamicProxy.jdkDynamic.custom.TLPerson;
import dynamicProxy.jdkDynamic.custom.TLTranslation;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class Test {
public static void main(String[] args) throws Exception{
// Person translationInstance = (Person)Translation.getInstance(new GuangDongPerson());
// translationInstance.speak();
//
// byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
// FileOutputStream outputStream = new FileOutputStream("E:\\$Proxy0.class");
// outputStream.write(bytes);
// outputStream.close();
TLPerson translationInstance = (TLPerson)TLTranslation.getInstance(new TLGuangDongPerson());
translationInstance.speak();
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});
FileOutputStream outputStream = new FileOutputStream("E:\\$Proxy0.class");
outputStream.write(bytes);
outputStream.close();
}
}
8:测试结果
dynamicProxy.jdkDynamic.custom.TLGuangDongPerson
/F:/project/TimeTest/target/classes/dynamicProxy/jdkDynamic/custom/$ProxyO.java
dynamicProxy.jdkDynamic.custom.$ProxyO
我是翻译,你说话我翻译,请说话!
我说的是~¥#~&~#
他说的是xxxxxxxxxx
Process finished with exit code 0
这仅是一个理解动态代理的思路,可能会给你一点启发,共同进步!