本文从0开始实现JDK动态代理功能,代理模式更多扩展,请参考此链接Java基础 代理模式。
JDK动态代理应用
JDK动态代理角色划分
业务逻辑接口类:需要被代理的接口类。
业务逻辑类:具体业务逻辑代码(增删改查)。
代理逻辑接口类:JDK提供的InvocationHandler接口。
代理逻辑类:具体业务逻辑代码(修改目标方法)。
代理生成类:JDK提供的Proxy类。
实体类User
public class User {
public User(String name, int age) {
this.name = name;
this.age = age;
}
private String name;
private int age;
}
业务逻辑接口类IUserService
public interface IUserService {
public int insertUser(User user) throws Throwable;
}
业务逻辑类UserService
public class UserService implements IUserService {
@Override
public int insertUser(User user) {
System.out.println("假装访问数据库,插入一条User数据");
return 1;
}
}
代理逻辑类IUserServiceInvocationHandler
public class IUserServiceInvocationHandler implements InvocationHandler {
private Object target;
public IUserServiceInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态代理:调用IUserServiceInvocationHandler.invoke方法");
return method.invoke(target, args);
}
}
启动类Application
public class Application {
public static void main(String[] args) throws Throwable {
User user = new User("tbryant", 18);
// JDK动态代理
System.out.println("JDK动态代理demo:");
IUserService jdkProxy = (IUserService) Proxy.newProxyInstance(Application.class.getClassLoader(),
new Class[]{IUserService.class}, new IUserServiceInvocationHandler(new UserService()));
jdkProxy.insertUser(user);
// 自定义动态代理
System.out.println("自定义动态代理demo:");
IUserService customProxy = (IUserService) CustomProxy.newProxyInstance(Application.class.getClassLoader(),
new Class[]{IUserService.class}, new IUserServiceCustomInvocationHandler(new UserService()));
customProxy.insertUser(user);
}
}
执行结果
为了方便对比,我把JDK动态代理和自定义动态代理的调用代码和执行结果贴在一起。
自定义动态代理
JDK动态代理InvocationHandler接口对应自定义动态代理CustomInvocationHandler接口,invoke方法签名保持一致。
JDK动态代理Proxy类对应自定义动态代理CustomProxy类,newProxyInstance方法签名保持一致。
业务逻辑接口类IUserService和业务逻辑类UserService代码不变。
代理逻辑接口类CustomInvocationHandler
public interface CustomInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
代理逻辑类IUserServiceCustomInvocationHandler
public class IUserServiceCustomInvocationHandler implements CustomInvocationHandler {
private Object target;
public IUserServiceCustomInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("自定义动态代理:调用IUserServiceCustomInvocationHandler.invoke方法");
return method.invoke(target, args);
}
}
代理生成类CustomProxy
/**
* 模拟JDK动态代理工具类
*/
public class CustomProxy {
/**
* 根据目标对象进行分析,得到代理对象代码,拼接成string
* 保存到磁盘得到.java文件
* 编译.java文件得到.class文件
* 把.class文件load到内存
* 反射得到proxy对象
*/
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, CustomInvocationHandler h) {
Object proxy = null;
// 第一步:根据目标对象进行分析,得到代理对象代码,拼接成string
String line = "\n";// 换行
String tab = "\t";// 缩进
Class<?> targetInterface = interfaces[0];// TODO 先实现代理一个接口,后续实现代理多个接口
String targetInterfaceFullName = targetInterface.getName();// 接口全限定名
String targetInterfaceName = targetInterface.getSimpleName();// 接口名
String content = "";
String packageContent = "package com.tbryant;" + line;
String importContent = "import " + targetInterfaceFullName + ";" + line
+ "import com.tbryant.customjdkproxy.proxy.CustomInvocationHandler;" + line
+ "import java.lang.reflect.Method;" + line;
String clazzContent = "public class $CustomProxy implements " + targetInterfaceName + " {" + line;
String filedContent = tab + "private CustomInvocationHandler h;" + line;
String constructorContent = tab + "public $CustomProxy(CustomInvocationHandler h){" + line
+ tab + tab + "this.h=h;" + line
+ tab + "}" + line;
String methodContent = "";
Method[] methods = targetInterface.getDeclaredMethods();
for (Method method : methods) {
Class[] args = method.getParameterTypes();// 方法参数
// 循环取方法参数类型,拼接方法参数字符串
String argsTypesContent = "";// 参数类型 String,String
String argsTypesAndArgsContent = "";// 参数签名 String arg0,String arg1
String argsContent = "";// 参数 arg0,arg1
int i = 0;
for (Class arg : args) {
String argTypeFullName = arg.getName();
importContent += "import " + argTypeFullName + ";" + line;
String argTypeName = arg.getSimpleName();
argsTypesContent += argTypeName + ".class,";
argsTypesAndArgsContent += argTypeName + " arg" + i + ",";
argsContent += "arg" + i + ",";
i++;
}
if (argsTypesContent.length() > 0) {// 有参数的话,去掉末尾逗号
argsTypesContent = argsTypesContent.substring(0, argsTypesContent.lastIndexOf(","));
argsTypesAndArgsContent = argsTypesAndArgsContent.substring(0, argsTypesAndArgsContent.lastIndexOf(","));
argsContent = argsContent.substring(0, argsContent.lastIndexOf(","));
}
String methodName = method.getName();// 方法名
String returnTypeName = method.getReturnType().getSimpleName();// 方法返回值类型名字
if ("".equals(argsTypesContent)) {
argsTypesContent += "(Class<?>[]) null";
}
if ("void".equals(returnTypeName)) {// 判断是否有返回值
methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsTypesAndArgsContent + ") throws Throwable {" + line
+ tab + tab + "Method method=Class.forName(\"" + targetInterfaceFullName + "\").getDeclaredMethod(\"" + methodName + "\"," + argsTypesContent + ");" + line
+ tab + tab + "h.invoke(null,method,new Object[]{" + argsContent + "});" + line
+ tab + "}" + line;
} else {
methodContent += tab + "public " + returnTypeName + " " + methodName + "(" + argsTypesAndArgsContent + ") throws Throwable {" + line
+ tab + tab + "Method method=Class.forName(\"" + targetInterfaceFullName + "\").getDeclaredMethod(\"" + methodName + "\"," + argsTypesContent + ");" + line
+ tab + tab + "return (" + returnTypeName + ")h.invoke(null,method,new Object[]{" + argsContent + "});" + line
+ tab + "}" + line;
}
}
content = packageContent + importContent + clazzContent + filedContent + constructorContent + methodContent + "}";
// 第二步:保存到磁盘得到.java文件
File file = new File("d:\\com\\tbryant\\$CustomProxy.java");
try {
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file);
fw.write(content);
fw.flush();
fw.close();
// 第三步:编译.java文件得到.class文件
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null);
Iterable javaFileObjects = standardJavaFileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask compilationTask = javaCompiler.getTask(null, standardJavaFileManager, null, null, null, javaFileObjects);
compilationTask.call();
standardJavaFileManager.close();
// 第四步:把.class文件load到内存
URL urls[] = new URL[]{new URL("file:D:\\\\")};
URLClassLoader urlClassLoader = new URLClassLoader(urls);
Class clazz = urlClassLoader.loadClass("com.tbryant.$CustomProxy");
// 第五步:反射得到proxy对象
Constructor constructor = clazz.getConstructor(CustomInvocationHandler.class);
proxy = constructor.newInstance(h);
} catch (Exception ex) {
ex.printStackTrace();
}
return proxy;
}
}
源码地址:CustomJDKProxy模块