手写JDK动态代理
1、动态代理概述
概述
-
JAVA动态代理与静态代理相对,静态代理是在编译期就已经确定代理类和真实类的关系,并且生成代理类的。而动态代理是在运行期利用JVM的反射机制生成代理类,这里是直接生成类的字节码,然后通过类加载器载入JAVA虚拟机执行。现在主流的JAVA动态代理技术的实现有两种:一种是JDK自带的,就是我们所说的JDK动态代理,另一种是开源社区的一个开源项目CGLIB。本文主要对JDK动态代理做讨论。
-
JDK动态代理的实现是在运行时,根据一组接口定义,使用Proxy、InvocationHandler等工具类去生成一个代理类和代理类实例。
JDK动态代理的类关系模型和静态代理看起来差不多。也是需要一个或一组接口来定义行为规范。需要一个代理类来实现接口。区别是没有真实类,因为动态代理就是要解决在不知道真实类的情况下依然能够使用代理模式的问题。
分类
- JDK的动态代理: 与被代理的类必须实现相同的接口
- CGLIB: 继承
动态代理几个重要的参数
-
ClassLoader loader: 被代理对象的类加载器
-
Class<?>[] interfaces:接口中的使用方法。
-
InvocationHandler: 处理,加强方法 【invoke()方法】
2、手写动态代理
共同实现的接口
package com.qiumin.proxy;
/**
* @author qiumin
* @classname Service
* @Description love code
* @date 2022-06-06 21:36
*/
public interface Service {
/**
* 接口方法
* */
void order() throws Throwable;
}
被代理的类
package com.qiumin.proxy;
/**
* @author qiumin
* @classname orderService
* @Description love code
* @date 2022-06-06 21:36
*/
public class orderService implements Service{
/**
* 方法
* */
public void order() {
System.out.println("《订单编号1000101》");
}
}
自己的MyExtJdkInvocationHandler接口,与InvocationHandler几乎一样
package com.qiumin.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author qiumin
* @classname MyJdkIN
* @Description love code
* @date 2022-06-06 21:29
*/
public interface MyExtJdkInvocationHandler {
Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
MyJdkInvocationHandler实现MyExtJdkInvocationHandler
package com.qiumin.proxy;
import java.lang.reflect.Method;
/**
* @author qiumin
* @classname MyJdkInvocationHandler
* @Description love code
* @date 2022-06-06 21:34
*/
public class MyJdkInvocationHandler implements MyExtJdkInvocationHandler{
/**
* 被代理的目标对象
* */
private Object target;
public MyJdkInvocationHandler(Object target) {
this.target = target;
}
/**
* 加强被代理类的方法
* */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("正在生成订单中......");
method.invoke(target,args);
System.out.println("生成订单完打印票据......");
return null;
}
}
手写内存中创建的代理类
package com.qiumin.proxy;
import java.lang.reflect.Method;
/**
* @author qiumin
* @classname MyProxy
* @Description love code
* @date 2022-06-06 21:41
*/
public class MyProxy implements Service{
/**
* 处理类
* */
private MyJdkInvocationHandler h;
public MyProxy(MyJdkInvocationHandler h) {
this.h = h;
}
/**
*
* 回调加强方法
* */
public void order() throws Throwable {
//反射获取接口中的方法
Method method = Service.class.getMethod("order",new Class[]{});
this.h.invoke(this,method,null);
}
}
测试
package com.qiumin.proxy;
/**
* @author qiumin
* @classname TestProxy
* @Description love code
* @date 2022-06-06 21:47
*/
public class TestProxy {
public static void main(String[] args) throws Throwable {
//new出MyProxy的对象,将自己的InvocationHandler传进去
MyProxy myProxy = new MyProxy(new MyJdkInvocationHandler(new orderService()));
//执行方法
myProxy.order();
}
}
3、总结
总结
- 使用Java程序语言组装
.java
源代码,获取实现的接口反射获取。【上面是固定的代理类,使用该方法扩展性强】 - 用Java程序语言将
.java
文件编译生成字节码文件.class
,相当于命令行输入javac。 - 使用classloader技术将生成的class文件加载到内存中即java虚拟机中,这样才可以执行。
- 以上就是
Proxy.newProxyInstance()底层的原理
。
qiumin