[SSM]MyBatis使用javassist生成类和接口代理机制

news2025/1/10 16:44:12

目录

六、使用javassist生成类

6.1Javassist的使用

6.2使用Javassist生成DaoImpl类

七、MyBatis中接口代理机制及使用

7.1在之前的web应用中使用接口代理机制

7.2使用接口代理机制完成之前的CRUD(部分代码)


六、使用javassist生成类

6.1Javassist的使用

引入javassist依赖

<dependency>
 <groupId>org.javassist</groupId>
 <artifactId>javassist</artifactId>
 <version>3.29.1-GA</version>
</dependency>

测试

 @Test
    public void testGenerateFirstClass() throws Exception {
        //获取类池,这个类池就是用来生成class的
        ClassPool pool = ClassPool.getDefault();
        //制造类(需要告诉javassist类名是什么)
        CtClass ctClass = pool.makeClass("com.hhb.dao.impl.AccountDaoImpl");
        //制造方法
        String methodCode = "public void insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode, ctClass);
        //将方法添加到类中
        ctClass.addMethod(ctMethod);
        //在内存中生成class
        ctClass.toClass();
​
        //类加载到JVM中,返回AccountDaoImpl类的字节码
        Class<?> clazz = Class.forName("com.hhb.dao.impl.AccountDaoImpl");
        //创建对象
        Object obj = clazz.newInstance();
        //获取AccountDaoImpl中的insert方法
        Method insertMethod = clazz.getDeclaredMethod("insert");
        //调用方法insert
        insertMethod.invoke(obj);
    }

6.2使用Javassist生成DaoImpl类

GenerateDaoProxy

package com.hhb.utils;
​
import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtMethod;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.SqlSession;
​
import java.lang.reflect.Method;
import java.util.Arrays;
​
/**
 * 工具类:可以动态的生成DAO的实现类。(或者说可以动态生成DAO的代理类)
 * 注意注意注意注意注意!!!!!!:
 *      凡是使用GenerateDaoProxy的,SQLMapper.xml映射文件中namespace必须是dao接口的全名,id必须是dao接口中的方法名。
 */
public class GenerateDaoProxy { // GenerateDaoProxy是mybatis框架的开发者写的。
​
    /**
     * 生成dao接口实现类,并且将实现类的对象创建出来并返回。
     * @param daoInterface dao接口
     * @return dao接口实现类的实例化对象。
     */
    public static Object generate(SqlSession sqlSession, Class daoInterface){
        // 类池
        ClassPool pool = ClassPool.getDefault();
        // 制造类(com.powernode.bank.dao.AccountDao --> com.powernode.bank.dao.AccountDaoProxy)
        CtClass ctClass = pool.makeClass(daoInterface.getName() + "Proxy"); // 实际本质上就是在内存中动态生成一个代理类。
        // 制造接口
        CtClass ctInterface = pool.makeInterface(daoInterface.getName());
        // 实现接口
        ctClass.addInterface(ctInterface);
        // 实现接口中所有的方法
        Method[] methods = daoInterface.getDeclaredMethods();
        Arrays.stream(methods).forEach(method -> {
            // method是接口中的抽象方法
            // 将method这个抽象方法进行实现
            try {
                // Account selectByActno(String actno);
                // public Account selectByActno(String actno){ 代码; }
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public ");
                methodCode.append(method.getReturnType().getName());
                methodCode.append(" ");
                methodCode.append(method.getName());
                methodCode.append("(");
                // 需要方法的形式参数列表
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++) {
                    Class<?> parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
                    methodCode.append("arg" + i);
                    if(i != parameterTypes.length - 1){
                        methodCode.append(",");
                    }
                }
                methodCode.append(")");
                methodCode.append("{");
                // 需要方法体当中的代码
                methodCode.append("org.apache.ibatis.session.SqlSession sqlSession = com.powernode.bank.utils.SqlSessionUtil.openSession();");
                // 需要知道是什么类型的sql语句
                // sql语句的id是框架使用者提供的,具有多变性。对于我框架的开发人员来说。我不知道。
                // 既然我框架开发者不知道sqlId,怎么办呢?mybatis框架的开发者于是就出台了一个规定:凡是使用GenerateDaoProxy机制的。
                // sqlId都不能随便写。namespace必须是dao接口的全限定名称。id必须是dao接口中方法名。
                String sqlId = daoInterface.getName() + "." + method.getName();
                SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sqlId).getSqlCommandType();
                if (sqlCommandType == SqlCommandType.INSERT) {
​
                }
                if (sqlCommandType == SqlCommandType.DELETE) {
​
                }
                if (sqlCommandType == SqlCommandType.UPDATE) {
                    methodCode.append("return sqlSession.update(\""+sqlId+"\", arg0);");
                }
                if (sqlCommandType == SqlCommandType.SELECT) {
                    String returnType = method.getReturnType().getName();
                    methodCode.append("return ("+returnType+")sqlSession.selectOne(\""+sqlId+"\", arg0);");
                }
​
                methodCode.append("}");
                CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                ctClass.addMethod(ctMethod);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
​
        // 创建对象
        Object obj = null;
        try {
            Class<?> clazz = ctClass.toClass();
            obj = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
}

修改AccountMapper.xml文件:namespace必须是dao接口的全限定名称,id必须是dao接口中的方法名

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--要想使用GenerateDaoProxy,namespace必须是dao的全限定名称-->
<mapper namespace="com.hhb.dao.AccountDao">
    <!--要想使用GenerdateDaoProxy,id必须是dao的方法名-->
    <select id="selectByActno" resultType="com.hhb.pojo.Account">
        select * from t_act where actno = #{actno}
    </select>
​
    <update id="updateByActno">
        update t_act set balance = #{balance} where actno = #{actno}
    </update>
</mapper>

修改service类中获取dao对象

七、MyBatis中接口代理机制及使用

7.1在之前的web应用中使用接口代理机制

将service中获取dao对象的代码修改

 

前提:AccountMapper.xml文件中的namespace必须和dao接口的全限定名称一致,id必须和dao接口中方法名一致。否则报错提示如下:

 

7.2使用接口代理机制完成之前的CRUD(部分代码)

com.hhb.mapper.CarMapper

CarMapper相当于之前的CarDao。

package com.hhb.mapper;
​
import com.hhb.pojo.Car;
​
import java.util.List;
​
public interface CarMapper {
​
    int insert(Car car);
​
    int deleteById(Long id);
​
    int update(Car car);
​
    Car selectById(Long id);
​
    List<Car> selectAll();
}

测试

package com.hhb.test;
​
import com.hhb.mapper.CarMapper;
import com.hhb.pojo.Car;
import com.hhb.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
​
import java.util.List;
​
public class CarMapperTest {
    @Test
    public void testinsert() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        //面向接口获取接口的代理对象
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(null, "4444", "奔驰cls300", 65.0, "2023-06-05", "燃油车");
        int count = mapper.insert(car);
        System.out.println(count);
        sqlSession.commit();
    }
​
    @Test
    public void testDeleteById() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        int count = mapper.deleteById(10L);
        System.out.println(count);
        sqlSession.commit();
    }
​
    @Test
    public void testUpdate() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(28L, "1234", "奔驰cls300", 65.0, "2023-05-05", "燃油车");
        int count = mapper.update(car);
        System.out.println(count);
        sqlSession.commit();
    }
​
    @Test
    public void testSelectById() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = mapper.selectById(1L);
        System.out.println(car);
        sqlSession.commit();
    }
​
    @Test
    public void testSelectAll() {
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        List<Car> cars = mapper.selectAll();
        cars.forEach(car -> {
            System.out.println(car);
        });
    }
}
​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/717288.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

王道考研计算机网络第五章知识点汇总

5.1.1 传输层概述 复用&#xff1a;好比家里面每个人都要写信&#xff0c;向信箱里面投入信件&#xff0c;然后由邮递员取走。 分用&#xff1a;就是每个人都收到了各自的回信&#xff0c;然后从信箱中取走各自的信 5.2 UDP协议 注意&#xff1a;用户数据报和检验和都是指的整…

数学建模——插值(下)

本文是面向数学建模准备的&#xff0c;是介绍性文章&#xff0c;没有过多关于原理的说明&#xff01;&#xff01;&#xff01; 目录 一、2维插值原理及公式 1、二维插值问题 2、最邻近插值 3、分片线性插值 4、双线性插值 5、二维样条插值 二、二维插值及其Matlab工具箱…

记录一次Android侧滑需求代码

点击/滑动界面显示&#xff0c;不多说&#xff0c;上代码&#xff0c;性能未知 效果图 点击/滑动前界面 滑动后效果 布局 <?xml version"1.0" encoding"utf-8"?> <androidx.appcompat.widget.LinearLayoutCompat xmlns:android"…

【Cache】Squid代理服务器应用

文章目录 一、Squid 服务器的概念1. 代理服务器概述CDN 服务器 2. 代理的工作机制3. Squid 服务器的作用4. Squid 代理的类型 二、部署 Squid 服务器1. 安装 Squid 服务1.1 编译安装 Squid1.2 修改 Squid 的配置文件1.3 Squid 的运行控制1.4 创建 Squid 服务脚本1.5 supervisor…

在k8s集群中部署一个应用程序

一、 k8s集群简单介绍 上图描述的是拥有一个Master(主)节点和六个Worker(工作)节点的k8s集群 Master 负责管理集群 负责协调集群中的所有活动&#xff0c;例如调度应用程序&#xff0c;维护应用程序的状态&#xff0c;扩展和更新应用程序。 Worker节点(即图中的Node)是VM(虚…

模拟CSRF攻击

今天给大家表演一个拙劣的CSRF攻击。 我会编写两个应用&#xff1a;一个是正经应用&#xff0c;一个是钓鱼的应用。然后让后者攻击前者&#xff0c;让它打钱&#xff01; 一、绪论 1.1 先聊聊Cookie 参考&#xff1a;常用的本地存储——cookie篇 Cookie在八股文里面好像已…

模板类的开发

模板类的开发 栈定长数组变长数组 栈 入栈和出栈使用引用是为了传递参数 注意构造函数初始化列表使用模板的写法 注意析构函数delete指针需要 [ ] 测试 定长数组 重载了括号运算符 调用的其实是数组 使用int 使用char 变长数组

比亚迪车载Android开发岗三面经历~

前言 首先&#xff0c;我想说一下我为什么会想去比亚迪这样的车企做车载Android开发。我是一名有5年经验的Android开发工程师&#xff0c;之前一直在互联网软件公司工作&#xff0c;做过移动端App和IoT产品的开发。但我一直对汽车领域很感兴趣&#xff0c;也希望自己的技术能应…

TOT(Tree of Thought) | GPT-4+dfs搜索算法提升大模型复杂问题解决能力

大家好&#xff0c;我是HxShine。 今天分享一篇普林斯顿大学的一篇文章&#xff0c;Tree of Thoughts: Deliberate Problem Solving with Large Language Models[1]&#xff1a;思维之树:用大型语言模型解决复杂问题。 这篇工作还是非常有借鉴意义的&#xff0c;OpenAI的Andr…

2023年07月在线IDE流行度最新排名

点击查看最新在线IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年07月在线IDE流行度最新排名 TOP 在线IDE排名是通过分析在线ide名称在谷歌上被搜索的频率而创建的 在线IDE被搜索的次数越多&#xff0c;人们就会认为它越受欢迎。原始数据来自谷歌Trends 如果您相…

深度学习基础

1 机器学习、深度学习、人工智能 1.1 机器学习 机器学习是一门专门研究计算机怎样模拟或实现人类的学习行为&#xff0c;以获取新的知识或技能&#xff0c;重新组织已有的知识结构使之不断改善自身性能的学科。 基本步骤&#xff1a;获取数据、数据预处理、特征提取、特征选择…

postman几种常见的请求方式

1、get请求直接拼URL形式 对于http接口&#xff0c;有get和post两种请求方式&#xff0c;当接口说明中未明确post中入参必须是json串时&#xff0c;均可用url方式请求 参数既可以写到URL中&#xff0c;也可写到参数列表中&#xff0c;都一样&#xff0c;请求时候都是拼URL 2&am…

【win怎么给两个屏幕设置不同壁纸】

在现在经济的发展下&#xff0c;多数用户都拥有了两个屏幕&#xff0c;那么如何在不适用壁纸软件的情况下&#xff0c;将两个屏幕设置成不同的壁纸呢&#xff1f; 操作 首先将需要进行设置的图片选好&#xff0c;将其保存到桌面上&#xff0c;紧接着框选两张图片&#xff0c;…

探索Gradio库中的Image模块及其强大功能

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

84、基于stm32单片机超市自助存储柜快递箱系统设计(程序+原理图+流程图+参考论文+开题报告+任务书+设计资料+元器件清单等)

单片机主芯片选择方案 方案一&#xff1a;AT89C51是美国ATMEL公司生产的低电压&#xff0c;高性能CMOS型8位单片机&#xff0c;器件采用ATMEL公司的高密度、非易失性存储技术生产&#xff0c;兼容标准MCS-51指令系统&#xff0c;片内置通用8位中央处理器(CPU)和Flash存储单元&a…

Go程序结构- package和import

1、包和文件 在Go语言中包的作用和其他语言中的库或模块的作用类似&#xff0c;用于支持模块化、封装、编译隔离和重用。关键点如下&#xff1a; (1)包中保存一个或者多个.go结尾的文件&#xff0c;而包的目录就是包的导入路径 (2)中Go中通过一条简单的规则来管理标识符是否对外…

下个版本已定!C++自救新动作!

自去年年底&#xff0c;美国安全局&#xff08;NSA&#xff09;在其所发布的《Software Memory Safety》报告中点名批评C之后&#xff0c;C之父Bjarne Stroustrup一顿回怼后&#xff0c;做出决定&#xff1a;内部自救。现在&#xff0c;就让我们看看下一个版本的C&#xff0c;究…

【Go】Go 语言教程--语言变量(五)

往期教程&#xff1a; Go 语言教程–介绍&#xff08;一&#xff09;Go 语言教程–语言结构&#xff08;二&#xff09;Go 语言教程–语言结构&#xff08;三&#xff09;Go 语言教程–数据类型&#xff08;四&#xff09; 文章目录 变量声明多变量声明值类型和引用类型简短形…

【微服务】springboot 适配多数据源设计与实现

目录 一、问题背景 1.1 mysql读写分离 1.2 适配多种类型数据库 1.3 多数据源 二、适配多数据源场景和问题 2.1 支持快速切换其他数据源 2.2 代码层面最小化改造 2.3 数据迁移问题 2.4 跨库事务问题 三、多数据源适配解决方案 3.1 自己造轮子 3.2 基于providerId方式…

年少轻狂,中年失意,晚年凄惨的杜甫

诗圣杜甫的一生&#xff0c;几乎和苦难、倒霉紧紧拴在了一起。 裘马轻狂&#xff0c;恣意漫游的青年 公元712年&#xff0c;发生了两件值得历史铭记的大事情。第一件事&#xff0c;唐玄宗在这一年继位&#xff1b;第二件事&#xff0c;伟大的诗人杜甫在这一年出生。 杜甫字子…