欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

原理分析Java Mybatis中的Mapper

程序员文章站 2022-03-07 15:07:54
目录准备1.pom文件2.user类-数据库3.实体类4.dao 层5.mapper 文件源码分析1.断点2.查看源码总结准备1.pom文件 &...

准备

1.pom文件

 <dependencies>
        <!--mybatis坐标-->
        <dependency>
            <groupid>org.mybatis</groupid>
            <artifactid>mybatis</artifactid>
            <version>3.4.5</version>
        </dependency>
        <!--mysql驱动坐标-->
        <dependency>
            <groupid>mysql</groupid>
            <artifactid>mysql-connector-java</artifactid>
            <version>5.1.6</version>
            <scope>runtime</scope>
        </dependency>
        <!--单元测试坐标-->
        <dependency>
            <groupid>junit</groupid>
            <artifactid>junit</artifactid>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!--日志坐标-->
        <dependency>
            <groupid>log4j</groupid>
            <artifactid>log4j</artifactid>
            <version>1.2.12</version>
        </dependency>

        <dependency>
            <groupid>org.projectlombok</groupid>
            <artifactid>lombok</artifactid>
            <version>1.18.2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

2.user类-数据库

原理分析Java Mybatis中的Mapper

3.实体类

@getter
@setter
@tostring
@noargsconstructor
public class user {
    private int id;
    private string username;
    private string password;
}

4.dao 层

public interface userdao {
    list<user> findall();
}

5.mapper 文件

<?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">
<mapper namespace="dao.userdao">
    <select id="findall" resulttype="mode.user">
        select * from user
    </select>
</mapper>

核心配置文件

<?xml version="1.0" encoding="utf-8" ?>
<!doctype configuration public "-//mybatis.org//dtd config 3.0//en" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--通过properties标签加载外部properties文件-->
    <properties resource="jdbc.properties"></properties>
    <!--自定义别名-->
    <typealiases>
        <typealias type="mode.user" alias="user"></typealias>
    </typealiases>
    <!--数据源环境-->
    <environments default="developement">
        <environment id="developement">
            <transactionmanager type="jdbc"></transactionmanager>
            <datasource type="pooled">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </datasource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="usermapper.xml"></mapper>
    </mappers>

</configuration>

核心代码

import dao.userdao;
import mode.user;
import org.apache.ibatis.io.resources;
import org.apache.ibatis.session.sqlsession;
import org.apache.ibatis.session.sqlsessionfactory;
import org.apache.ibatis.session.sqlsessionfactorybuilder;
import java.io.ioexception;
import java.io.inputstream;
import java.util.list;

public class testmapper {
    public static void main(string[] args) throws ioexception {
        //加载核心配置文件
        inputstream resourceasstream = resources.getresourceasstream("sqlmapconfig.xml");
        //获得sqlsession工厂对象
        sqlsessionfactory sqlsessionfactory = new
                sqlsessionfactorybuilder().build(resourceasstream);
        //获得sqlsession对象
        sqlsession sqlsession = sqlsessionfactory.opensession();
        //执行sql语句
        userdao mapper = sqlsession.getmapper(userdao.class);
        list<user> userlist = mapper.findall();
        //打印结果
        system.out.println(userlist);
        //释放资源
        sqlsession.close();
    }
}

源码分析

1.断点

原理分析Java Mybatis中的Mapper

2.查看源码

defaultsqlsession:

原理分析Java Mybatis中的Mapper

configuration:

原理分析Java Mybatis中的Mapper

这是configuration 类。我们主要看getmapper()方法

原理分析Java Mybatis中的Mapper

mapperregistry:

原理分析Java Mybatis中的Mapper

关键代码:mapperproxyfactory.newinstance(sqlsession);

mapperproxyfactory:

原理分析Java Mybatis中的Mapper

返回的是mapperproxy 对象

mapperproxy:

源码:

// source code recreated from a .class file by intellij idea
// (powered by fernflower decompiler)
//
package org.apache.ibatis.binding;
import java.io.serializable;
import java.lang.invoke.methodhandles.lookup;
import java.lang.reflect.constructor;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import java.util.map;
import org.apache.ibatis.lang.usesjava7;
import org.apache.ibatis.reflection.exceptionutil;
import org.apache.ibatis.session.sqlsession;
public class mapperproxy<t> implements invocationhandler, serializable {
    private static final long serialversionuid = -6424540398559729838l;
    private final sqlsession sqlsession;
    private final class<t> mapperinterface;
    private final map<method, mappermethod> methodcache;
    public mapperproxy(sqlsession sqlsession, class<t> mapperinterface, map<method, mappermethod> methodcache) {
        this.sqlsession = sqlsession;
        this.mapperinterface = mapperinterface;
        this.methodcache = methodcache;
    }
    public object invoke(object proxy, method method, object[] args) throws throwable {
        try {
            if (object.class.equals(method.getdeclaringclass())) {
                return method.invoke(this, args);
            }
            if (this.isdefaultmethod(method)) {
                return this.invokedefaultmethod(proxy, method, args);
            }
        } catch (throwable var5) {
            throw exceptionutil.unwrapthrowable(var5);
        }
        mappermethod mappermethod = this.cachedmappermethod(method);
        return mappermethod.execute(this.sqlsession, args);
    }
    private mappermethod cachedmappermethod(method method) {
        mappermethod mappermethod = (mappermethod)this.methodcache.get(method);
        if (mappermethod == null) {
            mappermethod = new mappermethod(this.mapperinterface, method, this.sqlsession.getconfiguration());
            this.methodcache.put(method, mappermethod);
        }
        return mappermethod;
    }
    @usesjava7
    private object invokedefaultmethod(object proxy, method method, object[] args) throws throwable {
        constructor<lookup> constructor = lookup.class.getdeclaredconstructor(class.class, integer.type);
        if (!constructor.isaccessible()) {
            constructor.setaccessible(true);
        }
        class<?> declaringclass = method.getdeclaringclass();
        return ((lookup)constructor.newinstance(declaringclass, 15)).unreflectspecial(method, declaringclass).bindto(proxy).invokewitharguments(args);
    }
    private boolean isdefaultmethod(method method) {
        return (method.getmodifiers() & 1033) == 1 && method.getdeclaringclass().isinterface();
    }
}

原理分析Java Mybatis中的Mapper

在invoke方法中可以看到,如果我们调用的是object中的方法,不做任何处理,直接调用,否则执行:

mappermethod.execute(this.sqlsession, args);

mappermethod:

原理分析Java Mybatis中的Mapper

在mappermethod 中对sql语句进行分类反射

总结

  • mapperproxyfactory中,使用jdk的动态代理生成mapper接口的代理代理类
  • 由动态处理器mapperproxy中调用mappermethod中的方法处理执行sql
  • 最后,在mappermethod中根据执行的方法返回值决定调用sqlsession中的对应方法执行sql

 本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!