先看代码实现然后我们去剖析源码
1、还是需要去创建我们需要代理的代理类的接口和实现
service
public interface OrderService {
void test() throws Throwable;
}
impl
public class OrderServiceImpl implements OrderService {
@Override
public void test() {
System.out.println("【Test】");
}
}
2、我们知道JDK动态代理是需要去实现一个InvocationHandler接口那么接下来我们就去自定义一个自己的InvocationHandler接口和创建对应的实现
/**
* @Description:
* @ClassName design_pattern
* @Author: 王瑞文
* @Date: 2021/1/16 10:50
*/
public interface MyInvocationHandler {
/**
*
* @param proxy 代理类
* @param method 代理方法(目标方法)
* @param args 参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
接口实现/代理操作实现
/**
* @Description:
* @ClassName design_pattern
* @Author: 王瑞文
* @Date: 2021/1/16 10:51
*/
public class MyInvocationHandlerImpl implements MyInvocationHandler {
//目标对象(被代理类)
private Object target;
public MyInvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("手写动态代理开始");
Object invoke = method.invoke(target, args);//使用java的反射技术执行
System.out.println("手写动态代理结束");
return invoke;
}
}
3.写自己的Proxy
public class MyProxy {
static String rt = "\r\t";
/**
* @param myJavaClassLoader 自己写的类加载器
* @param classInfo
* @param h 自己写的MyInvocationHandler
* @return
* @throws IllegalArgumentException
*/
public static Object newProxyInstance(MyJavaClassLoader myJavaClassLoader, Class classInfo, MyInvocationHandler h)//修改成自己写的MyInvocationHandler
throws IllegalArgumentException {
try {
//1.拼接JAVA代理类的源代码
Method[] methods = classInfo.getMethods();
String proxyClass = "package 纯手写JDK动态代理;" + rt //包名
+ "import java.lang.reflect.Method;" + rt
+ "import 纯手写JDK动态代理.MyInvocationHandler;" + rt //我们自己的handler
+ "public class $Proxy0 implements " + classInfo.getName() + "{" + rt
+ "MyInvocationHandler h;" + rt
+ "public $Proxy0(MyInvocationHandler h)" + "{" + rt
+ "this.h= h;" + rt + "}"
+ getMethodString(methods, classInfo) + rt + "}";
// 2. 将代理类源码文件写入硬盘中
String filename = "d:/test/$Proxy0.java";
File f = new File(filename);
FileWriter fw = new FileWriter(f);
fw.write(proxyClass);
fw.flush();
fw.close();
//3.将源代码去编译成.class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(filename);
JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
//4.使用ClassLoader加载到内存中
Class proxy0Class = myJavaClassLoader.findClass("$Proxy0");//调用提前写好的自己的类加载器
//5.指明初始化有参数构造函数
Constructor constructor = proxy0Class.getConstructor(MyInvocationHandler.class);
Object o = constructor.newInstance(h);
return o;
} catch (Exception e) {
System.out.println("出现异常");
}
return null;
}
public static String getMethodString(Method[] methods, Class intf) {
String proxyMe = "";
for (Method method : methods) {
proxyMe += "public void " + method.getName() + "() throws Throwable {" + rt
+ "Method md= " + intf.getName() + ".class.getMethod(\"" + method.getName()
+ "\",new Class[]{});" + rt
+ "this.h.invoke(this,md,null);" + rt + "}" + rt;
}
return proxyMe;
}
}
4.自定义类加载器去加载我们自定义的MyProxy生成的$Proxy0文件
public class MyJavaClassLoader extends ClassLoader {
private File classPathFile;
public MyJavaClassLoader() {
// String classPath=JavaClassLoader.class.getResource("").getPath();
String classPath = "D:\\test";
this.classPathFile = new File(classPath);
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
String className = MyJavaClassLoader.class.getPackage().getName() + "." + name;
if (classPathFile != null) {
File classFile = new File(classPathFile, name.replaceAll("\\.", "/") + ".class");
if (classFile.exists()) {
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(classFile);
out = new ByteArrayOutputStream();
byte[] buff = new byte[1024];
int len;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
return defineClass(className, out.toByteArray(), 0, out.size());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
5.测试
public class Test001 {
public static void main(String[] args) throws NoSuchMethodException {
OrderService orderService = (OrderService) MyProxy.newProxyInstance(new MyJavaClassLoader(), OrderService.class, new MyInvocationHandlerImpl(new OrderServiceImpl()));
try {
orderService.test();
} catch (Throwable throwable) {
}
}
}
接下来说一下实现的思路:
1、使用JAVA语言组装$proxy0源码,在上边MyProxy中可以看出来我们使用的时字符串去拼接一个代理类的源代码,使用java的反射技术获取该接口下面所有方法
2、将 $proxy.java代理类的源代码编译成 $proxy0.class文件 JavaCompiler技术,类似于命令行输入javac
3、使用ClassLoader把class文件加载到内存中去