Analyse des Prinzips des dynamischen Proxys des Mybatis-Mappers

Analyse des Prinzips des dynamischen Proxys des Mybatis-Mappers

Vorwort

Bevor wir mit der Erklärung des Prinzips des dynamischen Proxys beginnen, schauen wir uns zunächst die beiden Implementierungsmethoden der DAO-Schicht nach der Integration von Mybatis an, die keinen dynamischen Proxy verwenden und die einen dynamischen Proxy verwenden. Indem wir unsere eigene Implementierung der Schnittstelle der DAO-Schicht und des dynamischen Proxys von Mybatis vergleichen, können wir intuitiver zeigen, was der dynamische Proxy von Mybatis für uns tut, was für uns hilfreich ist, um den Prozess des dynamischen Proxys zu verstehen. Nach der Erklärung werden wir das Prinzip des dynamischen Proxys analysieren. Diese Erklärung basiert auf der erstellten Mybatis-Umgebung, und das grundlegende Schreiben der Benutzerklasse und die Deklaration der Dao-Schnittstelle der Benutzerklasse wurden implementiert. Das Folgende ist der Schnittstellencode der Dao-Schicht

öffentliche Schnittstelle UserDao {
 /*
 Alle Benutzerinformationen abfragen*/
 List<Benutzer> findAll();
 /**
  * Benutzer speichern * @param Benutzer
  */
 void save(Benutzer Benutzer);

 /**
  * Benutzer aktualisieren * @return
  */
 void update(Benutzer Benutzer);
 /**
  * Benutzer löschen */
 void delete(Integer Benutzer-ID);
 /**
  * Einen Benutzer suchen * @param userId
  * @zurückkehren
  */
 Benutzer findOne(Integer userId);
 /**
  * Fuzzy-Abfrage basierend auf Namen* @param name
  * @zurückkehren
  */
 List<Benutzer> findByName(String name);
 /**
  * Fuzzy-Abfrage basierend auf kombinierten Objekten* @param vo
  * @zurückkehren
  */
 List<Benutzer> findByQueryVo(QueryVo vo);
}

1. Vergleich zweier Implementierungsmethoden der Mybatis-Dao-Schicht

1. Die DAO-Schicht verwendet keinen dynamischen Proxy

Wenn die DAO-Schicht keinen dynamischen Proxy verwendet, müssen wir die Schnittstelle der DAO-Schicht selbst implementieren. Der Einfachheit halber habe ich nur die Methode findAll in der DAO-Schnittstelle implementiert. Diese Methode wird als Beispiel verwendet, um zu zeigen, wie wir DAO selbst implementieren. Schauen wir uns den Code an:

öffentliche Klasse UserDaoImpl implementiert UserDao{
 private SqlSessionFactory-Fabrik;
 öffentliche UserDaoImpl(SqlSessionFactory Fabrik){
  diese.fabrik = Fabrik;
 }
 öffentliche Liste<Benutzer> findAll() {
  //1. Holen Sie sich das SQLSession-Objekt SqlSession sqlSession = factory.openSession();
  //2. Rufen Sie die selectList-Methode auf. List<Benutzer> list = sqlSession.selectList("com.example.dao.UserDao.findAll");
  //3. Schließen Sie den Stream sqlSession.close();
  Liste zurückgeben;
 }
 public void save(Benutzer Benutzer) {
 }
 public void update(Benutzer Benutzer) {
 }
 public void löschen(Integer Benutzer-ID) {
 }
 öffentlicher Benutzer findOne(Integer userId) {
  gibt null zurück;
 }
 öffentliche Liste<Benutzer> findByName(String name) {
  gibt null zurück;
 }
 öffentliche Liste<Benutzer> findByQueryVo(QueryVo vo) {
  gibt null zurück;
 }

Der Schlüsselcode hier ist List<User> list = sqlSession.selectList("com.example.dao.UserDao.findAll"), was erfordert, dass wir die Methode in SqlSession manuell aufrufen. Das Endziel basierend auf der dynamischen Proxy-Methode besteht darin, hier erfolgreich aufzurufen.

Hinweis: Wenn Sie Vorgänge hinzufügen, aktualisieren oder löschen, müssen Sie der Methode die Transaktionsübermittlung hinzufügen.

2. Die DAO-Schicht verwendet den dynamischen Proxy von Mybatis

Wenn Sie einen dynamischen Proxy verwenden, müssen Sie nach Abschluss der Schnittstellendeklaration der Dao-Ebene bei Verwendung nur das der Dao-Schnittstelle entsprechende Proxy-Objekt über die getMapper-Methode des SqlSession-Objekts abrufen. Der Schlüsselcode lautet wie folgt:

//3. Holen Sie sich das SqlSession-Objekt SqlSession session = factory.openSession();
//4. Holen Sie sich das Proxy-Objekt von DAO UserDao mapper = session.getMapper(UserDao.class);
//5. Alle Abfragemethoden ausführen List<User> list = mapper.findAll();

Nachdem Sie das Proxy-Objekt der DAO-Ebene erhalten haben, können Sie die Abfragemethode über das Proxy-Objekt aufrufen, um die Funktion zum Abfragen der Liste aller Benutzer zu realisieren.

2. Prinzipanalyse der Mybatis Dynamic Proxy-Implementierung

Die wichtigsten Klassen im dynamischen Proxy: SqlSession, MapperProxy, MapperMethod. Beginnen wir mit der Prozessanalyse von der Einstiegsmethode bis zum Ende des Aufrufs.

1. Beginn der Aufrufmethode:

// 4. Holen Sie sich das Proxy-Objekt von DAO

UserDao-Mapper = session.getMapper(UserDao.class); Da es sich bei SqlSession um eine Schnittstelle handelt, haben wir im Debug-Modus festgestellt, dass die hier verwendete Implementierungsklasse DefaultSqlSession ist.

2. Suchen Sie in DeaultSqlSession nach der Methode getMapper und stellen Sie fest, dass hier keine weiteren Aktionen ausgeführt werden. Die Arbeit wird einfach in die Konfigurationsklasse verschoben. Konfiguration ist eine Klasse, keine Schnittstelle. Sie können die Methode getMapper dieser Klasse direkt eingeben.

@Überschreiben
 öffentliche <T> T getMapper(Klasse<T> Typ) {
 Konfiguration zurückgeben.<T>getMapper(Typ, dies);
 }

3. Suchen Sie die getMapper-Methode der Configuration-Klasse . Hier wird die Arbeit an die getMapper-Methode von MapperRegistry übergeben, sodass wir weitermachen können.

 öffentliche <T> T getMapper(Klasse<T> Typ, SqlSession sqlSession) {
 returniere mapperRegistry.getMapper(Typ, SQLSession);
 }

4. Suchen Sie die getMapper-Methode von MapperRegistry . Sie können sehen, dass sie sich von der vorherigen unterscheidet. Durch die Benennungsmethode von MapperProxyFactory wissen wir, dass die Proxy-Klasse von MapperProxy, um die es uns geht, durch diese Factory generiert wird. Dann geben wir die newInstance-Methode von MapperProxyFactory über mapperProxyFactory.newInstance(sqlSession) ein.

öffentliche <T> T getMapper(Klasse<T> Typ, SqlSession sqlSession) {
 endgültige MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(Typ);
 if (mapperProxyFactory == null) {
  throw new BindingException("Typ " + Typ + " ist der MapperRegistry nicht bekannt.");
 }
 versuchen {
  gibt mapperProxyFactory.newInstance(sqlSession) zurück;
 } Fang (Ausnahme e) {
  throw new BindingException("Fehler beim Abrufen der Mapper-Instanz. Ursache: " + e, e);
 }
 }

5. Suchen Sie die newIntance-Methode von MapperProxyFactory . Aus dem Parametertyp SqlSession können wir erkennen, dass der obige Aufruf zuerst die zweite newInstance-Methode aufruft und das MapperProxy-Objekt erstellt, auf das wir uns konzentrieren müssen. Die zweite Methode ruft dann die erste newInstance-Methode auf und übergibt das MapperProxy-Objekt an sie. Die Proxy-Klasse wird basierend auf dem Objekt erstellt und zurückgegeben. Wir haben hier bereits die erforderliche Proxy-Klasse, müssen aber noch in die MapperProxy-Klasse schauen, um zu sehen, was unsere Proxy-Klasse macht.

geschützt T neueInstanz(MapperProxy<T> mapperProxy) {
 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), neue Klasse[] { mapperInterface }, mapperProxy);
 }
 öffentliche T neueInstanz(SqlSession sqlSession) {
 endgültiger MapperProxy<T> mapperProxy = neuer MapperProxy<T>(sqlSession, mapperInterface, methodCache);
 gib neue Instanz zurück (MapperProxy);
 }

6. Suchen Sie die MapperProxy-Klasse und stellen Sie fest, dass sie die InvocationHandler-Schnittstelle implementiert, die der dynamische JDK-Proxy implementieren muss. Daher konzentrieren wir uns auf die invoke () -Methode. Hier sehen wir, dass die MapperMethod-Klasse zuerst in der invoke-Methode abgerufen wird und dann mapperMethod.execute () aufgerufen wird. Daher sehen wir uns weiterhin die Execute-Methode der MapperMethod-Klasse an.

öffentliche Klasse MapperProxy<T> implementiert InvocationHandler, Serializable {
 private statische endgültige lange SerialVersionUID = -6424540398559729838L;
 private endgültige SqlSession sqlSession;
 private endgültige Klasse<T> MapperInterface;
 private finale Map<Methode, MapperMethod> methodCache;
 öffentliche MapperProxy(SqlSession sqlSession, Klasse<T> mapperInterface, Map<Methode, MapperMethod> methodCache) {
 diese.sqlSession = sqlSession;
 this.mapperInterface = Mapper-Interface;
 this.methodCache = MethodenCache;
 }

 @Überschreiben
 öffentliches Objekt aufrufen(Objektproxy, Methode Methode, Objekt[] args) wirft Throwable {
 versuchen {
  wenn (Objekt.Klasse.equals(Methode.getDeclaringClass())) {
  Rückgabemethode.aufrufen(dies, Argumente);
  } sonst wenn (isDefaultMethod(Methode)) {
  returniere invokeDefaultMethod(Proxy, Methode, Argumente);
  }
 } fangen (Wurfbares t) {
  wirf ExceptionUtil.unwrapThrowable(t);
 }
 endgültige MapperMethod mapperMethod = cachedMapperMethod(Methode);
 gibt mapperMethod.execute(sqlSession, args) zurück;
 }

 private MapperMethod cachedMapperMethod(Methode Methode) {
 MapperMethod mapperMethod = methodCache.get(Methode);
 if (mapperMethod == null) {
  mapperMethod = neue MapperMethod(mapperInterface, Methode, sqlSession.getConfiguration());
  methodCache.put(Methode, MapperMethode);
 }
 MapperMethod zurückgeben;
 }

 @UsesJava7
 privates Objekt invokeDefaultMethod(Objektproxy, Methodenmethode, Objekt[] args)
  wirft Throwable {
 endgültiger Konstruktor<MethodHandles.Lookup> Konstruktor = MethodHandles.Lookup.class
  .getDeclaredConstructor(Klasse.Klasse, int.Klasse);
 wenn (!Konstruktor.istZugänglich()) {
  Konstruktor.setAccessible(true);
 }
 endgültige Klasse<?> declaringClass = method.getDeclaringClass();
 Rückgabekonstruktor
  .newInstance(deklarierendeKlasse,
   MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.GESCHÜTZT
    | MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
  .unreflectSpecial(Methode, deklarierendeKlasse).bindTo(Proxy).invokeWithArguments(Argumente);
 }
 /**
 * Backport von java.lang.reflect.Method#isDefault()
 */
 private boolean istStandardMethode(Methode Methode) {
 return ((Methode.getModifiers()
  & (Modifikator.ABSTRACT | Modifikator.PUBLIC | Modifikator.STATIC)) == Modifikator.PUBLIC)
  && method.getDeclaringClass().isInterface();
 }
}

7. Suchen Sie die Execute-Methode der MapperMethod-Klasse und stellen Sie fest, dass Execute die Rückgabeergebnisse abruft und kapselt, indem es andere Methoden in dieser Klasse aufruft. Sehen wir uns die gesamte MapperMethod-Klasse an.

öffentliches Objekt ausführen(SqlSession sqlSession, Object[] args) {
 Objektergebnis;
 Schalter (Befehl.getType()) {
  Fall EINFÜGEN: {
  Objektparameter = Methode.convertArgsToSqlCommandParam(args);
  Ergebnis = Zeilenzählerergebnis(sqlSession.insert(command.getName(), param));
  brechen;
  }
  Fall-UPDATE: {
  Objektparameter = Methode.convertArgsToSqlCommandParam(args);
  Ergebnis = rowCountResult(sqlSession.update(command.getName(), param));
  brechen;
  }
  Fall LÖSCHEN: {
  Objektparameter = Methode.convertArgsToSqlCommandParam(args);
  Ergebnis = ZeilenzählerResult(sqlSession.delete(command.getName(), param));
  brechen;
  }
  Fallauswahl:
  wenn (Methode.returnsVoid() und Methode.hasResultHandler()) {
   : Führen Sie einen der folgenden Schritte aus, um SQL Server 2013 zu starten:
   Ergebnis = null;
  } sonst wenn (Methode.returnsMany()) {
   Ergebnis = executeForMany(sqlSession, args);
  } sonst wenn (Methode.returnsMap()) {
   Ergebnis = executeForMap(sqlSession, args);
  } sonst wenn (Methode.returnsCursor()) {
   Ergebnis = executeForCursor(sqlSession, args);
  } anders {
   Objektparameter = Methode.convertArgsToSqlCommandParam(args);
   Ergebnis = sqlSession.selectOne(command.getName(), param);
  }
  brechen;
  Gehäuse FLUSH:
  Ergebnis = sqlSession.flushStatements();
  brechen;
  Standard:
  throw new BindingException("Unbekannte Ausführungsmethode für: " + command.getName());
 }
 wenn (Ergebnis == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
  throw new BindingException("Mapper-Methode '" + command.getName() 
   + " Es wurde versucht, von einer Methode mit einem primitiven Rückgabetyp (" + method.getReturnType() + ") null zurückzugeben.");
 }
 Ergebnis zurückgeben;
 }

8. Die MapperMethod-Klasse ist die Kernklasse des gesamten Proxy-Mechanismus , die die Operationen in SqlSession kapselt und verwendet.

In dieser Klasse gibt es zwei innere Klassen: SqlCommand und MethodSignature. SqlCommand wird zum Kapseln von CRUD-Operationen verwendet, die die Knoten der Operationen sind, die wir in XML konfiguriert haben. Jeder Knoten generiert eine MappedStatement-Klasse.

MethodSignature wird verwendet, um die Parameter und den Rückgabetyp der Methode zu kapseln. In der Execute-Methode stellen wir fest, dass wir zum Schnittstellenaufruf in SqlSession zurückgekehrt sind. Dies entspricht der Art und Weise, wie wir die UerDao-Schnittstelle implementieren, indem wir das SqlSession-Objekt direkt verwenden, um die Implementierungsklasse von DefaultSqlSession aufzurufen. Nach einem großen Proxy-Kreis kehren wir an den ursprünglichen Ort zurück. Dies ist der Implementierungsprozess des gesamten dynamischen Proxys.

öffentliche Klasse MapperMethod {
 privater endgültiger SqlCommand-Befehl;
 private endgültige MethodSignature-Methode;
 öffentliche MapperMethod(Klasse<?> mapperInterface, Methode method, Konfiguration config) {
 this.command = neuer SqlCommand(Konfiguration, Mapper-Schnittstelle, Methode);
 this.method = neue MethodSignature(Konfiguration, MapperInterface, Methode);
 }
 öffentliches Objekt ausführen(SqlSession sqlSession, Object[] args) {
 Objektergebnis;
 Schalter (Befehl.getType()) {
  Fall EINFÜGEN: {
  Objektparameter = Methode.convertArgsToSqlCommandParam(args);
  Ergebnis = Zeilenzählerergebnis(sqlSession.insert(command.getName(), param));
  brechen;
  }
  Fall-UPDATE: {
  Objektparameter = Methode.convertArgsToSqlCommandParam(args);
  Ergebnis = rowCountResult(sqlSession.update(command.getName(), param));
  brechen;
  }
  Fall LÖSCHEN: {
  Objektparameter = Methode.convertArgsToSqlCommandParam(args);
  Ergebnis = ZeilenzählerResult(sqlSession.delete(command.getName(), param));
  brechen;
  }
  Fallauswahl:
  wenn (Methode.returnsVoid() und Methode.hasResultHandler()) {
   : Führen Sie einen der folgenden Schritte aus, um SQL Server 2013 zu starten:
   Ergebnis = null;
  } sonst wenn (Methode.returnsMany()) {
   Ergebnis = executeForMany(sqlSession, args);
  } sonst wenn (Methode.returnsMap()) {
   Ergebnis = executeForMap(sqlSession, args);
  } sonst wenn (Methode.returnsCursor()) {
   Ergebnis = executeForCursor(sqlSession, args);
  } anders {
   Objektparameter = Methode.convertArgsToSqlCommandParam(args);
   Ergebnis = sqlSession.selectOne(command.getName(), param);
  }
  brechen;
  Gehäuse FLUSH:
  Ergebnis = sqlSession.flushStatements();
  brechen;
  Standard:
  throw new BindingException("Unbekannte Ausführungsmethode für: " + command.getName());
 }
 wenn (Ergebnis == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
  throw new BindingException("Mapper-Methode '" + command.getName() 
   + " Es wurde versucht, von einer Methode mit einem primitiven Rückgabetyp (" + method.getReturnType() + ") null zurückzugeben.");
 }
 Ergebnis zurückgeben;
 }

 privates Objekt rowCountResult(int rowCount) {
 endgültiges Objektergebnis;
 wenn (Methode.returnsVoid()) {
  Ergebnis = null;
 } sonst wenn (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
  Ergebnis = Zeilenanzahl;
 } sonst wenn (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
  Ergebnis = (lang)Zeilenanzahl;
 } sonst wenn (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
  Ergebnis = Zeilenanzahl > 0;
 } anders {
  throw new BindingException("Mapper-Methode '" + command.getName() + "' hat einen nicht unterstützten Rückgabetyp: " + method.getReturnType());
 }
 Ergebnis zurückgeben;
 }

 private void executeWithResultHandler(SqlSession sqlSession, Object[] args) {
 MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName());
 wenn (void.class.equals(ms.getResultMaps().get(0).getType())) {
  wirf eine neue BindingException("Methode " + command.getName() 
   + " benötigt entweder eine @ResultMap-Annotation, eine @ResultType-Annotation," 
   + " oder ein resultType-Attribut in XML, sodass ein ResultHandler als Parameter verwendet werden kann.");
 }
 Objektparameter = Methode.convertArgsToSqlCommandParam(args);
 wenn (Methode.hasRowBounds()) {
  Zeilenbegrenzungen Zeilenbegrenzungen = Methode.extractRowBounds(Argumente);
  sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args));
 } anders {
  sqlSession.select(command.getName(), param, method.extractResultHandler(args));
 }
 }

 private <E> Objekt executeForMany(SqlSession sqlSession, Objekt[] args) {
 Liste<E> Ergebnis;
 Objektparameter = Methode.convertArgsToSqlCommandParam(args);
 wenn (Methode.hasRowBounds()) {
  Zeilenbegrenzungen Zeilenbegrenzungen = Methode.extractRowBounds(Argumente);
  Ergebnis = sqlSession.<E>selectList(command.getName(), param, rowBounds);
 } anders {
  Ergebnis = sqlSession.<E>selectList(command.getName(), param);
 }
 // Problem Nr. 510 Unterstützung für Sammlungen und Arrays
 wenn (!method.getReturnType().isAssignableFrom(result.getClass())) {
  wenn (Methode.getReturnType().isArray()) {
  returniereconvertToArray(Ergebnis);
  } anders {
  returniere convertToDeclaredCollection(sqlSession.getConfiguration(), Ergebnis);
  }
 }
 Ergebnis zurückgeben;
 }

 private <T> Cursor<T> executeForCursor(SqlSession sqlSession, Object[] args) {
 Cursor<T> Ergebnis;
 Objektparameter = Methode.convertArgsToSqlCommandParam(args);
 wenn (Methode.hasRowBounds()) {
  Zeilenbegrenzungen Zeilenbegrenzungen = Methode.extractRowBounds(Argumente);
  Ergebnis = sqlSession.<T>selectCursor(command.getName(), param, rowBounds);
 } anders {
  Ergebnis = sqlSession.<T>selectCursor(command.getName(), param);
 }
 Ergebnis zurückgeben;
 }

 private <E> Objekt convertToDeclaredCollection(Konfiguration config, Liste<E> Liste) {
 Objektsammlung = config.getObjectFactory().create(method.getReturnType());
 MetaObject metaObject = config.newMetaObject(Sammlung);
 metaObject.addAll(Liste);
 Rücknahme;
 }
 @SuppressWarnings("nicht markiert")
 private <E> Objekt convertToArray(Liste<E> Liste) {
 Klasse<?> arrayComponentType = method.getReturnType().getComponentType();
 Objektarray = Array.newInstance(arrayComponentType, list.size());
 wenn (arrayComponentType.isPrimitive()) {
  für (int i = 0; i < list.size(); i++) {
  Array.set(array, i, list.get(i));
  }
  Array zurückgeben;
 } anders {
  gibt list.toArray((E[])array) zurück;
 }
 }
 private <K, V> Map<K, V> executeForMap(SqlSession sqlSession, Object[] args) {
 Map<K, V>-Ergebnis;
 Objektparameter = Methode.convertArgsToSqlCommandParam(args);
 wenn (Methode.hasRowBounds()) {
  Zeilenbegrenzungen Zeilenbegrenzungen = Methode.extractRowBounds(Argumente);
  Ergebnis = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey(), rowBounds);
 } anders {
  Ergebnis = sqlSession.<K, V>selectMap(command.getName(), param, method.getMapKey());
 }
 Ergebnis zurückgeben;
 }
 öffentliche statische Klasse ParamMap<V> erweitert HashMap<String, V> {
 private statische endgültige lange SerialVersionUID = -2212268410512043556L;
 @Überschreiben
 public V get(Objektschlüssel) {
  wenn (!super.containsKey(Schlüssel)) {
  throw new BindingException("Parameter '" + key + "' nicht gefunden. Verfügbare Parameter sind " + keySet());
  }
  return super.get(Schlüssel);
 }
 }
 öffentliche statische Klasse SqlCommand {
 privater endgültiger String-Name;
 privater endgültiger SqlCommandType-Typ;

 public SqlCommand(Konfiguration Konfiguration, Klasse<?> MapperInterface, Methode Methode) {
  endgültige Zeichenfolge methodName = method.getName();
  endgültige Klasse<?> declaringClass = method.getDeclaringClass();
  MappedStatement ms = resolveMappedStatement(Mapper-Schnittstelle, Methodenname, Deklarationsklasse,
   Konfiguration);
  wenn (ms == null) {
  wenn (Methode.getAnnotation(Flush.class) != null) {
   Name = null;
   Typ = SqlCommandType.FLUSH;
  } anders {
   throw new BindingException("Ungültige gebundene Anweisung (nicht gefunden): "
    + mapperInterface.getName() + "." + methodName);
  }
  } anders {
  Name = ms.getId();
  Typ = ms.getSqlCommandType();
  wenn (Typ == SqlCommandType.UNBEKANNT) {
   throw new BindingException("Unbekannte Ausführungsmethode für: " + Name);
  }
  }
 }
 öffentliche Zeichenfolge getName() {
  Rückgabename;
 }
 öffentliche SqlCommandType getType() {
  Rückgabetyp;
 }
 private MappedStatement resolveMappedStatement(Klasse<?> mapperInterface, String methodName,
  Klasse<?> deklarierendeKlasse, Konfigurationskonfiguration) {
  String-Anweisungs-ID = mapperInterface.getName() + "." + Methodenname;
  wenn (Konfiguration.hasStatement(statementId)) {
  gibt die Konfiguration zurück.getMappedStatement(statementId);
  } sonst wenn (mapperInterface.equals(declaringClass)) {
  gibt null zurück;
  }
  für (Klasse<?> superInterface : mapperInterface.getInterfaces()) {
  wenn (declaringClass.isAssignableFrom(superInterface)) {
   MappedStatement ms = resolveMappedStatement(superInterface, methodName,
    Deklarationsklasse, Konfiguration);
   wenn (ms != null) {
   Rückgabe ms;
   }
  }
  }
  gibt null zurück;
 }
 }

 öffentliche statische Klasse MethodSignature {
 privater finaler Boolescher Wert gibt Viele zurück;
 privater finaler Boolescher Wert gibt Map zurück;
 privater finaler Boolescher Wert gibt Void zurück;
 privater finaler Boolean-Wert gibt Cursor zurück;
 private endgültige Klasse<?> returnType;
 privater endgültiger String-MapKey;
 privater endgültiger Integer-ErgebnisHandlerIndex;
 privater endgültiger Integer-Zeilengrenzindex;
 privater finaler ParamNameResolver paramNameResolver;

 öffentliche MethodSignature(Konfigurationskonfiguration, Klasse<?> MapperInterface, Methode Methode) {
  Typ aufgelösterReturnType = TypeParameterResolver.resolveReturnType(Methode, Mapper-Schnittstelle);
  if (aufgelösterReturnType-Instanz der Klasse<?>) {
  this.returnType = (Klasse<?>) aufgelösterReturnType;
  } sonst wenn (aufgelösterReturnType Instanz von ParameterizedType) {
  this.returnType = (Klasse<?>) ((ParameterisierterTyp) aufgelösterReturnType).getRawType();
  } anders {
  this.returnType = method.getReturnType();
  }
  Dies.returnsVoid = void.class.equals(dies.returnType);
  this.returnsMany = (Konfiguration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());
  Dies.returnsCursor = Cursor.class.equals(dies.returnType);
  this.mapKey = getMapKey(Methode);
  this.returnsMap = (this.mapKey != null);
  this.rowBoundsIndex = getUniqueParamIndex(Methode, RowBounds.Klasse);
  this.resultHandlerIndex = getUniqueParamIndex(Methode, ResultHandler.Klasse);
  this.paramNameResolver = neuer ParamNameResolver(Konfiguration, Methode);
 }

 öffentliches Objekt convertArgsToSqlCommandParam(Object[] args) {
  gibt paramNameResolver.getNamedParams(args) zurück;
 }

 öffentliches Boolean hasRowBounds() {
  gibt rowBoundsIndex zurück != null;
 }

 öffentliche RowBounds extractRowBounds(Objekt[] args) {
  returniere hasRowBounds() ? (RowBounds) args[rowBoundsIndex] : null;
 }

 öffentliches Boolean hasResultHandler() {
  gibt resultHandlerIndex zurück != null;
 }

 öffentlicher ResultHandler extractResultHandler(Object[] args) {
  gibt hasResultHandler() zurück? (ResultHandler) args[resultHandlerIndex] : null;
 }

 öffentliche Zeichenfolge getMapKey() {
  MapKey zurückgeben;
 }

 öffentliche Klasse<?> getReturnType() {
  Rückgabewerttyp zurückgeben;
 }

 öffentliches Boolean gibt viele zurück() {
  returniert viele zurück;
 }

 öffentliches Boolean returnsMap() {
  Rückgabewert der Karte;
 }

 öffentlicher Boolescher Wert returnsVoid() {
  Rückgabe gibt Void zurück;
 }

 öffentlicher Boolescher Wert returnsCursor() {
  returniert den Cursor;
 }
 private Integer getUniqueParamIndex(Methode methode, Klasse<?> paramType) {
  Integer-Index = null;
  letzte Klasse<?>[] argTypes = method.getParameterTypes();
  für (int i = 0; i < argTypes.length; i++) {
  wenn (paramType.isAssignableFrom(argTypes[i])) {
   wenn (index == null) {
   Index = i;
   } anders {
   throw new BindingException(method.getName() + " kann nicht mehrere " + paramType.getSimpleName() + " Parameter haben");
   }
  }
  }
  Rückgabeindex;
 }
 private String getMapKey(Methode Methode) {
  Zeichenfolge mapKey = null;
  wenn (Map.class.isAssignableFrom(method.getReturnType())) {
  endgültige MapKey mapKeyAnnotation = method.getAnnotation(MapKey.class);
  if (mapKeyAnnotation != null) {
   mapKey = mapKeyAnnotation.value();
  }
  }
  MapKey zurückgeben;
 }
 }

Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, er wird für jedermanns Studium hilfreich sein. Ich hoffe auch, dass jeder 123WORDPRESS.COM unterstützen wird.

Das könnte Sie auch interessieren:
  • So entfernen Sie die Mapper-Warnmethodenanalyse in Idea
  • Beispielanalyse des Arbeitsprinzips der Mybatis Mapper-Schnittstelle
  • MyBatis Mapper akzeptiert vier Möglichkeiten der Parametercodeanalyse
  • Detaillierte Erläuterung der beiden Möglichkeiten zum Einfügen der Mapper-Schnittstelle
  • Springboot-Integration, allgemeine Mapper-Prozessanalyse
  • Detaillierte Erklärung des Prinzips der Implementierung von Datenbankaufrufen mithilfe des MyBatis Mapper-Proxys
  • So generieren Sie automatisch Mybatis Mapper-Dateien
  • So erstellen Sie mit IDEA ein MAPPER-Vorlagenprozessdiagramm

<<:  CentOS 7 erstellt Hadoop 2.10 mit hoher Verfügbarkeit (HA)

>>:  Vue3.0 implementiert die Fallstudie zum Lupeneffekt

Artikel empfehlen

So stellen Sie MySQL- und Redis-Dienste mit Docker bereit

Inhaltsverzeichnis So stellen Sie den MySQL-Diens...

So öffnen Sie externe Netzwerkzugriffsrechte für MySQL

Wie unten dargestellt: Führen Sie hauptsächlich A...

Grafisches Tutorial zur Offline-Installation und Konfiguration von MySQL 8.0.2

Die Offline-Installationsmethode von MySQL_8.0.2 ...

Detaillierte Erklärung der Datenmengen von Docker-Containern

Was ist Schauen wir uns zunächst das Konzept von ...

Einfacher Webseitencode, der im NetEase-Blog verwendet wird

So verwenden Sie den Code im NetEase-Blog: Melden...

Detaillierte Erläuterung der Verwendung des gcc-Befehls unter Linux

Inhaltsverzeichnis 1. Vorverarbeitung 2. Zusammen...

Javascript zum Erzielen eines Trommeleffekts

In diesem Artikel wird der spezifische Code von J...

WeChat-Applet implementiert Suchfunktion und springt zur Suchergebnisseite

Suchseite: search.wxml-Seite: <view class=&quo...

Detaillierte Erklärung von PID und Socket in MySQL

Inhaltsverzeichnis 1. Einführung in die PID-Datei...

Lösung zur Schnittstellenverformung beim Einstellen der Frameset-Höhe

Derzeit habe ich ein Projekt erstellt, die Schnitt...