实现原理是在本地生成一个.java文件,再使用jdk自带的javax.tools.JavaCompiler类在程序运行过程中编译运行生成的java文件,加载到内存中。
MyProxy.java
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.net.URLClassLoader;
public class MyProxy {
public static Object newMyProxyInstance(Class clazz, MyInvocationHandler myInvocationHandler) {
String methodContext = "";
String rn = "\r\n";
String importContext = clazz.getName().replace("." + clazz.getSimpleName(), "");
for (Method method : clazz.getMethods()) {
String parameterContext = "", argsContext = "", paramTypeContext = "";
for (Parameter parameter : method.getParameters()) {
argsContext += parameter.getName() + ",";
paramTypeContext += parameter.getType().getName() + ".class,";
parameterContext += parameter.getType().getSimpleName() + " " + parameter.getName() + ",";
}
if (parameterContext.length() > 0) {
argsContext = argsContext.substring(0, argsContext.length() - 1);
parameterContext = parameterContext.substring(0, parameterContext.length() - 1);
paramTypeContext = paramTypeContext.substring(0, paramTypeContext.length() - 1);
}
methodContext += rn + "\t@Override" + rn
+ "\tpublic " + method.getReturnType().getSimpleName() + " " + method.getName() + "(" + parameterContext + "){" + rn
+ "\t\ttry {" + rn
+ "\t\t\tMethod method = " + clazz.getName() + ".class.getMethod(\"" + method.getName() + "\"" + "," + paramTypeContext + ");" + rn
+ "\t\t\treturn (" + method.getReturnType().getSimpleName() + ") myInvocationHandler.call(this,method," + argsContext + ");" + rn
+ "\t\t}catch(Exception e) {" + rn
+ "\t\t\te.printStackTrace();" + rn
+ "\t\t}" + rn
+ "\t\treturn null;" + rn
+ "\t}" + rn;
}
String context = "package " + importContext + ";" + rn + rn
+ "import java.lang.reflect.Method;" + rn + rn
+ "public class $Proxy0 implements " + clazz.getName() + "{" + rn + rn
+ "\tcom.myproxy.MyInvocationHandler myInvocationHandler;" + rn + rn
+ "\tpublic $Proxy0(com.myproxy.MyInvocationHandler myInvocationHandler) {" + rn
+ "\t\tthis.myInvocationHandler = myInvocationHandler;" + rn
+ "\t}" + rn
+ methodContext + rn
+ "}";
try {
String fileName = clazz.getResource("/").getPath() + importContext.replaceAll("\\.","/") + "/$Proxy0.java";
fileName = fileName.replaceAll("%20", " ");
File file = new File(fileName);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file);
fw.write(context);
fw.flush();
fw.close();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, units);
task.call();
fileMgr.close();
URL[] urls = new URL[]{new URL("file:/" + fileName)};
URLClassLoader ul = new URLClassLoader(urls);
Constructor constructor = ul.loadClass(importContext + ".$Proxy0").getConstructor(MyInvocationHandler.class);
return constructor.newInstance(myInvocationHandler);
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
MyInvocationHandler.java
public abstract class MyInvocationHandler {
protected Object t;
public <T, E> E getProxy(T t, Class<E> clazz) {
this.t = t;
return (E) MyProxy.newMyProxyInstance(clazz, this);
}
public Object call(Object proxy, Method method, Object... args) {
Object returnContext = null;
try {
before();
before(method);
returnContext = method.invoke(t, args);
afterReturning();
afterReturning(returnContext);
} catch (Throwable throwable) {
afterThrowing();
afterThrowing(throwable);
} finally {
after();
}
return returnContext;
}
protected void before(){}
protected void before(Method method){}
protected void after(){}
protected void afterReturning(){}
protected void afterReturning(Object returnContext){}
protected void afterThrowing(){}
protected void afterThrowing(Throwable throwable){}
}
MyHandler.java
public class MyHandler extends MyInvocationHandler {
@Override
public void before() {
System.out.println("支付前");
}
@Override
public void after() {
System.out.println("支付后");
}
@Override
public void afterReturning() {
System.out.println("支付成功");
}
@Override
public void afterThrowing() {
System.out.println("出异常了");
}
}
测试方法
@Test
public void test06() {
Payment proxy = new MyHandler().getProxy(new Payment() {
@Override
public String pay(double price) {
return "支付了" + price;
}
@Override
public String rest(double rest) {
return "还剩" + rest;
}
}, Payment.class);
System.out.println(proxy.pay(15.6));
System.out.println(proxy.rest(15.7));
}