0x01 前言
JDK动态代理与Cglib代理的区别
JDK 动态代理:
拦截器实现InvocationHandler
接口,加上反射机制生成一个实现代理接口的匿名类
在调用具体方法前调用InvokeHandler
来处理,自身额外操作
Cglib代理:
利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理
JDK动态代理与Cglib字节码生成的区别?
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的
0x02 环境
编辑器为: IntelliJ IDEA
java版本:
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)
使用的架包:
cglib 3.3.0
代码仓库: https://github.com/pmiaowu/JavaProxyTest
0x03 语法介绍
0x03.1 MethodInterceptor接口
package net.sf.cglib.proxy;
import java.lang.reflect.Method;
public interface MethodInterceptor extends Callback {
/**
* @param var1 被代理的对象
* @param var2 被代理对象的方法
* @param var3 参数集合
* @param var4 生成的代理类
* @return
* @throws Throwable
*/
Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}
0x04 例子
例如现在有一个人,想去影院看电影,看完电影顺便去上个厕所
但是我们作为电影院的人,还想产生一些额外的收益
比如在影片开始与结束时播发一些广告
或是去洗手间的时候播发一些广告
先建立个人的行为类
package 动态代理2;
public class People {
public void movie() {
System.out.println("您正在观看电影《花园宝宝历险记》");
}
public void toilet() {
System.out.println("您冲进了洗手间");
}
}
在建立个电影院提供用户最爱的广告
package 动态代理2;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class Cinema implements MethodInterceptor {
private Object target;
public Object bind(Object target) {
this.target = target;
// 工具类
Enhancer en = new Enhancer();
// 设置父类
en.setSuperclass(target.getClass());
// 设置回调函数
en.setCallback(this);
// 创建子类代理对象
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(" ");
System.out.println("------------------");
System.out.println("该影院叫: " + this.getClass().getSimpleName());
this.advertising1();
Object obj = method.invoke(this.target);
this.advertising2();
return obj;
}
public void advertising1() {
System.out.println("开始广告: 电影准备开始了,肯德基十翅一桶,只需要39元,快来买啊!");
}
public void advertising2() {
System.out.println("结束广告: 电影结束了,肯德基十翅一桶,只需要39元,快买回家吃吧!");
}
}
运行看看结果
package 动态代理2;
public class Test {
public static void main(String[] args) {
People people = new People();
Cinema cinema = new Cinema();
People peopleProxy = (People) cinema.bind(people);
peopleProxy.movie();
peopleProxy.toilet();
}
}
// 执行结果
------------------
该影院叫: Cinema
开始广告: 电影准备开始了,肯德基十翅一桶,只需要39元,快来买啊!
您正在观看电影《花园宝宝历险记》
结束广告: 电影结束了,肯德基十翅一桶,只需要39元,快买回家吃吧!
------------------
该影院叫: Cinema
开始广告: 电影准备开始了,肯德基十翅一桶,只需要39元,快来买啊!
您冲进了洗手间
结束广告: 电影结束了,肯德基十翅一桶,只需要39元,快买回家吃吧!