美文网首页
MyBatis动态代理(二)

MyBatis动态代理(二)

作者: Doooook | 来源:发表于2020-07-23 22:38 被阅读0次

接着上一篇MyBatis动态代理(一),这一篇我们来追踪下MyBatis的动态代理

0. 通过SqlSessionFactoryUtil获取SqlSession

package com.pengjs.kkb.mybatis.utils;

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.InputStream;

/**
 * @author: Jason
 * @date: 2020-06-21 21:13
 */
public class SqlSessionFactoryUtil {

    /**
     * SqlSessionFactory对象
     */
    private static SqlSessionFactory sqlSessionFactory = null;

    /**
     * 类线程锁
     */
    private static final Class CLASS_LOCK = SqlSessionFactoryUtil.class;

    /**
     * 私有化构造参数,不让实例化,只能通过类来访问
     * 避免使用者使用new的方式去创建多个对象
     */
    private SqlSessionFactoryUtil() {}

    /**
     * 构建SqlSessionFactory,单利模式,懒汉式
     * 某一个对象在应用中承担唯一职责的时候就是用单利模式,在本例中,SqlSessionFactory的唯一职责就是创建SqlSession
     */
    private static void initSqlSessionFactory() {
        String resource = "mybatis_config.xml";
        InputStream inputStream = null;

        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 静态方法使用类锁
        synchronized (CLASS_LOCK) {
            if (sqlSessionFactory == null) {
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            }
        }
    }

    /**
     * 打开SqlSession
     * @return SqlSession
     */
    public static SqlSession openSqlSession() {
        if (sqlSessionFactory == null) {
            initSqlSessionFactory();
        }
        // 获取数据库信息,对应mybatis配置文件中的databaseIdProvider,现在我们用的是MySQL,对应的value就是mysql,即databaseId
        String databaseId = sqlSessionFactory.getConfiguration().getDatabaseId();
        System.out.println("databaseId: " + databaseId);
        return sqlSessionFactory.openSession();
    }

}
image.png

1. 入口,通过SqlSession获取Mapper接口

image.png
image.png

2. SqlSession默认实现类DefaultSqlSession

image.png

3. 从全局的Configuration中获取已经装载的mapper

image.png

4. 从mapperProxyFactory中获取mapper

image.png
image.png

5. 我们来看看MapperProxyFactory

是不是就是MyBatis动态代理(一)讲到的JDK动态代理了。

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.binding;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.ibatis.session.SqlSession;

/**
 * @author Lasse Voss
 */
public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();

  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }

  public Class<T> getMapperInterface() {
    return mapperInterface;
  }

  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

}

newInstance(mapperProxy)生成的就是一个动态代理类:


image.png

下面我们来看看代理类的invoke方法

MapperMethod采用命令模式运行,根据上下文跳转,它可能跳转到许多方法中,我们不需要全部明白。我们可以看到里面的executeForMany方法,再看看它的实现,实际上它最后就是通过sqlSession对象去运行对象的SQL。


image.png image.png image.png image.png image.png image.png

至此,相信大家已经了解了MyBatis为什么只用Mappper接口便能够运行SQL,因为映射器的XML文件的命名空间对应的便是这个接口的全路径,那么它根据全路径和方法名便能够绑定起来,通过动态代理技术,让这个接口跑起来。而后采用命令模式,最后还是使用SqlSession接口的方法使得它能够执行查询,有了这层封装我们便可以使用接口编程,这样编程就更简单了。

相关文章

  • MyBatis-Mapper动态代理

    MyBatis官方教程MyBatis二级缓存设计Mybatis中Mapper动态代理的实现原理制作Mybatis插...

  • mybatis 源码解析之如何实现 mapper 动态代理

    从源码解析 mybatis 是如何实现 mapper 动态代理的。 mybatis 底层是基于 JDK 动态代理来...

  • MyBatis动态代理(二)

    接着上一篇MyBatis动态代理(一),这一篇我们来追踪下MyBatis的动态代理 0. 通过SqlSession...

  • Mybatis动态代理

    Mybatis动态代理 实现 MapperProxy实现InvocationHandler接口,重写...

  • 设计模式之动态代理

    动态代理模式,在当前流行框架(如:Spring、Mybatis、Dubbo)中应用非常广泛,掌握动态代理模式是理...

  • MyBatis之Mapper动态代理开发

    title: MyBatis之Mapper动态代理开发tags: MyBatiscategories: MyBat...

  • 动态代理

    动态代理理论及Mybatis实战动态代理在我们平时编程并不常用,但因为Spring AOP以及大量框架均使用动态代...

  • Mybatis插件

    Mybatis插件 Mybatis插件又称拦截器。 Mybatis采用责任链模式,通过动态代理组织多个插件(拦截器...

  • mybatis动态代理

    1.用户使用 1.提供 xxMapper接口 2.在xml里配置(可选配置)(2) 2.mybatis实现 在调用...

  • javassist动态代理与cglib动态代理

    mybatis的懒加载是用到了javassist的动态代理,所以想先简单说一下这个,顺便带上cglib动态代理。 ...

网友评论

      本文标题:MyBatis动态代理(二)

      本文链接:https://www.haomeiwen.com/subject/bipklktx.html