参考:代理模式Proxy Pattern
不用JDK的动态代理,手写JDK动态代理
在程序运行阶段,在内存中动态生成代理类,被称为动态代理,目的是为了减少代理类的数量。解决代码复用的问题。
在内存当中动态生成类的技术常见的包括:
CGLIB既可以代理接口,又可以代理类。底层采用继承的方式实现。所以被代理的目标类不能使用final修饰。
使用CGLIB,需要引入它的依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
使用CGLIB代理类
创建一个目标类:
/**
* 目标类,不是接口了
*/
public class TargetClass{
public void sayHi(){
System.out.println("Hi,动态 CGLEIB proxy");
}
}
创建一个调用处理器类:
在CGLIB当中不是InvocationHandler接口,是方法拦截器接口:MethodInterceptor
实现的不是invoke方法了,是intercept方法
intercept有一个目标对象的值,所以这个类不需要依赖目标对象了
intercept方法有四个参数:
target:目标对象
method:目标方法
objects:目标方法参数
methodProxy:代理方法
public class ProxyClass implements MethodInterceptor {
/**
*
* @param target 目标对象
* @param method 目标方法
* @param objects 目标方法参数
* @param methodProxy 代理方法
* @return 代理类
* @throws Throwable
*/
@Override
public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//方法调用之前功能增强
System.out.println("目标方法执行前。。。。");
Object result = methodProxy.invokeSuper(target,objects);//该方法真正调用目标方法
//方法调用之后功能增强
System.out.println("目标方法执行后。。。。");
return result;
}
}
编写测试程序:
使用CGLIB在内存中为目标类生成代理类,并创建对象,有以下几个步骤:
1.创建字节码增强器对象Enhancer
这个对象是CGLIB库当中的核心对象,需要依靠它来生成代理类
2.调用setSuperclass方法设置目标类/接口
3.调用setCallback方法设置回调(等同于JDK动态代理当中的调用处理器InvocationHandler)
4.调用create方法创建代理对象
这一步会做两件事:
public class Client {
public static void main(String[] args) {
//1.创建字节码增强器对象
Enhancer enhancer = new Enhancer();
//2.设置目标类/接口
enhancer.setSuperclass(TargetClass.class);
//3.设置回调(等同于JDK动态代理当中的调用处理器InvocationHandler)
enhancer.setCallback(new ProxyClass());
//4.创建代理对象
TargetClass targetClass = (TargetClass)enhancer.create();
targetClass.sayHi();
}
}
运行程序:出现错误
原因是jdk8版本之后有了java.base这个包,jdk8版本之前没有,导致找不到。
需要加这两个参数
–add-opens java.base/java.lang=ALL-UNNAMED
–add-opens java.base/sun.net.util=ALL-UNNAMED
第一步:点击右上方进行编辑配置
第二步:点击修改选项,勾选添加VM选项
第三步:添加两个参数,保存
再次运行:运行成功