思路
先上一张图
对目标对象进行代理,本质其实是底层动态生成一个类加载到 jvm 中,该类将实现原目标对象的所有接口,重写所有方法,通过动态代理扩展功能,其实也可以理解为是通过重写扩展功能,下面就通过这个思路手写一个动态代理
实现
jdk动态生成代理对象步骤
- 创建目标对象
- 目标对象通过反射获取所有接口
- 动态生成Java源代码,实现所有接口
- 通过IO流生成Java文件
- 使用JavaCompiler类将Java文件编译成class文件
- 将生成的新类加载到jvm
- 获取该类构造器创建代理对象
MyInvocationHandler接口
package com.cml.proxy;
import java.lang.reflect.Method;
/**
* @author yys
* @version 1.0
*/
public interface MyInvocationHandler {
/**
* 该方法进行加强原方法,需要被实现
* @param proxy 生成的代理对象
* @param method 方法对象
* @param args 方法需要的参数
* @return 返回Method执行的返回结果
* @throws Throwable 抛出所有错误和异常
*/
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
MyClassLoader
package com.cml.proxy;
import java.io.*;
import java.util.Objects;
/**
* @author yys
* @version 1.0
*/
public class MyClassLoader extends ClassLoader{
private final File classPathFile;
public MyClassLoader(){
String classPath = Objects.requireNonNull(MyClassLoader.class.getResource("")).getPath();
this.classPathFile = new File(classPath);
}
/**
* 通过类名查找Class对象,必须重写,原方法默认抛出ClassNotFoundException异常
* @param name
* @return
*/
@Override
protected Class<?> findClass(String name) {
String className = MyClassLoader.class.getPackage().getName() + "." + name;
if(classPathFile != null){
File classFile = new File(classPathFile,name.replaceAll("\\.","/") + ".class");
if(classFile.exists()){
try {
//将class文件转为字节数组
byte[] bytes = file2ByteArray(classFile);
//将字节数组转为Class对象返回
return defineClass(className,bytes,0,bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* File对象转字节数组
* @param file
* @return
* @throws Exception
*/
private byte[] file2ByteArray(File file) throws Exception {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte [] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1){
out.write(buff,0,len);
}
return out.toByteArray();
}
}
MyProxy
package com.cml.proxy;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
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.Method;
import java.util.Objects;
/**
* @author yys
* @version 1.0
*/
public class MyProxy {
private static final String LN = "\r\n";
public static Object newProxyInstance(MyClassLoader classLoader, Class<?>[] interfaces, MyInvocationHandler h) {
try {
//1.动态生成java源代码,字符串拼接
String src = generateSrc(interfaces);
System.out.println(src);
//2.IO流生成java文件
String filePath = Objects.requireNonNull(MyProxy.class.getResource("")).getPath();
File f = new File(filePath + "$MyProxy0.java");
System.out.println(f);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//3.编译java文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager manage = compiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> iterable = manage.getJavaFileObjects(f);
JavaCompiler.CompilationTask task = compiler.getTask(null, manage, null, null, null, iterable);
task.call();
manage.close();
//4.加载到JVM
Class<?> myProxyClass = classLoader.findClass("$MyProxy0");
//5.获取动态生成的类的构造器
Constructor<?> c = myProxyClass.getConstructor(MyInvocationHandler.class);
//加载完class文件删除生成的java源文件
f.delete();
//6.返回构造的代理对象
return c.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 拼接java源代码
*/
private static String generateSrc(Class<?>[] interfaces) {
StringBuilder sb = new StringBuilder();
sb.append(MyProxy.class.getPackage()).append(";").append(LN);
sb.append("import ").append(interfaces[0].getName()).append(";").append(LN);
sb.append("import java.lang.reflect.*;" + LN);
sb.append("public class $MyProxy0 implements ").append(interfaces[0].getName()).append("{").append(LN);
sb.append("MyInvocationHandler h;" + LN);
sb.append("public $MyProxy0(MyInvocationHandler h) { " + LN);
sb.append("this.h = h;");
sb.append("}" + LN);
for (Method m : interfaces[0].getMethods()) {
Class<?>[] params = m.getParameterTypes();
StringBuilder paramNames = new StringBuilder();
StringBuilder paramValues = new StringBuilder();
StringBuilder paramClasses = new StringBuilder();
for (int i = 0; i < params.length; i++) {
Class<?> clazz = params[i];
String type = clazz.getName();
//参数变量名
String paramName = "var" + i;
//参数列表拼接类型和变量名
paramNames.append(type).append(" ").append(paramName);
//变量名拼接作为Object数组,作为invoke的参数
paramValues.append(paramName);
//拼接参数类型作为Class数组,用于反射查找对应的方法对象
paramClasses.append(clazz.getName()).append(".class");
if (i < params.length - 1) {
paramNames.append(",");
paramClasses.append(",");
paramValues.append(",");
}
}
sb.append("public ").append(m.getReturnType().getName()).append(" ").append(m.getName()).append("(").append(paramNames).append(") {").append(LN)
.append("try{" + LN)
.append("Method m = ").append(interfaces[0].getName()).append(".class.getMethod(\"").append(m.getName()).append("\",new Class[]{").append(paramClasses).append("});").append(LN)
.append(hasReturnValue(m.getReturnType()) ? "return (" + m.getReturnType().getName() + ")" : "").append("this.h.invoke(this,m,new Object[]{").append(paramValues).append("})").append(";").append(LN)
.append("}catch(Error er) {throw er; }").append(LN)
.append("catch(Throwable e){").append(LN)
.append("throw new UndeclaredThrowableException(e);" + LN)
.append("}").append(LN)
.append("}");
}
sb.append("}" + LN);
return sb.toString();
}
/**
* 判断方法是否有返回值
* @param clazz
* @return
*/
private static boolean hasReturnValue(Class<?> clazz) {
return clazz != void.class;
}
}
测试
定义接口InterfaceOne
package com.cml.test;
public interface InterfaceOne {
String show(String s1, String s2);
String hello(String s1);
}
接口实现类
package com.cml.test;
public class ImplOne implements InterfaceOne {
@Override
public String show(String s1, String s2) {
System.out.println("InterfaceOne >> ImplOne >> show");
return s1 + s2;
}
@Override
public String hello(String s1) {
return s1;
}
}
定义通知类
package com.cml.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 此类做通知
* @author yys
*
*/
public class Aspect {
public void before(){
System.out.println("前置通知");
}
public void afterReturning(Object ret){
System.out.println("后置通知, 返回值为-->" + ret);
}
public void afterThrowing(Throwable e){
System.out.println("抛出异常通知 ,异常信息: " + e.getMessage());
}
public void after(){
System.out.println("最终通知:finally里面的代码,发生异常也会执行。。。");
}
public Object around(Object target, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
System.out.println("环绕通知 前");
Object ret = method.invoke(target, args);
System.out.println("环绕通知 后");
return ret;
}
}
实现MyInvocationHandler接口
package com.cml.test;
import com.cml.proxy.MyClassLoader;
import com.cml.proxy.MyInvocationHandler;
import com.cml.proxy.MyProxy;
import java.lang.reflect.Method;
/**
* @author yys
* @version 1.0
*/
public class MyDynamicProxy implements MyInvocationHandler {
private Object target;
/**
* 通知类
*/
private Aspect aspect;
//设置通知类
public void setAspect(Aspect aspect) {
this.aspect = aspect;
}
/**
* 此方法用于创建代理对象
* @param target 传入一个被代理的对象
* @return 返回代理对象
*/
public Object createProxyInstance(Object target) {
this.target = target;
return MyProxy.newProxyInstance(new MyClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret = null;
try {
aspect.before();
ret = aspect.around(target, method, args);
aspect.afterReturning(ret);
} catch (Exception e) {
aspect.afterThrowing(e);
} finally {
aspect.after();
}
return ret;
}
}
执行
package com.cml.test;
/**
* @author yys
* @version 1.0
*/
public class Test {
public static void main(String[] args) {
MyDynamicProxy myDynamicProxy = new MyDynamicProxy();
myDynamicProxy.setAspect(new Aspect());
InterfaceOne interfaceOne = (InterfaceOne) myDynamicProxy.createProxyInstance(new ImplOne());
interfaceOne.show("show", "cml");
System.out.println(interfaceOne.getClass());
System.out.println(interfaceOne.getClass().getSuperclass());
}
}
结果