所谓回调,就是在执行某个程序时,具体的封装处理由第三方类来实现,简单一点说就是记录内部,再出来(由第三方类可以对数据进行处理),再返回去继续执行,这个过程就是回调。想要程序具有记录内部的功能就必须定义一个规范,也就是接口,即你的程序出来被其他类处理了,但你规定了还要返回原程序。
下面看一个简单的例子:
/** * @描述:回调函数--记录内部,再出来返回去的过程就叫回调 * @author cxie */ public class CopyOfCallBackDemo { public static void main(String[] args) { QRunner run = new QRunner(); run.query("张三",new RunnerHandler1(){ @Override public void handler(String name) { System.err.println(name+"1"); } }); } } /** * 定义调用类 */ class QRunner{ public void query(String sql,RunnerHandler1 rh){ //调用规范的实现类 System.err.println(sql+"o"); rh.handler(sql); } } /** * 定义回调规范 */ interface RunnerHandler1{ void handler(String name); }程序的执行结果如下
下面再看一个高级一点的例子,通过定义泛型,使回调具有任意的返回值
package hd.cx.dbutilTest;
import java.util.List;
import java.util.Map;
/**
* @描述:回调函数--记录内部,再出来返回去的过程就叫回调
* @author cxie
* @拓展:通过定义泛型,使回调具有任意的返回值
*
*/
public class CallBackDemo {
public static void main(String[] args) {
Runner run = new Runner();
run.query("zhangsan",new RunnerHandler<><>>>()/** 定义了该方法的规范*/{
@Override
public List<>> handler(String name){
System.err.print(name+"1");
return null;
}
});
}
}
/**
* 定义一个调用类
*/
class Runner{
public /**这里是定义泛型*/ T query(String sql,RunnerHandler/**这里是使用泛型*/ rh){
//调用一规范的实现类
System.err.println(sql+"0");
return rh.handler(sql);
}
}
/**
* 定义一个回调规范:接口
*/
interface RunnerHandler{
T handler(String name);
}
程序的运行结果同样如下
由此可以看出程序先执行调用类再回调回去执行接口定义的方法。
接下来是简单模拟Queryrunner中的两种方法来来编写自己的Queryrunner(一种是封装成Map放到List中,一种是封装到JavaBean中,暂时先不使用回调函数,大概了解一下原理)
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import java.sql.Statement;
/**
* @描述:模拟queryrunner编写一个封装数据库操作的方法
* @author cxie
*
*/
public class QueryRunner {
private DataSource ds;
public QueryRunner(){
}
public QueryRunner(DataSource ds){
this.ds=ds;
}
/**
* 只封装List
本次使用的数据库连接方法仍然是c3p0连接池,具体实现方法请看我上篇博客:通过使用反射+动态代理+注解来实现对事务的控制
接下来编写一个测试方法:
package hd.cx.demo;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import hd.cx.utils.DataSourceUtils;
import hd.cx.queryrunner.QueryRunner;
public class DaoTest {
@Test
public void test1(){
QueryRunner run = new QueryRunner(DataSourceUtils.getDatasSource());
String sql = "select * from user";
List<>> list = run.query(sql);
System.out.println(list);
}
}
封装成List
@Test
public void test2(){
QueryRunner run = new QueryRunner(DataSourceUtils.getDatasSource());
String sql = "select * from user";
List list = run.queryForBean(sql,User.class);
System.out.println(list);
}
接下来是模拟dbutils中的方法,使用回调函数编写一个自己的BeanListHandler,方法大致跟上面的一样,具体代码如下
回调函数:
/**
* 有回调的查询
*/
public T query(String sql,MyHandler mh){
T t = null;
//声明conn
Connection con = null;
try {
con = ds.getConnection();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
//让回调去执行数据库封装
t = mh.handler(rs);
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return t;
}
具体实现都差不多就不写注释了
package hd.cx.queryrunner;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
public class MyBeanListHandler implements MyHandler<>> {
private Class cls;
/**传入bean的字节码*/
public MyBeanListHandler(Class cls){
this.cls=cls;
}
@Override
public List handler(ResultSet rs) {
List list = new ArrayList();
try {
ResultSetMetaData rsmd = rs.getMetaData();
int cols = rsmd.getColumnCount();
while(rs.next()){
T t = cls.newInstance();
for(int i = 0; i
定义的规范,也就是接口:
package hd.cx.queryrunner;
/**
* @描述:定义规范,接受rs结果集
* @author cxie
*/
import java.sql.ResultSet;
public interface MyHandler {
T handler(ResultSet rs);
}
@Test
public void test3(){
QueryRunner run = new QueryRunner(DataSourceUtils.getDatasSource());
String sql = "select * from user";
List list = run.query(sql, new MyBeanListHandler(User.class));
System.out.println(list);
}
再来看一下dbutils中beanlisthandler的执行方法
@Test
public void test4(){
org.apache.commons.dbutils.QueryRunner run = new org.apache.commons.dbutils.QueryRunner(DataSourceUtils.getDatasSource());
String sql = "select * from user";
List list = null;
try {
list = run.query(sql, new BeanListHandler(User.class));
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println(list);
}
如果仔细一点的话就能发现,当调用dbutils中的方法时需要捕获异常,而调用MyBeanListHandler时确实不用,原因在于编写MyBeanListHandler时已经对异常进行了捕获,所以我们可以重写dbutils中的Queryrunner呢,捕获每个方法的异常,这样每次调用的时候就不必要try-catch了。其实说白了很简单,就是继承dbutils的Queryrunner,对父类的方法进行try-catch覆盖,
下面是dbutils的源码和jar包的下载地址
http://pan.baidu.com/s/1kT2y9FL
下面是覆盖了Queryrunner方法的完整代码如下
package hd.cx.utils;
import java.beans.PropertyDescriptor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
/**
* @描述:重写Queryrunner,避免try-catch的麻烦
* @author cxie
*
*/
public class MyQueryRunner extends QueryRunner{
public MyQueryRunner(){}
public MyQueryRunner(DataSource ds){
super(ds);
}
@Override
public int[] batch(Connection conn, String sql, Object[][] params) {
try {
return super.batch(conn, sql, params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public int[] batch(String sql, Object[][] params){
try {
return super.batch(sql, params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public void fillStatement(PreparedStatement stmt, Object... params){
try {
super.fillStatement(stmt, params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public void fillStatementWithBean(PreparedStatement stmt, Object bean,
PropertyDescriptor[] properties){
try {
super.fillStatementWithBean(stmt, bean, properties);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public void fillStatementWithBean(PreparedStatement stmt, Object bean,
String... propertyNames){
try {
super.fillStatementWithBean(stmt, bean, propertyNames);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
protected PreparedStatement prepareStatement(Connection conn, String sql){
try {
return super.prepareStatement(conn, sql);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
protected Connection prepareConnection(){
try {
return super.prepareConnection();
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public T query(Connection conn, String sql, Object param,
ResultSetHandler rsh){
try {
return super.query(conn, sql, rsh);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public T query(Connection conn, String sql, Object[] params,
ResultSetHandler rsh){
try {
return super.query(conn, sql, params, rsh);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public T query(Connection conn, String sql, ResultSetHandler rsh,
Object... params){
try {
return super.query(conn, sql, rsh, params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public T query(Connection conn, String sql, ResultSetHandler rsh){
try {
return super.query(conn, sql, rsh);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public T query(String sql, Object param, ResultSetHandler rsh){
try {
return super.query(sql, param, rsh);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public T query(String sql, Object[] params, ResultSetHandler rsh){
try {
return super.query(sql, params, rsh);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public T query(String sql, ResultSetHandler rsh, Object... params){
try {
return super.query(sql, rsh, params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public T query(String sql, ResultSetHandler rsh){
try {
return super.query(sql, rsh);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
protected void rethrow(SQLException cause, String sql, Object... params){
try {
super.rethrow(cause, sql, params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public int update(Connection conn, String sql){
try {
return super.update(conn, sql);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public int update(Connection conn, String sql, Object param){
try {
return super.update(conn, sql, param);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public int update(Connection conn, String sql, Object... params){
try {
return super.update(conn, sql, params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public int update(String sql){
try {
return super.update(sql);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public int update(String sql, Object param){
try {
return super.update(sql, param);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
public int update(String sql, Object... params){
try {
return super.update(sql, params);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
protected void close(Connection conn){
try {
super.close(conn);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
protected void close(Statement stmt){
try {
super.close(stmt);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
@Override
protected void close(ResultSet rs){
try {
super.close(rs);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(),e);
}
}
}
如此这般,就可以省去try-catch的麻烦了,由于篇幅的问题,这里就不写测试类了。