Home  >  Article  >  Java  >  Detailed explanation of java templates and callback mechanism

Detailed explanation of java templates and callback mechanism

高洛峰
高洛峰Original
2017-01-24 13:37:241169browse

When I recently looked at the template method call of spring's JDBCTemplete, I became very interested in templates and callbacks. I queried some information and made some summaries.

Callback function:

The so-called callback means that the client program C calls a function A in the service program S, and then S in turn calls a function B in C at a certain time. , for C, this B is called the callback function. The callback function is just a functional fragment, a function implemented by the user according to the callback function calling convention. The callback function is part of a workflow, and the workflow determines the timing of the function call (callback). Generally speaking, C will not call B by itself. The purpose of C providing B is to let S call it, and C has to provide it. Since S does not know the name of B provided by C, S will agree on the interface specification (function prototype) of B, and then C will tell S in advance that it will use the B function through a function R of S. This process is called a callback. Registration of a function, R is called a registered function. Web Service and Java's RMI both use callback mechanisms to access remote server programs. The callback function includes the following characteristics:

1. It is a part of the workflow;

2. It must be declared (defined) according to the calling convention specified by the workflow;

3. The timing of his call is determined by the workflow. The implementer of the callback function cannot directly call the callback function to implement the function of the workflow;

Callback mechanism:

The callback mechanism is a common The design model exposes a certain function within the workflow to external users according to the agreed interface, provides data to external users, or requires external users to provide data.

java callback mechanism:

There are always certain interfaces between software modules. In terms of calling methods, they can be divided into three categories: synchronous calls, callbacks and asynchronous calls.

Synchronous call: a blocking call, the caller has to wait for the other party to finish executing before returning, it is a one-way call;

Callback: a two-way calling mode, that is That is to say, the callee will also call the other party's interface when the interface is called;

Asynchronous call: a mechanism similar to messages or events, but its calling direction is exactly the opposite. The service of the interface receives a certain When a message or an event occurs, the client will be notified proactively (that is, the client's interface will be called).

The relationship between callbacks and asynchronous calls is very close: callbacks are used to register asynchronous messages, and asynchronous calls are used to notify messages.

Callback instance

1, callback interface

public interface Callback {
 
   String callBack();
 }

2, caller

public class Another {
  private Callback callback;
  //调用实现类的方法
  public void setCallback(Callback callback) {
    this.callback = callback;
  }
    //业务需要的时候,通过委派,来调用实现类的具体方法
  public void doCallback(){
    System.out.println(callback.callBack());
  }
}

3, Test callback function

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

The use of callback methods usually occurs during the use of "java interface" and "abstract class". The template method design pattern uses the method callback mechanism. This pattern first defines the algorithm skeleton of specific steps and defers some steps to subclasses for implementation. The template method design pattern allows subclasses to redefine specific steps of an algorithm without changing the structure of the algorithm.

Applicability of template design pattern:

1. Implement the constant part of an algorithm at one time, and leave the variable algorithm to subclasses for implementation.

 2. Common behaviors in each subclass should be extracted and concentrated in a common parent class to avoid code duplication.

 3. Can control subclass expansion.

Template instance:

Abstract template method class:

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

Subclass implementation template method class:

public class SubClass extends AbstractSup{
  @Override
  public void print() {
    System.out.println("子类的实现方法");
  }
 
}

Template method test class:

public class TempleteTest {
  public static void main(String[] args) {
    SubClass subClass = new SubClass();
    subClass.print();
    subClass.doPrint();
  }
}

The following is an in-depth introduction to the use of spring template methods. Taking JdbcTemplete as an example, the use of template mode and callback mechanism is explained in detail.
First, let’s take a look at the classic JDBC programming example:

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

A simple query has to do so many things, and it also has to handle exceptions. Let’s sort it out:
1. Get the connection
2. Get the statement
3. Get the resultset
4. Traverse the resultsset and encapsulate it into a collection
5. Close the connection, statement, and resultsset in sequence, and consider various exceptions, etc. wait.

If multiple queries will generate more duplicate codes, you can use the template mechanism at this time. Through observation, we found that most of the above steps are repeated and reusable. Only when traversing the ResultSet This step of encapsulating it into a collection is customizable because each table maps a different java bean. This part of the code cannot be reused and can only be customized.

Abstract class code:

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

This abstract class encapsulates the main process of the SUN JDBC API, and the step of traversing the ResultSet is Put it in the abstract method doInStatement(), and the subclass is responsible for implementing it.

Subclass implementation code:

public class JdbcTemplateUserImpl extends JdbcTemplate {
  
  @Override
  protected Object doInStatement(ResultSet rs) {
    List<User> userList = new ArrayList<User>();
      
    try {
      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;
    } catch (SQLException e) {
      e.printStackTrace();
      return null;
    }
  }
  
}

In the doInStatement() method, we traverse the ResultSet and finally return it.

Test code:

String sql = "select * from User";
JdbcTemplate jt = new JdbcTemplateUserImpl();
List<User> userList = (List<User>) jt.execute(sql);

The use of the template mechanism ends here, but if you have to inherit the above parent class every time you call jdbcTemplate, this is not very convenient. Conveniently, this way the callback mechanism can come into play.

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

回调加模板模式实现

回调接口:

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中文网!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn