Heim  >  Artikel  >  Java  >  Detaillierte Erläuterung der Java-Vorlagen und des Rückrufmechanismus

Detaillierte Erläuterung der Java-Vorlagen und des Rückrufmechanismus

高洛峰
高洛峰Original
2017-01-24 13:37:241171Durchsuche

Als ich mir kürzlich die Vorlagenmethode von Springs JDBCTemplete ansah, interessierte ich mich sehr für Vorlagen und Rückrufe. Ich habe einige Informationen abgefragt und einige Zusammenfassungen erstellt.

Callback-Funktion:

Der sogenannte Callback bedeutet, dass das Client-Programm C eine Funktion A im Dienstprogramm S aufruft und dann S wiederum zu einem bestimmten Zeitpunkt eine Funktion B in C aufruft Für C wird dieses B als Callback-Funktion bezeichnet. Die Rückruffunktion ist nur ein Funktionsfragment, eine Funktion, die vom Benutzer gemäß der Aufrufkonvention für Rückruffunktionen implementiert wird. Die Callback-Funktion ist Teil eines Workflows und der Workflow bestimmt den Zeitpunkt des Funktionsaufrufs (Callback). Im Allgemeinen ruft C B nicht selbst auf. Der Zweck der Bereitstellung von B durch C besteht darin, dass S es aufrufen kann, und C muss es bereitstellen. Da S den von C bereitgestellten Namen von B nicht kennt, stimmt S der Schnittstellenspezifikation (Funktionsprototyp) von B zu, und dann teilt C S im Voraus mit, dass es die B-Funktion über eine Funktion R von S verwenden wird. Dies Der Prozess wird als Rückruf einer Funktion bezeichnet, R wird als registrierte Funktion bezeichnet. Web Service und Javas RMI nutzen beide Callback-Mechanismen, um auf Remote-Server-Programme zuzugreifen. Die Rückruffunktion umfasst die folgenden Merkmale:

1. Sie ist Teil des Workflows

2. Sie muss gemäß der durch den Workflow angegebenen Aufrufkonvention deklariert (definiert) werden; 🎜>

3. Der Zeitpunkt seines Aufrufs wird durch den Workflow bestimmt. Der Implementierer der Callback-Funktion kann die Callback-Funktion nicht direkt aufrufen, um die Funktion des Workflows zu implementieren:

Der Rückrufmechanismus ist ein gängiges Designmodell, das gemäß der vereinbarten Schnittstelle eine bestimmte Funktion innerhalb des Workflows für externe Benutzer verfügbar macht, Daten für externe Benutzer bereitstellt oder von externen Benutzern die Bereitstellung von Daten verlangt.

Java-Rückrufmechanismus:

Es gibt immer bestimmte Schnittstellen zwischen Softwaremodulen. Hinsichtlich der Aufrufmethoden können sie in drei Kategorien unterteilt werden: synchrone Aufrufe, Rückrufe und asynchrone Aufrufe.

Synchroner Anruf: Ein blockierender Anruf. Der Anrufer muss warten, bis die andere Partei die Ausführung beendet hat. Es handelt sich um einen einseitigen Anruf Das heißt, der Angerufene ruft auch die Schnittstelle der anderen Partei auf, wenn die Schnittstelle aufgerufen wird Die Schnittstelle empfängt eine bestimmte Nachricht oder ein Ereignis, und der Client wird proaktiv benachrichtigt (dh die Schnittstelle des Clients wird aufgerufen).

Rückrufe und asynchrone Anrufe hängen eng zusammen: Rückrufe werden zum Registrieren asynchroner Nachrichten verwendet, und asynchrone Anrufe werden zum Benachrichtigen von Nachrichten verwendet.

Callback-Instanz

1. Callback-Schnittstelle

2 >3. Callback-Funktion testen

public interface Callback {
 
   String callBack();
 }

Die Verwendung von Callback-Methoden erfolgt normalerweise bei der Verwendung von „Java-Schnittstelle“ und „abstrakter Klasse“. Das Entwurfsmuster für Vorlagenmethoden verwendet den Methodenrückrufmechanismus. Dieses Muster definiert zunächst das Algorithmusgerüst bestimmter Schritte und verschiebt einige Schritte zur Implementierung an Unterklassen. Das Entwurfsmuster der Vorlagenmethode ermöglicht es Unterklassen, bestimmte Schritte eines Algorithmus neu zu definieren, ohne die Struktur des Algorithmus zu ändern.

Die Anwendbarkeit des Vorlagenentwurfsmusters:

public class Another {
  private Callback callback;
  //调用实现类的方法
  public void setCallback(Callback callback) {
    this.callback = callback;
  }
    //业务需要的时候,通过委派,来调用实现类的具体方法
  public void doCallback(){
    System.out.println(callback.callBack());
  }
}
1. Implementieren Sie den konstanten Teil eines Algorithmus auf einmal und überlassen Sie den variablen Algorithmus zur Implementierung den Unterklassen.

2. Gemeinsame Verhaltensweisen in jeder Unterklasse sollten extrahiert und in einer gemeinsamen übergeordneten Klasse konzentriert werden, um Codeduplizierung zu vermeiden.

3. Sie können die Erweiterung der Unterklasse steuern.
public class TestCallcack {
  public static void main(String[] args) {
    //创建调用者的实现类
    Another another = new Another();
    //将回掉接口注册到实现类中
    another.setCallback(new Callback() { 
      @Override
      public String callBack() {
        return "you are a pig";
      }
    });
    //执行回调函数
    another.doCallback();
  }
}

Vorlageninstanz:

Abstrakte Vorlagenmethodenklasse:

Unterklassenimplementierungsvorlagenmethodenklasse:

Testklasse für Vorlagenmethoden:

public abstract class AbstractSup {
    //需要子类实现的方法
  public abstract void print();
    //模板方法
  public void doPrint(){
    System.out.println("执行模板方法");
    for (int i = 0; i < 3; i++) {
      print();
    }
  }
}

Das Folgende ist eine ausführliche Einführung in die Verwendung von Spring-Vorlagenmethoden, der Vorlage Die Verwendung von Modus und Rückrufmechanismus wird ausführlich erläutert.

Schauen wir uns zunächst ein klassisches JDBC-Programmierbeispiel an:

public class SubClass extends AbstractSup{
  @Override
  public void print() {
    System.out.println("子类的实现方法");
  }
 
}
Eine einfache Abfrage muss so viele Dinge tun und auch Ausnahmen verarbeiten:

1. Holen Sie sich die Verbindung

3. Holen Sie sich die Ergebnismenge und kapseln Sie sie in eine Sammlung

Reihenfolge, und berücksichtigen Sie auch verschiedene Ausnahmen usw.

public class TempleteTest {
  public static void main(String[] args) {
    SubClass subClass = new SubClass();
    subClass.print();
    subClass.doPrint();
  }
}
Wenn mehrere Abfragen mehr doppelte Codes generieren, können Sie zu diesem Zeitpunkt den Vorlagenmechanismus verwenden. Durch Beobachtung haben wir festgestellt, dass die meisten der oben genannten Schritte nur beim Durchlaufen des ResultSets wiederholt werden Das Einfügen in eine Sammlung ist anpassbar, da jede Tabelle eine andere Java-Bean zuordnet. Dieser Teil des Codes kann nicht wiederverwendet und nur angepasst werden.

Abstrakter Klassencode:


public List<User> query() {
  
  List<User> userList = new ArrayList<User>();
  String sql = "select * from User";
  
  Connection con = null;
  PreparedStatement pst = null;
  ResultSet rs = null;
  try {
    con = HsqldbUtil.getConnection();
    pst = con.prepareStatement(sql);
    rs = pst.executeQuery();
  
    User user = null;
    while (rs.next()) {
  
      user = new User();
      user.setId(rs.getInt("id"));
      user.setUserName(rs.getString("user_name"));
      user.setBirth(rs.getDate("birth"));
      user.setCreateDate(rs.getDate("create_date"));
      userList.add(user);
    }
  
  
  } catch (SQLException e) {
    e.printStackTrace();
  }finally{
    if(rs != null){
      try {
        rs.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
    try {
      pst.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
    try {
      if(!con.isClosed()){
        try {
          con.close();
       } catch (SQLException e) {
          e.printStackTrace();
        }
      }
    } catch (SQLException e) {
      e.printStackTrace();
    }
      
  }
  return userList;
}



Diese abstrakte Klasse kapselt den Hauptprozess der SUN JDBC-API und durchläuft die ResultSet-Schritte werden in der abstrakten Methode doInStatement() platziert, die von der Unterklasse implementiert wird.

Unterklassen-Implementierungscode:

public abstract class JdbcTemplate {
  
  //模板方法
  public final Object execute(String sql) throws SQLException{
    
    Connection con = HsqldbUtil.getConnection();
    Statement stmt = null;
    try {
   
      stmt = con.createStatement();
      ResultSet rs = stmt.executeQuery(sql);
      Object result = doInStatement(rs);//抽象方法(定制方法,需要子类实现) 
      return result;
    }
    catch (SQLException ex) {
       ex.printStackTrace();
       throw ex;
    }
    finally {
   
      try {
        stmt.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
      try {
        if(!con.isClosed()){
          try {
            con.close();
          } catch (SQLException e) {
            e.printStackTrace();
          }
        }
      } catch (SQLException e) {
        e.printStackTrace();
      }
        
    }
  }
    
  //抽象方法(定制方法)
  protected abstract Object doInStatement(ResultSet rs);
}
In der doInStatement()-Methode durchlaufen wir das ResultSet und geben es schließlich zurück.

Testcode:

Die Verwendung des Vorlagenmechanismus endet hier. Wenn Sie jedoch jedes Mal jdbcTemplate aufrufen, müssen Sie die oben genannte übergeordnete Klasse erben Es ist ziemlich unpraktisch, daher kann der Rückrufmechanismus ins Spiel kommen.

所谓回调,就是方法参数中传递一个接口,父类在调用此方法时,必须调用方法中传递的接口的实现类。

回调加模板模式实现

回调接口:

public interface StatementCallback {
  Object doInStatement(Statement stmt) throws SQLException;
 }

 模板方法:

public class JdbcTemplate {
  
  //模板方法
  public final Object execute(StatementCallback action) throws SQLException{
      
    Connection con = HsqldbUtil.getConnection();
    Statement stmt = null;
    try {
   
      stmt = con.createStatement();
      Object result = action.doInStatement(rs);//回调方法
      return result;
    }
    catch (SQLException ex) {
       ex.printStackTrace();
       throw ex;
    }
    finally {
   
      try {
        stmt.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
      try {
        if(!con.isClosed()){
          try {
            con.close();
          } catch (SQLException e) {
            e.printStackTrace();
          }
        }
      } catch (SQLException e) {
        e.printStackTrace();
      }
        
    }
  }    
  }
  public Object query(StatementCallback stmt) throws SQLException{
    return execute(stmt);
  }
}

   

测试的类:

public Object query(final String sql) throws SQLException {
    class QueryStatementCallback implements StatementCallback {
  
      public Object doInStatement(Statement stmt) throws SQLException {
        ResultSet rs = stmt.executeQuery(sql);
        List<User> userList = new ArrayList<User>();
  
        User user = null;
        while (rs.next()) {
  
          user = new User();
          user.setId(rs.getInt("id"));
          user.setUserName(rs.getString("user_name"));
          user.setBirth(rs.getDate("birth"));
          user.setCreateDate(rs.getDate("create_date"));
          userList.add(user);
        }
        return userList;
  
      }
  
    }
  
    JdbcTemplate jt = new JdbcTemplate();
    return jt.query(new QueryStatementCallback());
  }

   


为什么spring不用传统的模板方法,而加之以Callback进行配合呢? 
试想,如果父类中有10个抽象方法,而继承它的所有子类则要将这10个抽象方法全部实现,子类显得非常臃肿。而有时候某个子类只需要定制父类中的某一个方法该怎么办呢?这个时候就要用到Callback回调了。

另外,上面这种方式基本上实现了模板方法+回调模式。但离spring的jdbcTemplate还有些距离。 我们上面虽然实现了模板方法+回调模式,但相对于Spring的JdbcTemplate则显得有些“丑陋”。Spring引入了RowMapper和ResultSetExtractor的概念。 RowMapper接口负责处理某一行的数据,例如,我们可以在mapRow方法里对某一行记录进行操作,或封装成entity。 ResultSetExtractor是数据集抽取器,负责遍历ResultSet并根据RowMapper里的规则对数据进行处理。 RowMapper和ResultSetExtractor区别是,RowMapper是处理某一行数据,返回一个实体对象。而ResultSetExtractor是处理一个数据集合,返回一个对象集合。

  当然,上面所述仅仅是Spring JdbcTemplte实现的基本原理,Spring JdbcTemplate内部还做了更多的事情,比如,把所有的基本操作都封装到JdbcOperations接口内,以及采用JdbcAccessor来管理DataSource和转换异常等。

以上就是本文的全部内容,希望对大家的学习有所帮助。

更多详解java模板和回调机制相关文章请关注PHP中文网!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn