`

mybatis之MapperProxy

阅读更多
用mybatis的时候有一个问题困扰着我就是mybatis的mapper都是接口,没有实现类为什么可以直接调用xml中的sql语句进行实现?带着疑问我去看mybatis源码:

以在spring中整合mybatis为例:首先在web容易启动的时候,加载在spring中配置的SqlSessionFactoryBean和MapperScannerConfigurer。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="mapperLocations" value="classpath:com/stark/app/mappers/**/*Mapper.xml" />
	</bean>
	<!-- 扫描相关的Mapper接口 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com/stark/app/mappers" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
	</bean>


SqlSessionFactoryBean会扫描所有的xml文件,解析这些xml文件,封装到Configuration中。在Configuration这个类中有一个属性MapperRegistry mapperRegistry = new MapperRegistry(this);在解析namespace的时候会调用 configuration.addMapper()方法。
private void bindMapperForNamespace() {
    String namespace = builderAssistant.getCurrentNamespace();
    if (namespace != null) {
      Class<?> boundType = null;
      try {
        boundType = Resources.classForName(namespace);
      } catch (ClassNotFoundException e) {
        //ignore, bound type is not required
      }
      if (boundType != null) {
        if (!configuration.hasMapper(boundType)) {
          // Spring may not know the real resource name so we set a flag
          // to prevent loading again this resource from the mapper interface
          // look at MapperAnnotationBuilder#loadXmlResource
          configuration.addLoadedResource("namespace:" + namespace);
          configuration.addMapper(boundType);
        }
      }
    }
  }
//调用configuration.addMapper(boundType)就转为调用下面的方法
public <T> void addMapper(Class<T> type) {
    if (type.isInterface()) {
      if (hasMapper(type)) {
        throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
      }
      boolean loadCompleted = false;
      try {
        //放到一个map集合中该集合是:
        //public class MapperRegistry {
  //private Configuration config;
 // private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new //HashMap<Class<?>, MapperProxyFactory<?>>();
        knownMappers.put(type, new MapperProxyFactory<T>(type));
        // It's important that the type is added before the parser is run
        // otherwise the binding may automatically be attempted by the
        // mapper parser. If the type is already known, it won't try.
        MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
        parser.parse();
        loadCompleted = true;
      } finally {
        if (!loadCompleted) {
          knownMappers.remove(type);
        }
      }
    }
  }

看上面的分析现在也就是 MapperProxyFactory<?>> knownMappers, MapperProxyFactory<?>> 是什么东西?看源码:
public class MapperProxyFactory<T> {

  private final Class<T> mapperInterface;
  private 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;
  }
   //动态代理生成MapperProxy代理类。
  @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);
  }

}

//然后看MapperProxy
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 {
    if (Object.class.equals(method.getDeclaringClass())) {
      try {
        return method.invoke(this, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

  private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

}

通过以上源码我们明白了:是在web容易启动的时候,为每一个mapper生成一个动态代理去拦截,然后调用MapperProxy的invoke方法去执行。
分享到:
评论

相关推荐

    mybatis mybatis-spring source jar

    源码中可以看到 MapperProxy 和 MapperMethod,它们实现了接口方法的动态代理,将方法调用转换为 SQL 执行。 3. **SqlSessionFactory**: 这是创建 SqlSession 的工厂,通常由 SqlSessionFactoryBuilder 创建。源码...

    mybatis-3-mybatis-3.4.5 源码

    通过MapperProxy和MapperRegistry,MyBatis能够动态地生成Mapper接口的实现类,从而实现SQL的执行。 4. **XML配置文件/注解映射**: MyBatis允许通过XML或注解的方式定义SQL语句。XML配置文件包含SQL映射信息,包括...

    mybatis源码、用户手册、javadoc等

    - **Mapper接口**:这是MyBatis的核心组件之一,它允许开发者定义SQL操作,并将这些操作方法与SQL语句关联起来。 - **XML映射文件/注解**:用于描述SQL语句及其结果集映射,使得Java对象与数据库记录之间可以进行...

    MyBatis-Plus 学习笔记.pdf

    * MapperProxy 中 * SqlSessionFacotry 中 第四节:条件构造器 * EntityWrapper 简介 * 测试查询 * 测试修改 * 测试删除 第五节:活动记录 * 需要让实体类继承 Model 类且实现主键指定方法 * 新增、修改、查询、...

    mybatis的Jar

    通过MapperProxy,MyBatis将调用这些接口的方法转换为实际的SQL执行,并返回结果。 5. **Mapper XML文件**: 这是MyBatis配置的另一部分,它包含了SQL语句和结果映射。在XML文件中,你可以编写动态SQL,实现复杂的...

    Mybatis源码分析

    Mybatis通过MapperProxy实现了接口方法调用到具体SQL执行的转换。 2. Mapper XML:每个Mapper接口都有对应的XML配置文件,其中包含了具体的SQL语句和结果映射。Mybatis通过MapperRegistry找到对应的XML配置,实现...

    mybatis-3.3.1源码

    MapperRegistry维护了Mapper接口和MapperProxy之间的映射关系。 5. **Executor**:执行器是MyBatis执行SQL的核心组件,分为SimpleExecutor、ReusedExecutor和BatchExecutor三种类型,分别对应不同的执行策略。 6. ...

    mybatis3.4官方中文文档

    MyBatis的Mapper接口与XML映射文件中的namespace对应,接口方法与SQL语句对应,通过MapperProxy实现了接口调用与SQL执行的绑定。 9. **参数和结果处理** - `@Param`:用于指定方法参数的别名,方便在XML映射文件...

    mybatis源码.rar

    1. SQL动态生成:MyBatis的核心之一是SQL动态语句。在XML配置文件或注解中,我们可以编写动态SQL,例如`&lt;if&gt;`、`&lt;choose&gt;`、`&lt;when&gt;`、`&lt;otherwise&gt;`等标签,这些在编译时会被MyBatis解析为Java代码,动态生成SQL...

    mybatis框架源码及jar包

    重点研究的类包括SqlSessionManager、SqlSessionFactory、Executor和MapperProxy等。 2. **MyBatis jar包**: 提供的jar包包含MyBatis运行所需的所有依赖,主要用于在项目中引入MyBatis功能。主要的jar文件有...

    MyBatis源码详解学习.zip

    通过MapperProxy和MapperRegistry,MyBatis实现了接口方法调用到实际SQL执行的映射。 动态SQL是MyBatis的一大亮点,它允许在XML映射文件中编写条件语句,使得SQL语句可以根据传入参数的变化而变化。例如,if、...

    mybatis-spring-1.2.1.zip

    通过MyBatis-Spring,我们可以将MyBatis的数据访问层(DAO)对象纳入到Spring的管理之中,从而实现事务控制、DAO对象的自动装配等高级功能。 在1.2.1版本中,MyBatis-Spring提供了以下核心功能: 1. **...

    mybatis-spring-1.3.2.zip

    它会自动创建并配置所需的 SqlSession 和 MapperProxy,以便在应用中使用。 5. **注解支持**: MyBatis-Spring 支持在 Service 层方法上直接使用 @Transactional 注解来开启事务,简化了事务管理。同时,还可以在 ...

    MyBatis3.4.6 所有Jar包和源程序src

    此外,还有`MapperProxy`和`MapperMethod`,它们负责将Java方法调用转换为SQL执行。 MyBatis3.4.6的更新可能包括对JDBC驱动的兼容性提升,错误修复,性能优化,以及可能的新特性。例如,可能会引入更友好的API设计...

    《手写Mybatis》第4章:Mapper XML的解析和注册使用.doc

    《手写Mybatis》第4章深入探讨了Mapper XML的解析和注册使用,这是Mybatis框架的核心部分,它涉及到如何将XML配置文件转换为可执行的数据库操作。本章主要目标是实现对Mapper XML文件的解析,提取SQL信息,并创建...

    MyBatis 的执行流程.pdf

    - `getMapper`方法的调用会导致MyBatis去`Configuration`对象中获取`Mapper`对象,这个过程依赖于`MapperRegistry`对象,它是`Configuration`对象的属性之一。 - `MapperRegistry`使用一个`HashMap`属性`...

    MyBatis实战入门配套资料.zip

    - 映射器工厂和Mapper代理:了解Mapper接口和XML映射文件之间的关联,以及MapperFactoryBean和MapperProxy的工作原理。 - 高级特性:探索MyBatis的缓存机制、结果集映射、自定义插件等功能。 - 整合Spring:将...

    mybatis示例

    MyBatis通过MapperRegistry和MapperProxy实现接口方法到SQL的映射。 9. **事务管理**:MyBatis允许开发者自定义事务边界,可以结合Spring等框架实现全局事务管理。 10. **插件支持**:MyBatis提供插件机制,允许...

    mybatis框架-学习笔记Day01.rar

    2. **Executor.java**:执行器是MyBatis的核心接口之一,它定义了数据库操作的基本行为,如查询、插入、更新和删除。执行器根据不同的执行策略,可以有SimpleExecutor、ReuseExecutor和BatchExecutor等实现,分别...

    MyBatis学习资料

    1. 源码解析:可以学习MyBatis的内部实现,比如SqlSession是如何工作的,MapperProxy是如何动态生成的,以及动态SQL是如何编译和执行的。 2. 执行流程:通过源码分析,理解MyBatis执行SQL的完整步骤,包括SQL语句的...

Global site tag (gtag.js) - Google Analytics