Java中动态代理与MyBatis框架的底层简单实现
博主大二计科学生一枚,正在学习MyBatis框架,在动态代理用Java动态代理机制简单实现MyBatis框架底层时遇到小困难,回去复习Java动态代理机制后,结合自己的理解和ai辅助,写下了这篇笔记方便大家复习后端开发技术,祝大家都能拿高薪、进大厂!
本篇笔记重点Java动态代理机制的详细讲解,已经Github上上传了用Java动态代理机制简单实现MyBatis框架底层
文中的图一、图三引用自黑马程序员的网课,图二引用彩虹糖广告图,如有侵权,本人立即删除
1.动态代理概念
-
为什么要有动态代理?
-
假如我们写了一个方法A,后续业务要求我们向这个方法中添加几个新功能B,C,之前我们往往采取的方法是侵入式修改,即在方法外部写好新功能B、C的方法,然后在再要添加功能的方法A中调用新功能方法B、C。
如:

-
这种侵入式修改代码的方法在体量小的项目中,可能无伤大雅,没有什么影响,但是如果是大项目,侵入式修改很可能造成修改一处整个项目崩溃的场景,就如下图这个经典广告

-
此时我们如何无侵入式的给代码添加新的功能呢?
-
这就要用到我们今天所学的动态代理
-
-
-
动态代理基础概念
-
定义:Java 中的动态代理(Dynamic Proxy)是一种在运行时动态创建代理类和代理对象的机制,常用于 AOP(面向切面编程)、日志记录、权限检查等场景。
-
什么是代理?
代理是一种设计模式,代理对象代替目标对象对外提供服务,控制对目标对象的访问。
-
静态代理:代理类在编译时就已经确定了(写死了)。
-
动态代理:代理类在运行时生成,目标对象也可以动态设置。
-
-
特点:
-
无侵入式的给代码添加新功能
-
通过创建的代理对象添加新功能,代理对象添加新功能之后,接着调用原有方法
-
-
动态代理的实现分为两种
-
基于JDK动态代理
-
基于GGLIB动态代理
-
-
2.JDK实现动态代理的思想
-
基于JDK的动态代理的五个核心
三类:被代理类、新增功能工具类、代理工具类
proxy两接口:代理方法接口、调用处理器接口(
InvocationHandler)一对象:由代理工具类
proxy创建出的代理对象详解既应用动态代理核心过程:
-
要为方法新增功能的类是被代理类,我们将其中所有要新增功能的方法抽象的一个接口中,这个接口便是代理方法接口(有时没有被代理类,直接为代理方法接口新增功能,如下文
mybatis框架中实现增删改查的底层原理) -
既然要为被代理类(或代理方法接口)中的方法新增功能,就需要一个工具类负责调用原方法和新增功能,这个工具类便是新增功能工具类,新增功能工具类实现调用处理器接口(
InvocationHandler),并重写其中的invoke方法来完成新增功能、调用原方法等功能 -
实现完无侵入式方法功能新增后,需要以一个对象来调用新增功能后的方法,这个对象便是由代理类工具类proxy创建出的代理对象(
对象类型是被代理类),要调用新增功能的方法,就要知道这个方法的原方法从哪里来(传参被代理类或代理方法接口的类加载器),要知道这个方法约束(传参代理方法接口数组),要知道新增功能后的方法从哪里来(传参代理工具类对象)
-
3.基于JDK的动态代理实现步骤
步骤一:被代理类将要添加新功能的方法,抽象出来,写到一个代理方法接口中,并且被代理类自己要继承。
-
注意:代理接口的访问权限,要使代理类能访问
-
//被代理类将要添加新功能的方法,抽象出来 public interface UserService { void login(String username, String password); void register(String username); } -
//被代理类自己要继承 public class UserServiceImpl implements UserService { public void login(String username, String password) { System.out.println(username + " 登录成功"); } public void register(String username) { System.out.println(username + " 注册成功"); } }
步骤二:创建新增功能工具类实现调用处理器接口,完成invoke方法重写
-
invoke方法参数解释
-
invoke方法参数一:被代理的对象,一般不会使用,按默认的就行
-
invoke方法参数二:被代理类中要被调用的未新增功能的原有方法
-
invoke方法参数三:调用原方法时传递的实参数组
-
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;
/*创建新增功能工具类实现调用处理器接口,完成invoke方法重写,实现新增功能、调用原方法*/
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
// 所有方法调用都会进入 invoke 方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法调用前:" + method.getName());
Object result = method.invoke(target, args); // 调用目标方法
System.out.println("方法调用后:" + method.getName());
return result;
}
}
步骤三:创建代理对象调用新增功能的方法
-
调用位于
java.lang.reflect包下的Proxy类的静态方法newProxyInstance-
newProxyInstance方法参数一:代理工具类的类加载器 -
newProxyInstance方法参数二:代理方法接口的Class对象数组(代理方法接口的字节码文件数组) -
newProxyInstance方法参数三:新增方法接口InvocationHandler的实现类对象 -
注意:创建代理对象方法的返回值Object是代理对象

import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { UserService realService = new UserServiceImpl(); UserService proxy = (UserService) Proxy.newProxyInstance( realService.getClass().getClassLoader(), realService.getClass().getInterfaces(), new MyInvocationHandler(realService) ); proxy.login("张三", "123456"); proxy.register("张三"); } }
-
4用动态代理手动编写MyBatis增删改查底层
该篇幅需要有一定maven项目管理、MyBatis框架、Java反射、泛型的基础,如果没有请跳过
该篇幅只介绍各个文件对应动态代理部分,
详细代码见Github--https://github.com/Simonchu-73/mybatis_learn/tree/master/mybatis_day03_custom
注:代码只用动态代理完成了MyBatis中查询SElECT * FROM student的底层,欢迎各位同僚继续补充
其他部分若有不懂地方可私信问
其中com.xzit.mapper路径下StudentMapper是要代理方法接口
其中com.xzit.util路径下ProxyImp是要新增功能工具类
其中com.xzit.util路径下CustomSqlSession是要中由代理工具类创建了代理对象
其中com.xzit.test路径下Test是要完成了功能测试
更多推荐


所有评论(0)