Recently, when I saw the template method of spring's JDBCTemplete, I became very interested in templates and callbacks, and I queryed some information and made some summary.
Callback function:
The so-called callback means that the client program C calls a certain function A in the service program S, and then S calls a certain function B in C at some time. For C, this B is called a callback function. A callback function is just a function that is implemented by the user according to the callback function calling convention. A callback function is part of a workflow, and the workflow determines the timing of the function's 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 who B is named after C, S will agree on B's interface specification (function prototype), and then C will tell S in advance that he will use B function through a function R of S. This process is called registration of callback function, and R is called registration function. Web Service and Java RMI use callback mechanisms to access remote server programs. The callback function contains the following characteristics:
1. Belongs to a part of the workflow;
2. It must be declared (defined) in accordance with the calling convention specified by the workflow;
3. The timing of its 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 design model. It exposes a function in 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 complete execution before returning. It is a one-way call;
Callback: a two-way calling mode, that is, the called party will also call the other party's interface when the interface is called;
Asynchronous call: a mechanism similar to a message or event, but its calling direction is just the opposite. When an interface service receives a certain message or an event occurs, it will actively notify the client (that is, call the client's interface).
The relationship between callbacks and asynchronous calls is very closely related: callbacks are used to implement the registration of asynchronous messages, and notification of messages is achieved through asynchronous calls.
Callback instance
1. Callback interface
public interface Callback { String callBack(); } 2. Caller
public class Another { private Callback callback; //Calling the method that implements the class public void setCallback(Callback callback) { this.callback = callback; } //When business needs it, call the specific method that implements the class public void doCallback(){ System.out.println(callback.callBack()); }} 3. Test callback function
public class TestCallcack { public static void main(String[] args) { //Create the caller's implementation class Another another = new Another(); //Register the back interface into the implementation class another.setCallback(new Callback() { @Override public String callBack() { return "you are a pig"; } }); //Execute the callback function 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 delays some steps to the design pattern implemented in the subclass. The template method design pattern allows subclasses to redefine certain specific steps of an algorithm without changing the structure of an algorithm.
Applicability of template design pattern:
1. Implement the unchanging part of an algorithm at one time and leave the variable algorithm to subclasses to implement it.
2. Public behaviors in each subclass should be extracted and concentrated in a public parent class to avoid code duplication.
3. Subclass extensions can be controlled.
Template example:
Abstract template method class:
public abstract class AbstractSup { //Methods that require subclass implementation public abstract void print(); //Template method public void doPrint(){ System.out.println("Execute template method"); 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("Implementation method of subclasses"); }} Template method test class:
public class TempleteTest { public static void main(String[] args) { SubClass subClass = new SubClass(); subClass.print(); subClass.doPrint(); }} The following is a detailed introduction to the use of spring template method. Taking JdbcTemplete as an example, we will explain in detail the use of template mode and callback mechanism.
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 requires such a lot of things and also dealing with exceptions. Let's sort it out if we don't want to:
1. Get connection
2. Obtain statement
3. Obtain resultset
4. Iterate through the resultset and encapsulate it into a collection
5. Close connection, statement, and resultset in turn, and consider various exceptions, etc.
If multiple queries will generate more duplicate code, you can use the template mechanism. Through observation, we found that most of the above steps are repetitive and reusable. Only when traversing the ResultSet and encapsulating it into a collection is customizable, because each table maps different java beans. There is no way to reuse this part of the code, it can only be customized.
Abstract class code:
public abstract class JdbcTemplate { //Template method 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);//Abstract method (customized method, subclass implementation required) 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(); } } } //Abstract method (custom method) protected abstract Object doInStatement(ResultSet rs); }In this abstract class, the main process of the SUN JDBC API is encapsulated, and the step of traversing the ResultSet is placed in the abstract method doInStatement(), which is implemented by the subclass.
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 template mechanism has been used so far, but if you need to inherit the parent class every time you call jdbcTemplate, it is quite inconvenient, so the callback mechanism can play a role.
The so-called callback means passing an interface in the method parameters. When the parent class calls this method, it must call the implementation class of the interface passed in the method.
Callback plus template mode implementation
Callback interface:
public interface StatementCallback { Object doInStatement(Statement stmt) throws SQLException; } Template method:
public class JdbcTemplate { //Template method public final Object execute(StatementCallback action) throws SQLException{ Connection con = HsqldbUtil.getConnection(); Statement stmt = null; try { stmt = con.createStatement(); Object result = action.doInStatement(rs);//Callback method 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); } } } Tested class:
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()); }
Why doesn't spring use traditional template methods, but also cooperate with Callback?
Just imagine, if there are 10 abstract methods in the parent class and all subclasses that inherit it need to implement all of these 10 abstract methods, the subclass will appear very bloated. Sometimes, what should I do if a subclass only needs to customize a certain method in the parent class? At this time, Callback is used.
In addition, the above method basically implements the template method + callback mode. But it's still a little far from spring's jdbcTemplate. Although we implemented the template method + callback mode above, it seems a bit "ugly" compared to Spring's JdbcTemplate. Spring introduces the concepts of RowMapper and ResultSetExtractor. The RowMapper interface is responsible for processing a certain row of data. For example, we can operate on a certain row of records in the mapRow method, or encapsulate it into entity. The ResultSetExtractor is a dataset extractor, which is responsible for traversing the ResultSet and processing the data according to the rules in the RowMapper. The difference between RowMapper and ResultSetExtractor is that RowMapper processes a certain row of data and returns an entity object. The ResultSetExtractor processes a data set and returns a collection of objects.
Of course, the above is just the basic principles of Spring JdbcTemplate implementation. Spring JdbcTemplate has done more things, such as encapsulating all basic operations into the JdbcOperations interface, and using JdbcAccessor to manage DataSource and conversion exceptions.
The above is all about this article, I hope it will be helpful to everyone's learning.