一、静态代理
设置一个场景,小明想买台宝马,但是他对车一无所知,所以他拜托了自己的好朋友小李帮忙,那么代码如下
他们都是人
/**
* 人类需求
*/
public interface People {
void need();
}
小明
/**
* 对车一无所知的小明
*/
public class Xiaoming implements People {
public void need() {
System.out.println("我要买宝马车");
}
}
小李加入了对车的新需求
/**
* 车中高玩
*/
public class Xiaoli implements People {
private Xiaoming xiaoming;
public Xiaoli(Xiaoming xiaoming) {
this.xiaoming = xiaoming;
}
public void need() {
System.out.println("一键启动,无钥匙进入");
xiaoming.need();
System.out.println("四个电吸门");
}
}
测试一下
public static void main(String[] args) {
People xiaoli = new Xiaoli(new Xiaoming());
xiaoli.need();
}
紧随着问题来了,小红觉得小李很厉害,也想让他帮忙买车并给了一笔巨款,
/**
* 小红
*/
public class Xiaohong implements People {
public void need() {
System.out.println("我要买粉色车");
}
}
但是小李觉得钱不钱的无所谓,主要是对于美女不能拒绝,但是考虑到可能小红还有闺蜜甲,乙,丙。。。等等,他渐渐的优点力不从心。他苦思冥想,觉得,为什么我不能做个车贩子呢,于是便有了
二、动态代理
1.JDK动态代理
1.1 代码
代码如下(示例):
/**
* 车贩子小李
*/
public class Jdkchefanzi implements InvocationHandler {
private People people;
public People getInstance(People people){
this.people=people;
Class<? extends People> clazz = people.getClass();
return (People) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始大数据搜索车辆");
Object invoke = method.invoke(people, args);
System.out.println("车辆匹配上");
return invoke;
}
}
测试一下
public static void main(String[] args) {
Jdkchefanzi Xiaohong = new Jdkchefanzi();
Xiaohong.getInstance(new Xiaohong()).need();
Jdkchefanzi xiaomin = new Jdkchefanzi();
xiaomin.getInstance(new Xiaoming()).need();
People xiaoli = new Xiaoli(new Xiaoming());
}
1.1 原理
那么它的原理是啥样的呢
通过debug我们可以看到,最后生成的一个对象时$proxy0,由他来执行我们的方法,然后我们把他生成一下看看
proxy
我们可以看到他继承了proxy实现了我们接口,在need()方法中调用了一个super.h.invoke(),这个h其实就是小明或者小红的那个类。这也说明了使用jdk代理必须得有接口且没有继承;但是吧,如何我继承了呢,如果我没有接口呢,我是个普通类呢,再加上我们知道,在java中使用反射是效率很低的一件事,所以我们换一种方式
2.CGLib动态代理
代码如下(示例):
/**
* 车贩子小李
*/
public class Cglibchefanzi implements MethodInterceptor {
static{
//这行代码的作用是将cglib生成的代码输出到f盘file目录里边
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F://file");
}
public Object getInstance(Class<?> clazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开始大数据搜索车辆");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("车辆匹配上");
return o1;
}
}
测试一下
没问题,然后我们来看看原理,去f盘看看cglib生成的文件
一共三个文件,分别是
- 代理类的fastclass
- 目标类
- 目标类的fastclass
那么fastclass技术是什么呢,简单来说就是给你的方法做不同的序号,例如说给你的toString()方法标志位1,我如果要调用的时候直接调用序号为1的方法即可,使用switch ()case 如网上这幅图
这就是fastclass技术。
注意看这个
所以说jdk是基于接口实现的,cglib是基于继承实现的。本质区别