实现思路:在内存中通过拼接字符串的方式继承被代理的类,生成的代理类字符串通过JavaCompiler编译为字节码,并将字节码保存在内存中,最后通过自定义的类加载器加载到元数据区生成了代理类的Class对象。
Enhancer类:
package com.lj.proxy;
import lombok.Data;
import javax.tools.*;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.nio.CharBuffer;
import java.util.*;
/**
* @Description 模仿CGlib获取代理类,在内存中通过继承的方式动态生成代理类,再在内存中完成编译,最后返回代理对象
* @Date 2020/8/22 15:30
* @Created by 长白山西红柿
*/
@Data
public class Enhancer {
/**
* 生成的代理类,key为类名,value为字节码
*/
private static Map<String, byte[]> proxyClassMap = new HashMap<>();
/**
* 被代理类名
*/
private Class superclass;
/**
* 被代理类的对象
*/
private Object superObject;
/**
* 代理类执行的方法,(目前只支持around)
*/
private MethodInterceptor methodInterceptor;
private static String path = "com.lj.proxy.proxyClass.";
/**
* 代理类的类加载器
*/
private static ProxyClassLoader proxyClassLoader = new ProxyClassLoader();
/**
* 要求被代理的类必须有无参构造方法
* @return
*/
public Object create() {
if (Objects.isNull(superclass) || Objects.isNull(methodInterceptor)) {
return null;
}
if (Objects.nonNull(superObject) && !superclass.equals(superObject.getClass())) {
return null;
}
String className = superclass.getSimpleName() + "Proxy$" + proxyClassMap.size();
// 编译成字节码文件
compile(className, createProxyClass(className));
Object result = null;
try {
// 将字节码通过自定义类加载器加载到元数据区
Class<?> proxyClass = proxyClassLoader.loadClass(path + className);
// 生成代理对象并填充数据
result = proxyClass.newInstance();
superObject = superObject == null ? superclass.newInstance() : superObject ;
Field superObjectField = proxyClass.getDeclaredField("superObject");
superObjectField.setAccessible(true);
superObjectField.set(result, superObject);
Field methodInterceptorField = proxyClass.getDeclaredField("methodInterceptor");
methodInterceptorField.setAccessible(true);
methodInterceptorField.set(result, methodInterceptor);
HashMap<String, Method> methodMap = new HashMap<>();
for (Method method : superclass.getMethods()) {
methodMap.put(method.getName(), method);
}
Field methodMapField = proxyClass.getDeclaredField("methodMap");
methodMapField.setAccessible(true);
methodMapField.set(result, methodMap);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return result;
}
/**
* 本方法生成的字符串可以见最后的实例
* @return 返回字符串形式的代理类java文件
*/
private String createProxyClass(String className) {
StringBuilder sourceCode = new StringBuilder();
// 获取系统换行符
// String lineFeed = System.getProperty("line.separator");
sourceCode.append("package com.lj.proxy.proxyClass;\n");
sourceCode.append("import ").append(superclass.getName()).append(";\n");
sourceCode.append("import com.lj.proxy.MethodInterceptor;\n" +
"import java.lang.reflect.Method;\n" +
"import java.util.HashMap;\n" +
"import java.util.Map;\n");
// 代理类类开始的地方
sourceCode.append("public class ").append(className).append(" extends ").append(superclass.getSimpleName()).append(" {\n");
// 代理类的成员
sourceCode.append("private MethodInterceptor methodInterceptor;\n" +
"private Object superObject;\n" +
"private Map<String, Method> methodMap;\n");
// 代理对象真正执行的方法,¥是为了避免重名
sourceCode.append("private <T> T doAround¥(String methodName, Object[] args) {\n" +
"return (T) methodInterceptor.intercept(superObject, methodMap.get(methodName), args);\n" +
"}\n");
// 代理类的所有公有方法
Method[] methods = superclass.getMethods();
for (Method method : methods) {
// 不能代理static和final方法
if (Modifier.isStatic(method.getModifiers()) || Modifier.isFinal(method.getModifiers())) {
continue;
}
sourceCode.append("@Override\n");
sourceCode.append("public ").append(method.getReturnType().getName()).append(" ").append(method.getName()).append(" (");
Class<?>[] args = method.getParameterTypes();
if (args.length <= 0) {
sourceCode.append(") {\n");
// 判断方法是否有返回值
if (!method.getReturnType().getName().equals("void")) {
sourceCode.append("return ");
}
sourceCode.append("doAround¥(\"").append(method.getName()).append("\", null);\n");
} else {
// 先构造入参
for (int i = 0; i < args.length; i++) {
if (i != 0) {
sourceCode.append(", ");
}
sourceCode.append(args[i].getName()).append(" var").append(i);
}
sourceCode.append(") {\n");
sourceCode.append("Object[] args = new Object[methodMap.get(\"").append(method.getName()).append("\").getParameterTypes().length];\n");
// 将所有参数填入Object[] args
for (int i = 0; i < args.length; i++) {
sourceCode.append("args[").append(i).append("] = ").append(" var").append(i).append(";\n");
}
// 判断方法是否有返回值
if (!method.getReturnType().getName().equals("void")) {
sourceCode.append("return ");
}
sourceCode.append("doAround¥(\"").append(method.getName()).append("\", args);\n");
}
// 一个代理方法构造结束
sourceCode.append("}\n");
}
// 代理类构造结束
sourceCode.append("}");
return sourceCode.toString();
}
/**
* 将字符串形式的代理类java文件编译成字节码,并放在proxyClassMap里
* @param className 生成的代理类名
* @param sourceCode 字符串形式的代理类java文件
*/
private void compile(String className, String sourceCode) {
//获取系统Java编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//获取Java文件管理器
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
// 设置编译后的字节码直接放在内存里,需要重写JavaFileManager的openOutputStream方法
JavaFileManager jfm = new ForwardingJavaFileManager(fileManager) {
public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location,
String className,
JavaFileObject.Kind kind,
FileObject sibling) throws IOException {
if(kind == JavaFileObject.Kind.CLASS) {
return new SimpleJavaFileObject(URI.create(className + ".class"), JavaFileObject.Kind.CLASS) {
public OutputStream openOutputStream() {
return new FilterOutputStream(new ByteArrayOutputStream()) {
public void close() throws IOException{
out.close();
ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
proxyClassMap.put(className, bos.toByteArray());
}
};
}
};
}else{
return super.getJavaFileForOutput(location, className, kind, sibling);
}
}
};
// 设置获取源码的方式为字符串,需要重写JavaFileObject的getCharContent方法
Iterable<? extends JavaFileObject> compilationUnits = new Iterable<SimpleJavaFileObject>() {
@Override
public Iterator<SimpleJavaFileObject> iterator() {
SimpleJavaFileObject sourceJavaFileObject = new SimpleJavaFileObject(URI.create(className + ".java"),
JavaFileObject.Kind.SOURCE){
public CharBuffer getCharContent(boolean b) {
return CharBuffer.wrap(sourceCode);
}
};
List<SimpleJavaFileObject> list = new ArrayList<>();
list.add(sourceJavaFileObject);
return list.iterator();
}
};
//生成编译任务
JavaCompiler.CompilationTask task = compiler.getTask(null, jfm, null, null, null, compilationUnits);
//执行编译任务
task.call();
}
private static class ProxyClassLoader extends ClassLoader {
public ProxyClassLoader(){
}
/**
* 重写findClass方法
* @param name 是我们这个类的全路径
* @return
* @throws ClassNotFoundException
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class log = null;
// 获取该class文件字节码数组
byte[] classData = getData(name);
if (classData != null) {
// 将class的字节码数组转换成Class类的实例
log = defineClass(name, classData, 0, classData.length);
}
return log;
}
/**
* 将class文件转化为字节码数组
* * @return
*/
private byte[] getData(String name) {
return proxyClassMap.get(name);
}
}
}
/** 被代理类com.lj.model.Student生成的代理类(示例)
package com.lj.proxy.proxyClass;
import com.lj.model.Student;
import com.lj.proxy.MethodInterceptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class StudentProxy$0 extends Student {
private MethodInterceptor methodInterceptor;
private Object superObject;
private Map<String, Method> methodMap;
private <T> T doAround¥(String methodName, Object[] args) {
return (T) methodInterceptor.intercept(superObject, methodMap.get(methodName), args);
}
@Override
public boolean equals (java.lang.Object var0) {
Object[] args = new Object[methodMap.get("equals").getParameterTypes().length];
args[0] = var0;
return doAround¥("equals", args);
}
@Override
public java.lang.String toString () {
return doAround¥("toString", null);
}
@Override
public int hashCode () {
return doAround¥("hashCode", null);
}
@Override
public java.lang.String getName () {
return doAround¥("getName", null);
}
@Override
public java.lang.String getId () {
return doAround¥("getId", null);
}
@Override
public void setName (java.lang.String var0) {
Object[] args = new Object[methodMap.get("setName").getParameterTypes().length];
args[0] = var0;
doAround¥("setName", args);
}
@Override
public void setId (java.lang.String var0) {
Object[] args = new Object[methodMap.get("setId").getParameterTypes().length];
args[0] = var0;
doAround¥("setId", args);
}
}
*/
被代理的model类:
package com.lj.model;
import lombok.Data;
/**
* @Description TODO
* @Date 2020/8/22 15:27
* @Created by 长白山西红柿
*/
@Data
public class Student {
private String id;
private String name;
public void setId(String s) {
this.id = s;
}
}
测试Demo:
import com.lj.model.Student;
import com.lj.proxy.Enhancer;
import com.lj.proxy.MethodInterceptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @Description 简单模仿CGLib通过在内存中生成被代理类的子类实现动态代理(没有做代理链)
* @Date 2020/8/22 15:26
* @Created by 长白山西红柿
*/
public class Demo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
// 必须设置超类和拦截器方法
enhancer.setSuperclass(Student.class);
enhancer.setMethodInterceptor((Object o, Method method, Object[] objects) -> {
Object result = null;
System.out.println("对方法" + method.getName() + "前置拦截");
try {
result = method.invoke(o, objects);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("对方法" + method.getName() + "后置拦截");
return result;
});
Student student = (Student) enhancer.create();
// 如果正确会输出前置和后置拦截
student.setId("007");
System.out.println(student.getId());
// try {
// System.out.println(Student.class.getMethod("getClass", String.class));
// } catch (NoSuchMethodException e) {
// e.printStackTrace();
// }
}
}
测试结果:
对方法setId前置拦截
对方法setId后置拦截
对方法getId前置拦截
对方法getId后置拦截
007