单纯就是理解下JDK动态代理生成源码
1、JDK动态代理
JDK动态代理必须实现接口
接口:
public interface Marvel {
void attackBadPerson();
}
实现类:
public class Iron implements Marvel {
@Override
public void attackBadPerson() {
System.out.println("攻击灭霸");
}
}
代理类:
public class Sweetheart{
private Object marvel;
public Marvel getInstance(Marvel marvel) {
this.marvel = marvel;
Class<? extends Marvel> clazz = marvel.getClass();
return (Marvel) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object invokeResult = method.invoke(marvel, args);
after();
return invokeResult;
}
});
}
private void before() {
System.out.println("帮钢铁侠穿衣");
}
private void after() {
System.out.println("帮钢铁侠脱衣");
}
}
测试类:
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
Iron iron = new Iron();
Sweetheart sweetheart = new Sweetheart();
Marvel proxy = sweetheart.getInstance(iron);
proxy.attackBadPerson();
System.out.println(proxy.getClass());
}
}
执行结果:
帮钢铁侠穿衣
攻击灭霸
帮钢铁侠脱衣
class com.sun.proxy.$Proxy0
2、仿写JDK动态代理
接口:
public interface Marvel {
void attackBadPerson();
String getSlogan();
String getSlogan1(String name);
String getSlogan2(List<String> name);
String getSlogan3(String[] name);
String getSlogan4(int[] name);
String getSlogan5(double[] name);
String getSlogan6(String name, int num);
List<String> getSlogan7();
}
实现类:
public class Iron implements Marvel {
@Override
public void attackBadPerson() {
System.out.println("攻击灭霸");
}
@Override
public String getSlogan() {
System.out.println("爱你不止三千遍");
return "爱你不止三千遍";
}
@Override
public String getSlogan1(String name) {
System.out.println("string");
return "string";
}
@Override
public String getSlogan2(List<String> name) {
System.out.println("list集合");
return "list集合";
}
@Override
public String getSlogan3(String[] name) {
System.out.println("string数组");
return "string数组";
}
@Override
public String getSlogan4(int[] name) {
System.out.println("int数组");
return "int数组";
}
@Override
public String getSlogan5(double[] name) {
System.out.println("double数组");
return "double数组";
}
@Override
public String getSlogan6(String name, int num) {
System.out.println("String,int两个参数");
return "String,int两个参数";
}
@Override
public List<String> getSlogan7() {
System.out.println("返回类型为list集合");
return new ArrayList<>();
}
}
代理类:
public class Sweetheart implements BDInvocationHandler{
private Object marvel;
public Marvel getInstance(Marvel marvel) {
this.marvel = marvel;
Class<? extends Marvel> clazz = marvel.getClass();
return (Marvel) BDProxy.newProxyInstance(new BDClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(this.marvel, args);
}
}
仿写的Proxy:
public class BDProxy {
public static final String lineFeed = "\n";
public static int count = -1;
public static Object newProxyInstance(
BDClassLoader loader,
Class<?>[] interfaces,
BDInvocationHandler h) throws IllegalArgumentException {
String classCode = generateSourceCode(interfaces);
System.out.println(classCode);
String className = "$Proxy" + count;
String classPath = BDProxy.class.getResource("").getPath();
try {
File file = new File(classPath + className + ".java");
FileOutputStream fos = new FileOutputStream(file);
fos.write(classCode.getBytes());
fos.flush();
JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
task.call();
standardFileManager.close();
Class<?> aClass = loader.findClass(className);
Constructor<?> constructor = aClass.getConstructor(BDInvocationHandler.class);
return constructor.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static String generateSourceCode(Class<?>[] interfaces) {
StringBuilder sb = new StringBuilder();
String packageName = BDProxy.class.getPackage().getName();
sb.append("package ").append(packageName).append(";").append(lineFeed);
String implementsInterface = "";
for (int i = 0; i < interfaces.length; i++) {
String iName = interfaces[i].getName();
sb.append("import ").append(iName).append(";").append(lineFeed);
if (i == interfaces.length - 1) {
implementsInterface += iName;
} else {
implementsInterface += iName + ",";
}
}
sb.append("import java.lang.reflect.*;").append(lineFeed);
String className = "$Proxy" + ++count;
sb.append("public class " + className).append(" implements ").append(implementsInterface).append("{").append(lineFeed);
sb.append("BDInvocationHandler h;").append(lineFeed);
sb.append("public " + className + "(BDInvocationHandler h){").append(lineFeed);
sb.append("this.h = h;").append(lineFeed);
sb.append("}").append(lineFeed);
for (int i = 0; i < interfaces.length; i++) {
Method[] declaredMethods = interfaces[i].getDeclaredMethods();
for (int j = 0; j < declaredMethods.length; j++) {
Method method = declaredMethods[j];
String methodName = method.getName();
String returnTypeName = method.getReturnType().getName();
Class<?>[] parameterTypes = method.getParameterTypes();
String param = "param";
String paramTypeMethod = "";
String paramType = "";
String inParam = "";
for (int k = 0; k < parameterTypes.length; k++) {
Class<?> parameterType = parameterTypes[k];
String typeName = parameterType.getTypeName();
if (k == parameterTypes.length - 1) {
paramTypeMethod += typeName + " " + param + k;
paramType += typeName + ".class";
inParam += param + k;
}
else {
paramTypeMethod += typeName + " " + param + k + ",";
paramType += typeName + ".class,";
inParam += param + k + ",";
}
}
sb.append("public " + returnTypeName + " " + methodName + "(").append(paramTypeMethod).append("){").append(lineFeed);
sb.append("try {").append(lineFeed);
sb.append("Method m = " + interfaces[i].getName() + ".class.getMethod(").append("\"" + methodName + "\", new Class[]{").append(paramType).append("});").append(lineFeed);
if ("void".equals(returnTypeName)) {
sb.append("this.h.invoke(this, m, new java.lang.Object[]{").append(paramType).append("});").append(lineFeed);
sb.append("} catch (Throwable e){ e.printStackTrace();}").append(lineFeed);
}
else {
sb.append("return (" + returnTypeName + ") this.h.invoke(this, m, new java.lang.Object[]{").append(inParam).append("});").append(lineFeed);
sb.append("} catch (Throwable e){ ").append(lineFeed);
sb.append("e.printStackTrace();").append(lineFeed);
sb.append("}").append(lineFeed);
sb.append("return null;").append(lineFeed);
}
sb.append("}").append(lineFeed);
}
}
sb.append("}").append(lineFeed);
return sb.toString();
}
}
自定义的InvocationHandler:
public interface BDInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
自定义的类加载器:
public class BDClassLoader extends ClassLoader {
private File classPathFile;
public BDClassLoader() {
String path = BDClassLoader.class.getResource("").getPath();
this.classPathFile = new File(path);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String className = BDClassLoader.class.getPackage().getName() + "." + name;
if (classPathFile != null) {
File classFile = new File(classPathFile, name + ".class");
try {
if (classFile.exists()) {
FileInputStream fis = new FileInputStream(classFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = fis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
return defineClass(className, bos.toByteArray(), 0, bos.size());
}
} catch (Exception e) {
e.printStackTrace();
}
}
return super.findClass(name);
}
}
测试:
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
Iron iron = new Iron();
Sweetheart sweetheart = new Sweetheart();
Marvel proxy = sweetheart.getInstance(iron);
System.out.println(proxy.getClass());
proxy.attackBadPerson();
proxy.getSlogan();
proxy.getSlogan1("1号测试");
List<String> list = new ArrayList<>();
list.add("2号测试1");
list.add("2号测试2");
proxy.getSlogan2(list);
proxy.getSlogan3(new String[]{"3号测试1", "3号测试2"});
proxy.getSlogan4(new int[]{2, 4, 5, 6});
proxy.getSlogan5(new double[]{2.1, 4.4, 2.0});
proxy.getSlogan6("6号测试", 6);
proxy.getSlogan7();
}
}
测试结果:
class com.ByteDance.proxy.$Proxy0
攻击灭霸
爱你不止三千遍
1号:string
2号:list集合
3号:string数组
4号:int数组
5号:double数组
6号:String,int两个参数
7号:返回类型为list集合