溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

mybatis中的mapper.xml文件怎么利用接口查找

發(fā)布時(shí)間:2020-11-24 15:26:49 來(lái)源:億速云 閱讀:230 作者:Leah 欄目:編程語(yǔ)言

這篇文章給大家介紹mybatis中的mapper.xml文件怎么利用接口查找,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

在使用mybatis的時(shí)候,有一種方式是

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

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

那么接口是如何與mapper.xml對(duì)應(yīng)的呢?

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

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

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

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

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

下面重點(diǎn)來(lái)了,在MapperRegistry.java中實(shí)現(xiàn)了動(dòng)態(tài)代理

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

這個(gè)函數(shù)分兩部分來(lái)看,首先是從map集合中獲取接口代理,map集合的來(lái)源,第二部分獲取代理后實(shí)例化,獲取接口的方法,執(zhí)行sql。

對(duì)于第一部分:集合的來(lái)源。

這個(gè)MapperRegistry.java中有個(gè)方法是addMappers();共有兩個(gè)重載。

public void addMappers(String packageName, Class<&#63;> superType) {
 ResolverUtil<Class<&#63;>> resolverUtil = new ResolverUtil<Class<&#63;>>();
 //通過(guò)包名,查找該包下所有的接口進(jìn)行遍歷,放入集合中
 resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
 Set<Class<&#63; extends Class<&#63;>>> mapperSet = resolverUtil.getClasses();
 for (Class<&#63;> mapperClass : mapperSet) {
  addMapper(mapperClass);
 }
 }

 //解析包名下的接口
 public void addMappers(String packageName) {
 addMappers(packageName, Object.class);
 }

往上追溯該方法的調(diào)用是在SqlSessionFactory.build();時(shí)對(duì)配置文件的解析,其中對(duì)節(jié)點(diǎn)mappers的解析,這里先不贅述,

mapperElement(root.evalNode("mappers"));
private void mapperElement(XNode parent) throws Exception {
 if (parent != null) {
  for (XNode child : parent.getChildren()) {
  //使用package節(jié)點(diǎn)進(jìn)行解析配置
  if ("package".equals(child.getName())) {
   String mapperPackage = child.getStringAttribute("name");
   //注冊(cè)包下的接口
   configuration.addMappers(mapperPackage);
  } else {
  //使用mapper節(jié)點(diǎn)
   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<&#63;> 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()的順序。

同時(shí)在改方法中還有一個(gè)方法很重要

 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
  //找到對(duì)用的xml后進(jìn)行解析mapper節(jié)點(diǎn)里面的節(jié)點(diǎn)
  MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
  parser.parse();
  loadCompleted = true;
  } finally {
  if (!loadCompleted) {
   knownMappers.remove(type);
  }
  }
 }
 }

這是通過(guò)接口的全路徑來(lái)查找對(duì)應(yīng)的xml。這里有兩種方式解析,也就是我們平常xml文件放置位置的兩種寫(xiě)法。

第一種是不加namespace,把xml文件放在和接口相同的路徑下,同時(shí)xml的名字與接口名字相同,如接口名為Student.java,xml文件為Student.xml。在相同的包下。這種當(dāng)時(shí)可以不加namespace.

第二種是加namespace,通過(guò)namespace來(lái)查找對(duì)應(yīng)的xml.

到這就是接口名和xml的全部注冊(cè)流程。

下面再說(shuō)下第二部分就是通過(guò)動(dòng)態(tài)代理獲取接口名字來(lái)對(duì)應(yīng)xml中的id。

主要有兩個(gè)類(lèi)MapperProxyFactory.java和MapperProxy.java

對(duì)于MapperProxyFactory.java

public class MapperProxyFactory<T> {

 private final Class<T> mapperInterface;
 private Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
 //構(gòu)造函數(shù),獲取接口類(lèi)
 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中進(jìn)行方法的執(zhí)行

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的加載,以及通過(guò)動(dòng)態(tài)代理來(lái)進(jìn)行接口的執(zhí)行的過(guò)程。

關(guān)于mybatis中的mapper.xml文件怎么利用接口查找就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI