前言
最近学习了Jdk的动态代理,然后自己也简单的手写了一个。
思路
- 根据代理的接口,生成对应的Java代码文件
- 将生成的Java文件编译成class文件
- 利用URLClassLoader加载class到Jvm中,利用反射在new出这个对象。
业务代理接口
package com.michael.pl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public interface InvocationHandler {
Object invock(Object object, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException;
}
需要代理的接口
package com.michael.pl.service;
public interface LogService {
void sayHi() throws Exception;
Object out(String text) throws Exception;
}
package com.michael.pl.service.impl;
import com.michael.pl.service.LogService;
public class LogServiceImpl implements LogService {
@Override
public void sayHi() {
System.out.println("hello");
}
@Override
public Object out(String text) {
return text;
}
}
实现动态代理的核心类

package com.michael.pl;
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.Method;
import java.net.URL;
import java.net.URLClassLoader;
public class MyProxy {
public static final String TABLE = " ";
public static final String ENTER = "\n";
public static Object newProxyInstance(ClassLoader classLoader, Class<?> interfaceClass,
InvocationHandler invocationHandler) throws Exception {
String javaCode = buiderJavaFile(interfaceClass);
// System.out.println(javaCode);
String className = interfaceClass.getName().substring(interfaceClass.getName().lastIndexOf(".") + 1);
File file = new File("\\com\\sun\\proxy\\$" + className + ".java");
File parentFile = file.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
// 把拼好的Java文件写到硬盘当中
FileWriter fw = new FileWriter(file);
fw.write(javaCode);
fw.close();
// 把写到硬盘的Java文件编译成class
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(file);
JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
// 吧编译上的class文件加载到JVM中
URL[] urls = new URL[]{new URL("file:G:\\\\")};
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class clazz = urlClassLoader.loadClass("com.sun.proxy.$" + className);
Constructor constructor = clazz.getConstructor(InvocationHandler.class);
return constructor.newInstance(invocationHandler);
}
/**
* 生成对应的Java代码
*/
public static String buiderJavaFile(Class<?> interfaceClass) throws Exception {
String className = interfaceClass.getName().substring(interfaceClass.getName().lastIndexOf(".") + 1);
StringBuilder content = new StringBuilder();
content.append("package com.sun.proxy;" + ENTER );
content.append("import java.lang.reflect.Method;" + ENTER);
content.append("import java.lang.Exception;" + ENTER);
content.append("import com.michael.pl.InvocationHandler;" + ENTER);
content.append("public class $" + className + " implements " + interfaceClass.getName() + "{" + ENTER);
content.append(TABLE + "private InvocationHandler i;" + ENTER);
// 添加构造方法
content.append(forTable(1) + " public $" + className + "(InvocationHandler i){"+ENTER);
content.append(forTable(1) + "this.i = i;" + ENTER);
content.append(forTable(1) + "}" + ENTER);
Method[] methods = interfaceClass.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
String returnType = method.getReturnType().getName();
int j = 0;
String paramContent = "";
String callParam = "";
String paramClass = "";
for (Class<?> paramType : method.getParameterTypes()) {
paramContent += paramType.getName() + " args" + j + ",";
callParam += "args" + j + ",";
paramClass += paramType.getName() + ".class,";
j++;
}
if (paramContent.length()>0) {
paramContent = paramContent.substring(0, paramContent.length() - 1);
callParam = "new Object[]{" + callParam.substring(0, callParam.length() - 1) + "}";
paramClass = paramClass.substring(0, paramClass.length() - 1);
}
if (callParam.length() == 0) {
callParam = "null";
}
String exceptionContent = "";
for (Class<?> exceptionType : method.getExceptionTypes()) {
exceptionContent += exceptionType.getName() + ",";
}
if (exceptionContent.length()>0) {
exceptionContent = "throws " + exceptionContent.substring(0, exceptionContent.length() - 1);
}
content.append(forTable(1) + "public " + returnType + " " + method.getName() + "(" + paramContent + ") "
+ exceptionContent + " {" + ENTER);
content.append(forTable(2) + "Method declaredMethod = Class.forName(\"" + interfaceClass.getName()
+ "\").getDeclaredMethod(\"" + method.getName() + "\"" + (paramClass.length() == 0 ? "" :
"," + paramClass) + ");" + ENTER);
if (!"void".equals(method.getReturnType().getName())) {
content.append(forTable(2) + "return (" + returnType + ")");
}
content.append("i.invock(this,declaredMethod,"+callParam+");" + ENTER);
content.append(forTable(1) + "}" + ENTER);
}
content.append("}" + ENTER);
return content.toString();
}
private static String forTable(int i) {
String str = "";
for (int j = 0; j < i; j++) {
str += TABLE;
}
return str;
}
}
测试类
package com.michael.pl;
import com.michael.pl.service.LogService;
import com.michael.pl.service.impl.LogServiceImpl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestDemo {
public static void main(String[] args) throws Exception {
// 被代理的对象
LogServiceImpl logServiceImpl = new LogServiceImpl();
LogService logService = (LogService)MyProxy.newProxyInstance(TestDemo.class.getClassLoader(), LogService.class,
new InvocationHandler() {
@Override
public Object invock(Object object, Method method, Object[] argss)
throws InvocationTargetException, IllegalAccessException {
System.out.println(" 代理类容!!");
return method.invoke(logServiceImpl, argss);
}
});
logService.sayHi();
logService.out("你好");
}
}
代码下载地址:https://files.cnblogs.com/files/MichaelPL/MyProxy.zip