• (六)Mybatis中接口代理机制及使用


    Mybatis学习目录

    上一篇:(五)在WEB中应用MyBatis(使用MVC架构模式)
    下一篇:(七)Mybatis传值中#{}和${}的区别,及别名机制

    javassist的引入

    在上一篇的学习中,不难发现dao层中的实现类代码比较固定,基本就是创建SqlSession对象,然后通过SqlSession对象调用CURD的相关方法,这个类中的方法没有任何业务逻辑,那可以可以动态生成呢?
    可以,我们可以使用javassist动态生成代理类。

    public class AccountDaoImpl implements AccountDao{
        @Override
        public Account selectByActno(String actno) {
            SqlSession session = SqlSessionUtil.getSession();
            Account account = session.selectOne("selectByActno", actno);
            return account;
        }
    
        @Override
        public int updateByActno(Account act) {
            SqlSession session = SqlSessionUtil.getSession();
            int count = session.update("updateByActno",act);
            return count;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    javassist的简介及使用

    参考:动态生成类–javassist的使用

    Mybatis中使用javassist

    在Mybatis中已经内置了javassist,无需再次引入依赖
    在上一篇:(五)在WEB中应用MyBatis(使用MVC架构模式)的基础上写一个工具类,动态生成dao接口的代理实现类,通过这个代理类调用接口中的方法。
    动态生成dao接口的实现类步骤

    • 1.获取类池
    • 2.制造类
    • 3.制造接口
    • 4.实现接口
    • 5.制造并实现方法
      • 5.1 获取所有的方法
      • 5.2 通过遍历循环动态制造方法,并将方法添加到类中
        这里还需要知道sql语句的id,而sql的id具有多变性,想要获取是比较困难的,所以这里需要规定,凡是使用GenerateDaoProxy的,namespace就必须是dao接口的全限定名称,id必须是dao接口的方法名
    • 6.创建对象并返回
    public class GenerateDaoProxy {
        private GenerateDaoProxy() {//工具类构造方法私有化
        }
    
        /**
         * 生成dao接口的实现类,将接口的实现类创建并返回
         * @param sqlSession SqlSession对象
         * @param daoInterface dao目标接口
         * @return 实现类的实例化对象
         */
        public static Object generate(SqlSession sqlSession,Class daoInterface){
            //1.获取类池
            ClassPool pool = ClassPool.getDefault();
            //2.制造类
            CtClass ctClass = pool.makeClass(daoInterface.getName()+"Proxy");
            //3.制造接口
            CtClass ctInterface = pool.makeInterface(daoInterface.getName());
            //4.实现接口
            ctClass.addInterface(ctInterface);
            //5.制造并实现方法
            //5.1 获取所有的方法
            Method[] methods = daoInterface.getDeclaredMethods();
            //5.2通过遍历循环动态制造方法,并将方法添加到类中
            Arrays.stream(methods).forEach(method -> {
                try {
                    //通过StringBuffer动态制造方法
                    StringBuffer methodCode = new StringBuffer();
                    methodCode.append("public ");//接口一定是public
                    methodCode.append(method.getReturnType().getName() + " ");//追加返回值类型的简称,因为有可能引用类型是带包名的
                    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("arg" + i);//追加参数名
                        if (i != parameterTypes.length-1) {//如果不是最后一个,这追加逗号
                            methodCode.append(",");
                        }
                    }
                    methodCode.append(")");
                    methodCode.append("{");
                    //这里需要使用全限定类名,要不然系统找不到
                    methodCode.append("org.apache.ibatis.session.SqlSession session = com.bank.utils.SqlSessionUtil.getSession();");
                    //这里需要知道什么类型的sql语句
                    //这里还需要知道sql语句的id,而sql的id具有多变性,所以规定:
                    //凡是使用GenerateDaoProxy的,namespace就必须是dao接口的全限定名称,id必须是dao接口的方法名
                    String sqlid = daoInterface.getName() + "." + method.getName();//这个id就是接口全限定名称加方法名
                    //SqlCommandType是个枚举类型 UNKNOWN, INSERT, UPDATE, DELETE, SELECT, FLUSH
                    //分别表示未知,插入,更新,删除,选择,刷新
                    SqlCommandType sqlCommandType = sqlSession.getConfiguration().getMappedStatement(sqlid).getSqlCommandType();
                    if (sqlCommandType == SqlCommandType.INSERT) {
                        //insert操作
                    }
                    if (sqlCommandType == SqlCommandType.DELETE) {
                        //delete操作
                    }
                    if (sqlCommandType == SqlCommandType.UPDATE) {
                        methodCode.append("return session.update(\""+sqlid+"\",arg0);");//arg0是拼接的方法参数
                    }
                    if (sqlCommandType == SqlCommandType.SELECT) {
                        methodCode.append("return ("+method.getReturnType().getName()+")session.selectOne(\""+sqlid+"\",arg0);");
                    }
                    methodCode.append("}");
                    System.out.println(methodCode.toString());
                    CtMethod ctMethod = CtMethod.make(methodCode.toString(), ctClass);
                    ctClass.addMethod(ctMethod);
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            });
            //6.创建对象并返回
            Object obj = null;
            try {
                Class<?> clazz = ctClass.toClass();
                obj = clazz.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    在service里就可以把new 实现类换成我们封装的动态生成类

    	//private AccountDao accountDao = new AccountDaoImpl();//这里就可以换成下面的
    
        //自己封装的
        private AccountDao accountDao = (AccountDao) GenerateDaoProxy.generate(SqlSessionUtil.getSession(),AccountDao.class);
    
    • 1
    • 2
    • 3
    • 4

    请添加图片描述

    MyBatis中接口代理机制及使用

    其实以上内容mybatis内部已经实现了。直接调用以下代码即可获取dao接口的代理类:

    private AccountDao accountDao = SqlSessionUtil.getSession().getMapper(AccountDao.class);
    
    • 1

    与自己封装的一样,由于Mybatis需要知道你的sql的id,而sql的id具有多变性,所以mybatis开发者出台了一个规定,
    在SqlMapper.xml映射文件里面,namespace必须和dao接口的全限定名称一致,id必须和dao接口中方法名一致。

  • 相关阅读:
    基于RetinaFace的口罩人脸检测算法
    安装2023最新版PyCharm来开发Python应用程序
    Java微服务+分布式+全栈项目(一)---->项目介绍+MyBatis-Plus入门
    免费享受企业级安全:雷池社区版WAF,高效专业的Web安全的方案
    是否在业务中使用大语言模型?
    简单谈谈云服务器私网IP的存在意义及优势
    快速上手若依代码生成器(2022)
    10_6 input输入子系统,流程解析
    【Spring】从面向对象再到面向切面
    4.3 划分子网和构造超网
  • 原文地址:https://blog.csdn.net/weixin_45832694/article/details/127639666