1. 首先定义一个 InvocationHandler 实例,它负责实现接口的方法调用2. 通过 Proxy.newProxyInstance() 创建 interface 实例,它需要 3 个参数:(1)使用的 ClassLoader,通常就是接口类的 ClassLoader(2)需要实现的接口数组,至少需要传入一个接口进去;(3)用来处理接口方法调用的 InvocationHandler 实例 。3. 将返回的 Object 强制转型为接口
动态代理实际上是 JVM 在运行期动态创建class字节码并加载的过程,它并没有什么黑魔法技术,把上面的动态代理改写为静态实现类大概长这样:
public class JdkCalculatorDynamicProxy implements JdkCalculator {private InvocationHandler handler;public JdkCalculatorDynamicProxy(InvocationHandler handler) {this.handler = handler;}public void add(Integer num1, Integer num2) {handler.invoke(this,JdkCalculator.class.getMethod("add", Integer.class, Integer.class),new Object[] { num1, num2 });}}
本质就是 JVM 帮我们自动编写了一个上述类(不需要源码,可以直接生成字节码) 。
3.2、cglib 生成代理对象的玩法除了 jdk 能实现动态的创建代理对象以外,还有一个非常有名的第三方框架:cglib,它也可以做到运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展 。
cglib 特点如下:
- cglib 不仅可以代理接口还可以代理类,而 JDK 的动态代理只能代理接口
- cglib 是一个强大的高性能的代码生成包,它广泛的被许多 AOP 的框架使用,例如我们所熟知的 Spring AOP,cglib 为他们提供方法的 interception(拦截) 。
- CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类,速度非常快 。
cglib cglib3.2.5
下面,我们还是以两数相加为例,介绍具体的玩法!
- 创建接口
public interface CglibCalculator {/*** 计算两个数之和* @param num1* @param num2* @return*/Integer add(Integer num1, Integer num2);}
- 目标对象
public class CglibCalculatorImpl implements CglibCalculator {@Overridepublic Integer add(Integer num1, Integer num2) {Integer result = num1 + num2;return result;}}
- 动态代理对象
public class CglibProxyFactory implements MethodInterceptor {/*** 维护一个目标对象*/private Object target;public CglibProxyFactory(Object target) {this.target = target;}/*** 为目标对象生成代理对象* @return*/public Object getProxyInstance() {//工具类Enhancer en = new Enhancer();//设置父类en.setSuperclass(target.getClass());//设置回调函数en.setCallback(this);//创建子类对象代理return en.create();}@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("方法调用前,可以添加其他功能....");// 执行目标对象方法Object returnValue = https://www.goobye.net/method.invoke(target, args);System.out.println("方法调用后,可以添加其他功能....");return returnValue;}}
- 测试类
public class TestCglibProxy {public static void main(String[] args) {//目标对象CglibCalculator target = new CglibCalculatorImpl();System.out.println(target.getClass());//代理对象CglibCalculator proxyClassObj = (CglibCalculator) new CglibProxyFactory(target).getProxyInstance();System.out.println(proxyClassObj.getClass());//执行代理方法Integer result = proxyClassObj.add(1,2);System.out.println("相加结果:" + result);}}
- 输出结果
class com.example.java.proxy.cglib1.CglibCalculatorImplclass com.example.java.proxy.cglib1.CglibCalculatorImpl$EnhancerByCGLIB$3ceadfe4方法调用前,可以添加其他功能....方法调用后,可以添加其他功能....相加结果:3
将 cglib 生成的代理类改写为静态实现类大概长这样:
public class CglibCalculatorImplByCGLIB extends CglibCalculatorImpl implements Factory {private static final MethodInterceptor methodInterceptor;private static final Method method;public final Integer add(Integer var1, Integer var2) {return methodInterceptor.intercept(this, method, new Object[]{var1, var2}, methodProxy);}//....}
其中,拦截思路与 JDK 类似,都是通过一个接口方法进行拦截处理!
在上文中咱们还介绍到了,cglib 不仅可以代理接口还可以代理类,下面我们试试代理类 。
- 创建新的目标对象
- DNF手游韩服可预约 DNF手游预约
- 却不知道到底在隔离什么 隔离到底是什么
- 发音为什么和闽南语不一样 闽南语和普通话发音区别
- 常任理事国为什么会有一票否决权 常任理事国一票否决权是什么意思
- 南京是江苏省会 南京是江苏省会 位于
- 这些动漫中的cp 动漫是什么
- 越是爱你的男人 越是爱你的男人越容易离开你
- 家用电烤箱排行榜 电烤炉什么牌子好
- 冰咖啡会减肥吗,日本有什么减肥咖啡
- 脚底下长痣代表什么