对于动态代理生疏的同学可以先看看,这篇文章:https://www.jianshu.com/p/6729457d0509
动态代理的核心就是通过字节码动态生成代理类,思路如下:
1.手动生成动态代理类的java文件
2.通过代码动态编译手动生成的动态代理类
3.将编译好的动态代理类加载到虚拟机中
代码如下
目标类
package com.swh.design.proxy.handwritingproxy;
/**
* 被代理类接口
*/
public interface Person {
void findJob();
// 新增方法
void findLove();
}
package com.swh.design.proxy.handwritingproxy;
/**
* 原始类
*/
public class XiaoMing implements Person {
@Override
public void findJob() {
System.out.println("---小明面试---");
}
// 新增方法实现
@Override
public void findLove() {
System.out.println("---坠入爱河---");
}
}
代理类的创建
package com.swh.design.proxy.handwritingproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理类
*/
public class JdkProxy implements MyselfInvocationHandler {
private Person person;
public JdkProxy(Person person) {
this.person = person;
}
public Object newProxy(){
return MyselfProxy.newProxyInstance(new MyselfClassLoader(),person.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("---在被代理类执行之前干点坏事---");
Object invoke = method.invoke(person, args);
System.out.println("---在被代理类执行之后干点坏事---");
return invoke;
}
}
package com.swh.design.proxy.handwritingproxy;
import java.lang.reflect.Method;
public interface MyselfInvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
package com.swh.design.proxy.handwritingproxy;
import java.io.*;
/**
* 类加载器用于加载类文件
*/
public class MyselfClassLoader extends ClassLoader {
private File classPathFile;
public MyselfClassLoader() {
String path = MyselfClassLoader.class.getResource("").getPath();
this.classPathFile = new File(path);
}
/**
* 这个方法获取编译好的动态代理.class文件 并加载到虚拟机中
* @param name
* @return
* @throws ClassNotFoundException
*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (classPathFile == null) return null;
String className = MyselfClassLoader.class.getPackage().getName() + "." + name;
File file = new File(classPathFile, name + ".class");
//File file1 = new File("E:\\design_patterns\\design_patterns\\src\\main\\java\\com\\swh\\design\\proxy\\handwritingproxy\\Proxy$0.java");
FileInputStream inIo = null;
ByteArrayOutputStream out = null;
try {
if (file.exists()) {
inIo = new FileInputStream(file);
out = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = inIo.read(bytes)) != -1) {
out.write(bytes, 0, len);
}
// 把.class文件加载到虚拟机中,并返回Class对象
return defineClass(className, out.toByteArray(), 0, out.size());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(inIo!=null){
try {
inIo.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
package com.swh.design.proxy.handwritingproxy;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyselfProxy {
private static final String WRAP = "\r\n";
public static Object newProxyInstance(MyselfClassLoader loader,
Class<?>[] interfaces,
MyselfInvocationHandler h) {
//手动生成动态代理类java文件的代码字符串
String generateProxy = generateProxy(interfaces);
// 获取当前文件夹的路径
String path = MyselfProxy.class.getResource("").getPath() + "Proxy$0.java";
FileWriter fileWriter = null;
StandardJavaFileManager standardFileManager = null;
try {
// 生成java文件
fileWriter = new FileWriter(path);
fileWriter.write(generateProxy);
fileWriter.flush();
// 编译java文件
JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(path);
JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
task.call();
//把编译好的java文件加载到JVM中
Class<?> proxy$0 = loader.findClass("Proxy$0");
Constructor<?> constructor = proxy$0.getConstructor(MyselfInvocationHandler.class);
//删除虚拟代理类
File file = new File(path);
file.delete();
// 通过反射创建动态代理类
return constructor.newInstance(h);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(fileWriter!=null){
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(standardFileManager!=null){
try {
standardFileManager.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
// 生成动态代理类的java文件
private static String generateProxy(Class<?>[] interfaces) {
StringBuilder spliceProxy = new StringBuilder();
spliceProxy.append("package com.swh.design.proxy.handwritingproxy;" + WRAP + WRAP);
spliceProxy.append("import java.lang.reflect.Method;"+WRAP);
// 实现目标类的接口是为了生成动态代理类后能够使用目标类来接收,并可以使用目标类来调用目标类的方法
spliceProxy.append("public class Proxy$0 implements " + interfaces[0].getName() + " {" + WRAP);
spliceProxy.append("private MyselfInvocationHandler h;" + WRAP);
spliceProxy.append("public Proxy$0(MyselfInvocationHandler h){" + WRAP);
spliceProxy.append("this.h=h;}" + WRAP);
Method[] methods = interfaces[0].getMethods();
for (Method method : methods) { // 循环处理目标类的中方法 进行代理,并实现接口中的方法进行重写
spliceProxy.append("public " + method.getReturnType().getName() + " " + method.getName() + "(){" + WRAP);
spliceProxy.append("try{"+WRAP);
spliceProxy.append("Method m=" + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\",new Class[]{});" + WRAP);
// 调用JdkProxy类的invoke 方法 ,invoke方法加上额外功能后调用目标类的方法
spliceProxy.append("this.h.invoke(this,m,null);" + WRAP);
spliceProxy.append("}catch (Throwable e) {"+WRAP);
spliceProxy.append("e.printStackTrace();"+WRAP);
spliceProxy.append("}"+WRAP);
spliceProxy.append("}" + WRAP);
}
spliceProxy.append("}" + WRAP);
return spliceProxy.toString();
}
}
package com.swh.design.proxy.handwritingproxy;
public class JdkClient {
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy(new XiaoMing());
// 获取到动态代理类
Person o = (Person) jdkProxy.newProxy();
// 调用动态代理方法
o.findLove();
}
}