关于 回调 的一些理解(以jdbctemplate为例)

以前一起没有很好的理解 “回调”,偶然的机会下,看了一下spring的jdbctemplate,觉得对回调的理解很有帮助,就稍微自己总结一下,以便日后温习.
回调: 就是在方法的参数中传递一个接口,父在调用此方法时,必须调用方法中传递的接口的实现类。
看一段代码:
定义一个接口,作为方法中的参数:

import java.sql.SQLException;  
import java.sql.Statement;  

public interface StatementCallback {    
    //这个doInStatement相当于上面的doResultSet  
    Object doInStatement(Statement stmt) throws SQLException;    
}

定义一个方法,它的参数中含有上面定义的接口:

import java.sql.Connection;  
import java.sql.DriverManager;  
import java.sql.ResultSet;  
import java.sql.SQLException;  
import java.sql.Statement;  

public  class JDBCTemplate  {  
    public Object execute(StatementCallback action) {  
        String  url="";  
        String  userName="";  
        String  password="";  
        Connection con=null;  
        Statement st=null;  
        ResultSet rs=null;  
        try{  
            Class.forName("com.mysql.jdbc.driver");
            con=DriverManager.getConnection(url,userName,password);  
            st=con.createStatement();  
            Object object=action.doInStatement(st);  
            return object;            
        }  
        //省略try catch  
        return null;  
    }  


    public  Object query(StatementCallback action){  
        return execute(action);  
    }  

} 

下面的测试方法,只要给定一个sql,就能传回List

    @SuppressWarnings("unchecked")  
    public List<Student> test2(final String sql) {  
        JDBCTemplate jdbcTemplate = new JDBCTemplate();  
        return (List<Student>) jdbcTemplate.query(new StatementCallback() {  
            @Override  
            public Object doInStatement(Statement stmt) throws SQLException {  
                ResultSet rs = stmt.executeQuery(sql);  
                List<Student> userList = new ArrayList<Student>();  

                Student user = null;  
                while (rs.next()) {  
                    user = new Student();  
                    user.setId(rs.getInt("id"));  
                    user.setBirth(rs.getDate("birth"));  
                    userList.add(user);  
                }  
                return userList;  
            }  
        });  

    }  

在test中调用jdbctemplate的query()方法,参数为接口StatementCallback的一个实现类,并自定义实现了doInStatement()方法,当代码执行到Object object=action.doInStatement(st);时,会执行自定义实现了doInStatement()方法,实现回调.

再看一个难一点的示例,加深理解.
代码片段一:

    //主调用方法. 调用spring jdbctemplate的query()方法,参数中实现了RowCallbackHandler接口的processRow(ResultSet rs)方法.
    jt.query(sql, params, new RowCallbackHandler() {  
            @Override  
            public void processRow(ResultSet rs) throws SQLException {  
                Map<String, String> u = new HashMap<String, String>();  
                u.put("id", rs.getString("id"));  
                u.put("description", rs.getString("description"));  
                list.add(u);
            }  
        });  

以下均为spring jdbctemplate 源代码

代码片段二: 记为query_1()方法

    public void query(String sql, Object[] args, RowCallbackHandler rch) throws DataAccessException {  
        query(sql, newArgPreparedStatementSetter(args), rch);  
    }  

    protected PreparedStatementSetter newArgPreparedStatementSetter(Object[] args) {
        return new ArgumentPreparedStatementSetter(args);
    }

public class ArgumentPreparedStatementSetter implements PreparedStatementSetter, ParameterDisposer {
    private final Object[] args;

    public ArgumentPreparedStatementSetter(Object[] args) {
        this.args = args;
    }

    public void setValues(PreparedStatement ps) throws SQLException {
        if(this.args != null) {
            for(int i = 0; i < this.args.length; ++i) {
                Object arg = this.args[i];
                this.doSetValue(ps, i + 1, arg);
            }
        }

    }

    protected void doSetValue(PreparedStatement ps, int parameterPosition, Object argValue) throws SQLException {
        if(argValue instanceof SqlParameterValue) {
            SqlParameterValue paramValue = (SqlParameterValue)argValue;
            StatementCreatorUtils.setParameterValue(ps, parameterPosition, paramValue, paramValue.getValue());
        } else {
            StatementCreatorUtils.setParameterValue(ps, parameterPosition, -2147483648, argValue);
        }

    }
}

代码片段三:记为query_2()方法

    public void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch) throws DataAccessException {
        this.query((String)sql, (PreparedStatementSetter)pss, (ResultSetExtractor)(new JdbcTemplate.RowCallbackHandlerResultSetExtractor(rch)));
    }

    private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor<Object> {
        private final RowCallbackHandler rch;

        public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) {
            this.rch = rch;
        }

        public Object extractData(ResultSet rs) throws SQLException {
            while(rs.next()) {
                this.rch.processRow(rs);
            }
            return null;
        }
    }

代码片段四:记为query_3()方法

    public <T> T query(String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException {
        return this.query((PreparedStatementCreator)(new JdbcTemplate.SimplePreparedStatementCreator(sql)), (PreparedStatementSetter)pss, (ResultSetExtractor)rse);
    }

    private static class SimplePreparedStatementCreator implements PreparedStatementCreator, SqlProvider {
        private final String sql;

        public SimplePreparedStatementCreator(String sql) {
            Assert.notNull(sql, "SQL must not be null");
            this.sql = sql;
        }

        public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
            return con.prepareStatement(this.sql);
        }

        public String getSql() {
            return this.sql;
        }
    }

代码片段五:记为query_4()方法

    public <T> T query(  
                PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)  
                throws DataAccessException {  
            //注意匿名类  
            //execute一共两个参数 一个是PreparedStatementCreator 一个是PreparedStatementCallback  
            //***************3  
            return execute(psc, new PreparedStatementCallback<T>() {  
                public T doInPreparedStatement(PreparedStatement ps) throws SQLException {  
                    ResultSet rs = null;  
                    try {  
                        if (pss != null) {  
                            pss.setValues(ps);  
                        }  
                        rs = ps.executeQuery();  //最最核心的一步 调用jdk的接口  
                        ResultSet rsToUse = rs;  
                        if (nativeJdbcExtractor != null) {  
                            rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);  
                        }  
                        return rse.extractData(rsToUse);  
                    }  
                    finally {  
                        JdbcUtils.closeResultSet(rs);  
                        if (pss instanceof ParameterDisposer) {  
                            ((ParameterDisposer) pss).cleanupParameters();  
                        }  
                    }  
                }  
            });  
        }  

代码片段六:

    public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)  
                throws DataAccessException {  
            Connection con = DataSourceUtils.getConnection(getDataSource());  
            PreparedStatement ps = null;  
            try {  
                Connection conToUse = con;  
                //*******1   获得PreparedStatement  
                ps = psc.createPreparedStatement(conToUse);  
                //这里是给PreparedStatement设置一些参数 基本不怎么用 不用深究  
                applyStatementSettings(ps);  
                PreparedStatement psToUse = ps;  

                //跟上面的conToUse一样 暂且不管  
                if (this.nativeJdbcExtractor != null) {  
                    psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);  
                }  
                //************2 回调方法 我们得回到代码3处  
                T result = action.doInPreparedStatement(psToUse);  
                handleWarnings(ps);  
                return result;  
            }  
            catch (SQLException ex) {  
                //  
            }  
            finally {  
            //  
            }  
        }

1.在代码片段一中,调用了spring jdbctemplate源码中的query_1()方法,并传递了自定义RowCallbackHandler接口实现类为参数.
2.在代码片段二中query_1()方法执行newArgPreparedStatementSetter(args)时,最终会调用ArgumentPreparedStatementSetter类的构造方法,将sql语句中的参数转变成ArgumentPreparedStatementSetter的属性,并将生成的ArgumentPreparedStatementSetter对象作为参数传给query_2().
3.在代码片段三中query_2()方法执行(ResultSetExtractor)(new JdbcTemplate.RowCallbackHandlerResultSetExtractor(rch))时,会将自定义实现的RowCallbackHandler接口实现类转变成ResultSetExtractor对象,并作为参数传递给query_3().
4.在代码片段四中query_3()方法执行(PreparedStatementCreator)(new JdbcTemplate.SimplePreparedStatementCreator(sql))时,将sql转变成PreparedStatementCreator对象,并传递给query_4().
5.在代码片段五中query_4()方法调用片段六中的execute()方法时,自定义实现了PreparedStatementCallback接口,并在实现PreparedStatementCallback接口时,使用了传入的参数PreparedStatementSetter对象和ResultSetExtractor对象,
6.在代码片段六中execute()方法执行T result = action.doInPreparedStatement(psToUse);时,回调方法,代码执行回到了在代码片段五中自定义实现PreparedStatementCallback接口的doInPreparedStatement()方法;
当doInPreparedStatement()中的代码执行到pss.setValues(ps)时,会调用代码片段二中生成的ArgumentPreparedStatementSetter对象的setValues()方法;
当doInPreparedStatement()中的代码执行到rse.extractData(rsToUse)时,会调用代码片段三中生成的ResultSetExtractor对象的extractData();
当代码片段三中的ResultSetExtractor对象的extractData()执行到this.rch.processRow(rs);时,回调方法,代码执行回到了在代码片段一中自定义实现RowCallbackHandler接口的processRow()方法中.
7.jdbctemplate的sql查询与结果集转换完成.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值