这里使用最简单的方法实现动态代理,即重新生成一个.java文件使用类加载器加载到内存,这与jdk底层的动态代理有所不同。
通过字符串拼接出动态代理类的内容(强迫症必须要的对齐格式格式)
private static String generateProxyContentStr(Class clazz) {
Method[] methods = clazz.getDeclaredMethods();
String content = "package proxy;" + LINE + LINE;
content +=
"import com.hrious.javabasic.proxy.CustomInvocationHandler;" + LINE + LINE
+ "import java.lang.reflect.Method;" + LINE + LINE
+ "import " + clazz.getName() + ";" + LINE + LINE
+ "public class $Proxy implements UserDao {"
+ LINE + LINE
+ TAB + "private CustomInvocationHandler handler;"
+ LINE + LINE
+ TAB + "public $Proxy(CustomInvocationHandler handler) {"
+ LINE
+ TAB + TAB + "this.handler = handler;" + LINE
+ TAB + "}"
+ LINE + LINE;
String methodStr = "";
// 遍历每个方法
for (Method method : methods) {
methodStr +=
TAB + PUB + SPACE + method.getReturnType() + SPACE
+ method.getName() + "(";
Class<?>[] types = method.getParameterTypes();
String paramStr = "";
String declareType = "";
if (types.length != 0) {
declareType += ", ";
for (int i = 0; i < types.length; i++) {
paramStr += types[i].getName() + SPACE + "i" + i + "," + SPACE;
declareType += types[i].getName() + ".class" + "," + SPACE;
}
paramStr = paramStr.substring(0, paramStr.length() - 2);
declareType = declareType.substring(0, declareType.length() - 2);
}
methodStr += paramStr + ") {" + LINE
+ TAB + TAB + "try {" + LINE
+ TAB + TAB + TAB + "Class clazz = " + clazz.getSimpleName() + ".class;" + LINE
+ TAB + TAB + TAB + "Method method = " + "clazz.getDeclaredMethod(\"" + method.getName() + "\"" + declareType + ");" + LINE;
String objArrStr = "";
if (types.length != 0) {
objArrStr += "Object[] args = {";
for (int i = 0; i < types.length; i++) {
objArrStr += SPACE + "i" + i + ",";
}
objArrStr = objArrStr.substring(0 ,objArrStr.length() - 1);
objArrStr += " ";
methodStr +=
TAB + TAB + TAB + objArrStr + "};" + LINE
+ TAB + TAB + TAB + "return (" + method.getReturnType() + ") handler.invoke(method, args);" + LINE;
} else {
methodStr += TAB + TAB + TAB + "handler.invoke(method, null);" + LINE;
}
methodStr +=
TAB + TAB + "}" + LINE
+ TAB + TAB + "catch (Throwable t) {" + LINE
+ TAB + TAB + TAB + "throw new RuntimeException(t);" + LINE
+ TAB + TAB + "}" + LINE + TAB + "}" + LINE + LINE;
}
content += methodStr + "}";
return content;
}
即把生成的动态代理类的内容通过IO操作的方式,写入到与之对应的.java文件中
private static String createProxyFile(String proxyContent) throws IOException {
File dir = new File("D:\\proxy");
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File("D:\\proxy\\$Proxy.java");
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file));) {
bw.write(proxyContent);
bw.flush();
return "D:\\proxy\\$Proxy.java";
} catch (IOException e) {
throw e;
}
}
private static void complieProxyFile(String filePath) {
File file = new File(filePath);
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();
try {
fileMgr.close();
} catch (IOException e) {
}
}
private static Class loadProxy2Mem() throws MalformedURLException, ClassNotFoundException {
URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL("file:d://")});
return classLoader.loadClass("proxy.$Proxy");
}
public static Object newInstances(Class inter, CustomInvocationHandler handler) {
try {
String proxyContent = generateProxyContentStr(inter);
String filePath = createProxyFile(proxyContent);
complieProxyFile(filePath);
Class clazz = loadProxy2Mem();
Constructor constructor = clazz.getConstructor(CustomInvocationHandler.class);
return constructor.newInstance(handler);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
package com.hrious;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* 模拟jdk动态代理
*/
public class CustomProxy {
private static final String LINE = "\r\n";
private static final String TAB = "\t";
private static final String PUB = "public";
private static final String SPACE = " ";
public static Object newInstances(Class inter, CustomInvocationHandler handler) {
try {
String proxyContent = generateProxyContentStr(inter);
String filePath = createProxyFile(proxyContent);
complieProxyFile(filePath);
Class clazz = loadProxy2Mem();
Constructor constructor = clazz.getConstructor(CustomInvocationHandler.class);
return constructor.newInstance(handler);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
/**
* 将.class文件加载到内存
* @return
* @throws Exception
*/
private static Class loadProxy2Mem() throws MalformedURLException, ClassNotFoundException {
URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL("file:d://")});
return classLoader.loadClass("proxy.$Proxy");
}
/**
* 编译生成的.java文件为.class文件
*/
private static void complieProxyFile(String filePath) {
File file = new File(filePath);
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();
try {
fileMgr.close();
} catch (IOException e) {
}
}
/**
* 生成代理类的.java文件
* @param proxyContent
* @throws IOException
*/
private static String createProxyFile(String proxyContent) throws IOException {
File dir = new File("D:\\proxy");
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File("D:\\proxy\\$Proxy.java");
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file));) {
bw.write(proxyContent);
bw.flush();
return "D:\\proxy\\$Proxy.java";
} catch (IOException e) {
throw e;
}
}
/**
* 生成代理内容字符串
* @param clazz
* @return
*/
private static String generateProxyContentStr(Class clazz) {
Method[] methods = clazz.getDeclaredMethods();
String content = "package proxy;" + LINE + LINE;
content +=
"import com.hrious.javabasic.proxy.CustomInvocationHandler;" + LINE + LINE
+ "import java.lang.reflect.Method;" + LINE + LINE
+ "import " + clazz.getName() + ";" + LINE + LINE
+ "public class $Proxy implements UserDao {"
+ LINE + LINE
+ TAB + "private CustomInvocationHandler handler;"
+ LINE + LINE
+ TAB + "public $Proxy(CustomInvocationHandler handler) {"
+ LINE
+ TAB + TAB + "this.handler = handler;" + LINE
+ TAB + "}"
+ LINE + LINE;
String methodStr = "";
// 遍历每个方法
for (Method method : methods) {
methodStr +=
TAB + PUB + SPACE + method.getReturnType() + SPACE
+ method.getName() + "(";
Class<?>[] types = method.getParameterTypes();
String paramStr = "";
String declareType = "";
if (types.length != 0) {
declareType += ", ";
for (int i = 0; i < types.length; i++) {
paramStr += types[i].getName() + SPACE + "i" + i + "," + SPACE;
declareType += types[i].getName() + ".class" + "," + SPACE;
}
paramStr = paramStr.substring(0, paramStr.length() - 2);
declareType = declareType.substring(0, declareType.length() - 2);
}
methodStr += paramStr + ") {" + LINE
+ TAB + TAB + "try {" + LINE
+ TAB + TAB + TAB + "Class clazz = " + clazz.getSimpleName() + ".class;" + LINE
+ TAB + TAB + TAB + "Method method = " + "clazz.getDeclaredMethod(\"" + method.getName() + "\"" + declareType + ");" + LINE;
String objArrStr = "";
if (types.length != 0) {
objArrStr += "Object[] args = {";
for (int i = 0; i < types.length; i++) {
objArrStr += SPACE + "i" + i + ",";
}
objArrStr = objArrStr.substring(0 ,objArrStr.length() - 1);
objArrStr += " ";
methodStr +=
TAB + TAB + TAB + objArrStr + "};" + LINE
+ TAB + TAB + TAB + "return (" + method.getReturnType() + ") handler.invoke(method, args);" + LINE;
} else {
methodStr += TAB + TAB + TAB + "handler.invoke(method, null);" + LINE;
}
methodStr +=
TAB + TAB + "}" + LINE
+ TAB + TAB + "catch (Throwable t) {" + LINE
+ TAB + TAB + TAB + "throw new RuntimeException(t);" + LINE
+ TAB + TAB + "}" + LINE + TAB + "}" + LINE + LINE;
}
content += methodStr + "}";
return content;
}
public static void main(String[] args) {
UserDao userDao = (UserDao) newInstances(UserDao.class, new MyCustomInvocationHandler(new UserDaoImpl()));
userDao.query();
// userDao.insert(1, "张三");
}
}
package com.hrious;
import java.lang.reflect.Method;
/**
* 自定义InvocationHandler接口,模拟jdk动态代理
*/
public interface CustomInvocationHandler {
Object invoke(Method method, Object[] args) throws Throwable;
}
UserDao接口
public interface UserDao {
void query();
int insert(int id, String name);
}
UserDao实现类
package com.hrious;
public class UserDaoImpl implements UserDao {
@Override
public void query() {
System.out.println("UserDaoImpl query()");
}
@Override
public int insert(int id, String name) {
System.out.println("id:" + id + ", name:" + name);
return 1;
}
}
InvocationHandler增强逻辑
package com.hrious;
import java.lang.reflect.Method;
public class MyCustomInvocationHandler implements CustomInvocationHandler {
private UserDao userDao;
public MyCustomInvocationHandler(UserDao userDao) {
this.userDao = userDao;
}
@Override
public Object invoke(Method method, Object[] args) throws Throwable {
System.out.println("my dynamic proxy");
return method.invoke(userDao, args);
}
}
测试方法
public static void main(String[] args) {
UserDao userDao = (UserDao) newInstances(UserDao.class, new MyCustomInvocationHandler(new UserDaoImpl()));
userDao.query();
// userDao.insert(1, "张三");
}
生成的代理类
package proxy;
import com.hrious.javabasic.proxy.CustomInvocationHandler;
import java.lang.reflect.Method;
import com.hrious.javabasic.proxy.UserDao;
public class $Proxy implements UserDao {
private CustomInvocationHandler handler;
public $Proxy(CustomInvocationHandler handler) {
this.handler = handler;
}
public int insert(int i0, java.lang.String i1) {
try {
Class clazz = UserDao.class;
Method method = clazz.getDeclaredMethod("insert", int.class, java.lang.String.class);
Object[] args = { i0, i1 };
return (int) handler.invoke(method, args);
}
catch (Throwable t) {
throw new RuntimeException(t);
}
}
public void query() {
try {
Class clazz = UserDao.class;
Method method = clazz.getDeclaredMethod("query");
handler.invoke(method, null);
}
catch (Throwable t) {
throw new RuntimeException(t);
}
}
}