一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術(shù)及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - mybatis如何通過接口查找對應的mapper.xml及方法執(zhí)行詳解

mybatis如何通過接口查找對應的mapper.xml及方法執(zhí)行詳解

2020-11-19 10:25興國First Java教程

這篇文章主要給大家介紹了利用mybatis如何通過接口查找對應的mapper.xml及方法執(zhí)行的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面跟著小編一起來學習學習吧。

本文主要介紹的是關(guān)于mybatis通過接口查找對應mapper.xml及方法執(zhí)行的相關(guān)內(nèi)容,下面話不多說,來看看詳細的介紹:

在使用mybatis的時候,有一種方式是

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

獲取接口,然后調(diào)用接口的方法。只要方法名和對應的mapper.xml中的id名字相同,就可以執(zhí)行sql。

那么接口是如何與mapper.xml對應的呢?

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

在DefaultSqlSession.Java中調(diào)用了configuration.getMapper()

?
1
2
3
public <T> T getMapper(Class<T> type) {
 return configuration.<T>getMapper(type, this);
 }

在Configuration.java中調(diào)用了mapperRegistry.getMapper(type, sqlSession);

?
1
2
3
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
 return mapperRegistry.getMapper(type, sqlSession);
 }

下面重點來了,在MapperRegistry.java中實現(xiàn)了動態(tài)代理

?
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);
 }
 }

這個函數(shù)分兩部分來看,首先是從map集合中獲取接口代理,map集合的來源,第二部分獲取代理后實例化,獲取接口的方法,執(zhí)行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);
 }

往上追溯該方法的調(diào)用是在SqlSessionFactory.build();時對配置文件的解析,其中對節(jié)點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節(jié)點進行解析配置
  if ("package".equals(child.getName())) {
   String mapperPackage = child.getStringAttribute("name");
   //注冊包下的接口
   configuration.addMappers(mapperPackage);
  } else {
  //使用mapper節(jié)點
   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.");
   }
  }
  }
 }
 }

這是調(diào)用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));
 //根據(jù)接口名尋找同包下同名的xml或者mapper的namespace是該接口的xml
 //找到對用的xml后進行解析mapper節(jié)點里面的節(jié)點
 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的全部注冊流程。

下面再說下第二部分就是通過動態(tài)代理獲取接口名字來對應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>();
 //構(gòu)造函數(shù),獲取接口類
 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);
 }
//供外部調(diào)用
 public T newInstance(SqlSession sqlSession) {
 final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
 return newInstance(mapperProxy);
 }
 
}

在MapperProxy.java中進行方法的執(zhí)行

?
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);
 //方法的執(zhí)行
 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的加載,以及通過動態(tài)代理來進行接口的執(zhí)行的過程。

總結(jié)

以上就是這篇文章的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:http://blog.csdn.net/u014231523/article/details/53423890

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 啊好大好爽 | 久热在线这里只有精品7 | 亚洲欧美日韩精品久久亚洲区 | 免费观看成年肉动漫网站 | 99国产热 | 久久九九有精品国产23百花影院 | 久久人妻无码毛片A片麻豆 久久热这里只有 精品 | 精品香蕉99久久久久网站 | 久久黄色大片 | 精品久久久久久午夜 | 免费看日本 | 日韩高清在线免费观看 | 外国黄色软件 | 亚洲男人天堂 | chinaspanking调教| 99re热这里只有精品视频 | 爽好舒服快想要免费看 | 波多野结衣之双方调教在线观看 | 青草国产福利视频免费观看 | xvideoscom极品肌肉警察 | 高清国产激情视频在线观看 | 国产传媒在线播放 | 国产日韩欧美精品在线 | 日韩欧美一区二区三区免费观看 | 亚洲AV久久无码精品九号 | 国产一卡 | 免费片在线观看高清 | 91精品91 | 国产福利一区二区三区四区 | 视频免费在线 | 国产亚洲福利精品一区二区 | 成人小视频在线观看 | 国产一卡二卡3卡4卡四卡在线 | juy799大岛优香在线观看 | 艹b小说 | 黑帮少爷爱上我第8集在线观看 | 欧美在线一级片 | 免费理伦片手机在线播放 | 姐姐不~不可以动漫在线观看 | 国产午夜精品久久理论片小说 | 免费看1级伦理 |