Java设计模式-动态代理
【设计模式】Java设计模式 - 动态代理
😄 不断学习才是王道
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 一个有梦有戏的人 @怒放吧德德
🌝最近工作比较忙,没啥时间学习
1、简介
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。动态代理就需要建立真实对象和代理对象关系,再去实现代理逻辑方法。
Java中实现动态代理有许多方法,JDK、CGLIB、Javassist、ASM,常用的是JDK和CGLIB,在spring中就是使用了这两种,然而mybatis还是用了Javassist。
2、JDK动态代理
提供简单的接口类以及其实现类,在通过建立真是对象与代理对象的关系,并且实现代理逻辑。
(1)、准备接口类
先提供接口类:
HelloWorldService:
1 | package com.lyd.demo.service; |
HelloWorldServiceImpl:
1 | package com.lyd.demo.service.impl; |
(2)、jdk动态代理
在JDK动态代理中,通过bind将真实对象和代理对象绑定起来,实现代理逻辑就要去实现java.lang.reflect.InvocationHandler接口,并且去实现invoke方法
①、首先需要声明 bind 方法去建立真实对象与代理对象的关系,把本类中的target保存真实对象。在通过Proxy的newProxyInstance方法来建立并生成对象,target.getClass().getClassLoader():target本身的类加载器,target.getClass().getInterfaces():把生成的动态代理对象下挂在接口中,this:当前对象,是定义实现方法逻辑的代理类。
②、实现InvocationHandler类中的invoke方法,可以实现代理逻辑,当我们使用了代理对象调度方法后就会进入到invoke方法中。
代码如下:
1 | package com.lyd.demo.jdk; |
(3)、实例
测试jdk动态代理
通过 HelloWorldService proxy = (HelloWorldService) jdkProxyExample.bind(new HelloWorldServiceImpl()); 去代理对象,然后就是使用proxy去点接口里面的方法了。
代码如下:
1 | package com.lyd.demo.test; |
实验结果
可以带入参数:以下是带入参数的例子
在接口中的方法添加参数
1 | public void sayHelloWorld(String name); |
在实现类的实现方法中打印出来
1 | System.out.println("Hello World! " + name); |
调用方法的时候添加参数
1 | // 调用方法 |
代理模式十分重要,要理解里面的逻辑,可以通过debug打断点去一步一步查看。
3、CGLIB 动态代理
JDK动态代理需要接口才能完成,而如果不提供接口,只有实现的方法类,可以使用三方插件CGLIB来动态代理,采用这个动态代理技术,需要引入三方jar包,可以搭建maven项目,引入CGLIB jar包 ,通过maven官网搜索添加,亦可以直接下载jar文件。
(1)、加入CGLIB依赖
maven引入依赖:
1 | <!-- https://mvnrepository.com/artifact/cglib/cglib --> |
(2)、准备实现类
准备一个实现类,cglib不需要接口,只要实现就可以:
1 | package com.lyd.demo.impl; |
(3)、代理类
代理类需要MethodInterceptor去实现方法
这里使用了增强者enhancer,通过设置超类和使用setCallback方法设置代理类,CGLIB是通过invokeSuper方法代理逻辑的。
1 | package com.lyd.demo.cglib; |
(4)、实例
测试:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package com.lyd.demo.test;
import com.lyd.demo.cglib.CglibProxyExample;
import com.lyd.demo.impl.HelloWorldServiceImpl;
/**
* @Author: lyd
* @Description: 测试CGLIB
* @Date: 2022-08-17
*/
public class CGLIBProxyTest {
public static void main(String[] args) {
CglibProxyExample cglibProxyExample = new CglibProxyExample();
HelloWorldServiceImpl proxy = (HelloWorldServiceImpl) cglibProxyExample.getProxy(HelloWorldServiceImpl.class); // 获取对象,可以不需要接口类
proxy.sayHelloWorld("lyd");
}
}
结果