1 概念
# 代理模式:
1 二十三种设计模式中的一种,属于结构型模式
2 实现:当需要调用目标方法的时候,不直接调用目标方法,而是通过代理类间接调用
3 好处
让附加功能代码从目标方法中剥离出来----解耦
集中附加功能代码,方便统一维护
2 代理
目标类
public interface Calculator {
int add(int lnum,int rnum);
int sub(int lnum,int rnum);
int mul(int lnum,int rnum);
int div(int lnum,int rnum);
}
public class Target implements Calculator {
/**
* 目标类:
* 实现加减乘除
*/
@Override
public int add(int lnum, int rnum) {
System.out.println("目标代码:(lnum + rnum)=" + (lnum + rnum));
return lnum + rnum;
}
@Override
public int sub(int lnum, int rnum) {
System.out.println("目标代码:(lnum - rnum)=" + (lnum - rnum));
return lnum - rnum;
}
@Override
public int mul(int lnum, int rnum) {
System.out.println("目标代码:(lnum * rnum)=" + (lnum * rnum));
return lnum * rnum;
}
@Override
public int div(int lnum, int rnum) {
System.out.println("目标代码:(lnum / rnum)=" + (lnum / rnum));
return lnum / rnum;
}
}
静态代理类
public class ProxyCla implements Calculator{
/**
*静态代理:
* 一个目标类对应一个静态代理类
*/
Target target=new Target();
@Override
public int add(int lnum, int rnum) {
System.out.println("日志_参数:=====>"+lnum+","+rnum);
int res = target.add(lnum, rnum);
System.out.println("日志_结果:=====>"+res);
return res;
}
@Override
public int sub(int lnum, int rnum) {
System.out.println("日志_参数:=====>"+lnum+","+rnum);
int res = target.sub(lnum, rnum);
System.out.println("日志_结果:=====>"+res);
return res;
}
@Override
public int mul(int lnum, int rnum) {
System.out.println("日志_参数:=====>"+lnum+","+rnum);
int res = target.mul(lnum, rnum);
System.out.println("日志_结果:=====>"+res);
return res;
}
@Override
public int div(int lnum, int rnum) {
System.out.println("日志_参数:=====>"+lnum+","+rnum);
int res = target.div(lnum, rnum);
System.out.println("日志_结果:=====>"+res);
return res;
}
}
静态代理类测试结果
日志_参数:=====>1,1
目标代码:(lnum + rnum)=2
日志_结果:=====>2
日志_参数:=====>3,-1
目标代码:(lnum - rnum)=4
日志_结果:=====>4
日志_参数:=====>25,25
目标代码:(lnum * rnum)=625
日志_结果:=====>625
日志_参数:=====>120,4
目标代码:(lnum / rnum)=30
日志_结果:=====>30
静态代理的弊端
静态代理确实实现了 代理模式的目标----解耦
静态代理的代码是写死的:
1 静态代理类实现和目标类同样的借口,导致一个目标类需要一个静态代理类
2 静态代理类中的目标对象也是写死的
导致的后果:
产生大量重复的代码,附加功能代码还是分散的,并没有实现对附加代码的统一管理
JDK动态代理
通过JDK 提供的 API 在程序运行的过程中,动态得去生成每一个目标类所对应的动态代理类
java.lang.reflect.Proxy类提供了为对象产生代理对象的方法
三大参数
# 参数1 classloder 类加载器
为什么需要指定类加载器?
答:动态代理的作用就是在程序的运行过程中动态的生成 目标类的 动态代理类,生成完毕之后类需要加载。
类加载器有哪几种
答:
1 根类加载器
底层是使用C实现,加载核心类库
2 扩展类加载器
加载扩展类库
3 应用类加载器
加载 自己写的类库、第三方类库
如何获取类加载器:
答:通过反射获取,获取Class字节码文件对象,在通过其获取类加载器
# 参数2 Class[ ] interfaces 实现的所有接口
原则:目标类和代理类需要实现相同的接口
答:参数2就是来获取目标对象实现的所有接口的Class字节码对象数组
# 参数3 InvocationHandler接口 -------执行处理
答:定义代理类中抽象方法的重写细节,即附加代码编写的地方。使用匿名内部类写附加代码。
答:一共三个部分:
1 proxy 表示代理对象
2 method 表示要执行的方法
3 args 表示要执行的方法的参数列表
工厂类:动态生成代理类对象
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target){
this.target=target;
}
public Object getProxy(){
/**
* JDK代理三大参数:
* ClassLoader,Class[] interfaces,InvocationHandler
*/
return java.lang.reflect.Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理日志:==========>:操作名:"+method.getName()+",参数:"+ Arrays.toString(args));
Object res = method.invoke(target, args);
System.out.println("动态代理日志:==========>:结果:"+res);
retur![在这里插入图片描述](https://img-blog.csdnimg.cn/4c9fbb962bab4aa18b489a590bd832c6.png#pic_center)
n res;
}
}
);
}
}
JDK动态代理测试结果
@SpringBootTest
class ProxydemoApplicationTests {
@Test
void contextLoads() {
ProxyFactory proxyFactory = new ProxyFactory(new Target());
Calculator proxy =(Calculator) proxyFactory.getProxy();
proxy.add(1,1);
proxy.sub(4,-1);
proxy.mul(25,27);
proxy.div(120,3);
}
}
动态代理日志:==========>:操作名:add,参数:[1, 1]
目标代码:(lnum + rnum)=2
动态代理日志:==========>:结果:2
动态代理日志:==========>:操作名:sub,参数:[4, -1]
目标代码:(lnum - rnum)=5
动态代理日志:==========>:结果:5
动态代理日志:==========>:操作名:mul,参数:[25, 27]
目标代码:(lnum * rnum)=675
动态代理日志:==========>:结果:675
动态代理日志:==========>:操作名:div,参数:[120, 3]
目标代码:(lnum / rnum)=40
动态代理日志:==========>:结果:40
cglib动态代理和JDK动态代理的区别
1 JDK动态代理,要求必须有借口,最终生成的代理类在,com.sun.proxy包下
类名为:$proxy2($proxy+数字,此处以2示范)
除此之外,JDK动态代理,生成的动态代理类和目标类实现相同的接口
2 cglib动态代理,没有要求,最终生成的代理类有两大特性:
cglib动态代理生成的代理类会继承目标类
cglib动态代理生成的代理类和目标类在同一个包下
Proxy增强Target的地方
# 1 方法调用前
# 2 方法调用后
# 3 异常发生时
# 4 finally代码中
在这里插入图片描述