mybatis如何通过接口查找对应的mapper.xml及方法执行详解

转:http://www.jb51.net/article/116402.htm

本文主要介绍的是关于mybatis通过接口查找对应mapper.xml及方法执行的相关内容,下面话不多说,来看看详细的介绍:

在使用mybatis的时候,有一种方式是

?


1

BookMapper bookMapper = SqlSession().getMapper(BookMapper.class)

获取接口,然后调用接口的方法。只要方法名和对应的mapper.xml中的id名字相同,就可以执行sql。

那么接口是如何与mapper.xml对应的呢?

首先看下,在getMapper()方法是如何操作的。

在DefaultSqlSession.Java中调用了configuration.getMapper()

?


1

2

3

public <T> T getMapper(Class<T> type) {

 return configuration.<T>getMapper(type, this);

 }

在Configuration.java中调用了mapperRegistry.getMapper(type, sqlSession);

?


1

2

3

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {

 return mapperRegistry.getMapper(type, sqlSession);

 }

下面重点来了,在MapperRegistry.java中实现了动态代理

?


1

2

3

4

5

6

7

8

9

10

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {

 final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);

 if (mapperProxyFactory == null)

  throw new BindingException("Type " + type + " is not known to the MapperRegistry.");

 try {

  return mapperProxyFactory.newInstance(sqlSession);

 } catch (Exception e) {

  throw new BindingException("Error getting mapper instance. Cause: " + e, e);

 }

 }

这个函数分两部分来看,首先是从map集合中获取接口代理,map集合的来源,第二部分获取代理后实例化,获取接口的方法,执行sql。

对于第一部分:集合的来源。

这个MapperRegistry.java中有个方法是addMappers();共有两个重载。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

public void addMappers(String packageName, Class<?> superType) {

 ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();

 //通过包名,查找该包下所有的接口进行遍历,放入集合中

 resolverUtil.find(new ResolverUtil.IsA(superType), packageName);

 Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();

 for (Class<?> mapperClass : mapperSet) {

  addMapper(mapperClass);

 }

 }

 //解析包名下的接口

 public void addMappers(String packageName) {

 addMappers(packageName, Object.class);

 }

往上追溯该方法的调用是在SqlSessionFactory.build();时对配置文件的解析,其中对节点mappers的解析,这里先不赘述,

?


1

mapperElement(root.evalNode("mappers"));

?


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

private void mapperElement(XNode parent) throws Exception {

 if (parent != null) {

  for (XNode child : parent.getChildren()) {

  //使用package节点进行解析配置

  if ("package".equals(child.getName())) {

   String mapperPackage = child.getStringAttribute("name");

   //注册包下的接口

   configuration.addMappers(mapperPackage);

  } else {

  //使用mapper节点

   String resource = child.getStringAttribute("resource");

   String url = child.getStringAttribute("url");

   String mapperClass = child.getStringAttribute("class");

   if (resource != null && url == null && mapperClass == null) {

   ErrorContext.instance().resource(resource);

   InputStream inputStream = Resources.getResourceAsStream(resource);

   XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());

   mapperParser.parse();

   } else if (resource == null && url != null && mapperClass == null) {

   ErrorContext.instance().resource(url);

   InputStream inputStream = Resources.getUrlAsStream(url);

   XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());

   mapperParser.parse();

   } else if (resource == null && url == null && mapperClass != null) {

   Class<?> mapperInterface = Resources.classForName(mapperClass);

   configuration.addMapper(mapperInterface);

   } else {

   throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");

   }

  }

  }

 }

 }

这是调用addMapper()的顺序。

同时在改方法中还有一个方法很重要

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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 {

 knownMappers.put(type, new MapperProxyFactory<T>(type));

 //根据接口名寻找同包下同名的xml或者mapper的namespace是该接口的xml

 //找到对用的xml后进行解析mapper节点里面的节点

 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);

 parser.parse();

 loadCompleted = true;

 } finally {

 if (!loadCompleted) {

  knownMappers.remove(type);

 }

 }

}

}

这是通过接口的全路径来查找对应的xml。这里有两种方式解析,也就是我们平常xml文件放置位置的两种写法。

第一种是不加namespace,把xml文件放在和接口相同的路径下,同时xml的名字与接口名字相同,如接口名为Student.java,xml文件为Student.xml。在相同的包下。这种当时可以不加namespace.

第二种是加namespace,通过namespace来查找对应的xml.

到这就是接口名和xml的全部注册流程。

下面再说下第二部分就是通过动态代理获取接口名字来对应xml中的id。

主要有两个类MapperProxyFactory.java和MapperProxy.java

对于MapperProxyFactory.java

?


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

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;

 }

 @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.java中进行方法的执行

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

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;

 }

至此,就是mybatis所有接口和xml的加载,以及通过动态代理来进行接口的执行的过程。

总结

以上就是这篇文章的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

原文地址:https://www.cnblogs.com/wangle1001986/p/9072630.html

时间: 2024-10-08 02:20:25

mybatis如何通过接口查找对应的mapper.xml及方法执行详解的相关文章

【转】Mybatis 3.1中 Mapper XML 文件 的学习详解

MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 95%的代码量.MyBatis 的构建就是聚焦于 SQL 的,使其远离于普通的方式. SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序): cache – 配置给定命名空间的缓存. cache-ref – 从其他命名空间引用缓存配置. resultMap – 最复杂,也是最有力量的元

Mybatis 3.1中 Mapper XML 文件 的学习详解

转:http://blog.csdn.net/zhll3377/article/details/8203440 MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 95%的代码量.MyBatis 的构建就是聚焦于 SQL 的,使其远离于普通的方式. SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序): cache – 配置给定命名空间

MyBatis Mapper XML 文件 的学习详解

MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 95%的代码量.MyBatis 的构建就是聚焦于 SQL 的,使其远离于普通的方式. SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序): cache – 配置给定命名空间的缓存. cache-ref – 从其他命名空间引用缓存配置. resultMap – 最复杂,也是最有力量的元

[转] MyBatis的XxxMapper.xml 映射器的详解(六)

上一章简单介绍了MyBatis的核心配置文件 SqlMapConfig.xml(五),如果没有看过,请观看上一章. 一 . XxxMapper.xml 映射器的使用在MyBatis 中,将Dao层的接口与对应的Mapper.xml 配置文件进行组合使用,而不是以前的接口实现类处理. 这里着重讲解一下,这个配置文件的使用. 将XxxMapper.xml 放置在与接口XxxMapper.java 同级的目录下. 一.一 Schema约束<!DOCTYPE mapper PUBLIC "-//m

集合类 Contains 方法 深入详解 与接口的实例

.Net 相等性:集合类 Contains 方法 深入详解 http://www.cnblogs.com/ldp615/archive/2009/09/05/1560791.html 1.接口的概念及声明接口是一种用来定义程序的协议,它描述可属于任何类或结构的一组相关行为.接口可有方法.属性.事件和索引器或这四种成员的任何组合类型,但不能包含字段.那么接口具有哪些特点呢?·接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员(说明:如类A继承接口B,那么A中必须实现B中定义的属性

[转]C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

本文转自:http://www.cnblogs.com/landeanfen/p/5501487.html 阅读目录 一.void无返回值 二.IHttpActionResult 1.Json(T content) 2.Ok(). Ok(T content) 3.NotFound() 4.其他 5.自定义IHttpActionResult接口的实现 三.HttpResponseMessage 四.自定义类型 五.总结 正文 前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学

mybatis中的mapper接口文件以及example类的实例函数以及详解

##Example example = new ##Example(); example.setOrderByClause("字段名 ASC"); //升序排列,desc为降序排列. example.setDistinct(false)//去除重复,boolean型,true为选择不重复的记录. Criteria criteria = new Example().createCriteria(); is null;is not null; equal to(value);not equ

mybatis学习之路(二)mapper代理开发方法-开发规范及实现

1.在mapper.xml中namespace等于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

利用mybatis generator插件反向生成Dao、Mapper.xml、pojo(通过maven)

直接进入主题,由于项目选择的利用maven构建,所以选择了利用maven的生成方式.(还有一种可自行百度) 一.在pom.xml中添加插件 <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.2</version> <configur