好久没更新博客了,每天忙着接收新知识,博客好久没更新了。今天从新更细起来。
最近看spring源码,发现里面很多回调函数,可小白的我不知道回调是什么,经过多方查询,现在终于明白了,再看hibernatetemplete,感觉明朗了许多。下面附上个人理解。
由于本人还在努力着想着大神迈进,所以对于目前菜鸟的我,水平有限,大神勿笑。
对于一件事情的认识,我喜欢和另一件事情对比加以理解。那么,什么是回调呢?首先看看:回调,同步和异步的区别
例如:同步:Class A ------------------>class B 类A 中的一个方法,调用类B中的一个方法,而且必须等待类B中的方法返回结果后类A中的方法才能向下走,这便是同步,同步在我们的代码中用的最多,我们经常用到,但我们也许没有在意。
异步: 一种类似消息或事件的机制。 不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。
举个例子:用户需要把相片上传至某个服务器A上,然后服务器A把他们的照片取出并传送到另一台服务器B上进行审批,若没有通过则通知对方。其中用户上传和审批没有阻塞关系,但当审批不通过时,则需要调用A的方法通知对方。
一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;
下边结合一个例子说明下:
<span style="background-color: rgb(153, 153, 153);"><span style="color:#ffffff;"></span></span>
//这是我们最传统的方式,加载驱动,建立连接,设置参数,执行查询,重复性操作太多,那么,我们能不能简化?
public void update(User user){
String sql="update user set pwd = ? where name = ?";
Connection connection=ConnectionUtil.getConnection();
try {
PreparedStatement statement=connection.prepareStatement(sql);
statement.setString(1, "小明");
statement.setString(2, "123456");
statement.executeQuery();
} catch (SQLException e) {
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally{
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
ConnectionUtil.close(connection);
}
}
简化一下:
public final Object execute(String sql){
Connection connection=ConnectionUtil.getConnection();
try {
PreparedStatement statement=connection.prepareStatement(sql);
Object result= doinstatement(statement);//由子类去实现
return result;
} catch (SQLException e) {
e.printStackTrace();
}finally{
ConnectionUtil.close(connection);
}
return null;
}
public abstract Object doinstatement(PreparedStatement statement)throws SQLException;
}
子类代码:
public class JdbcTemeteInpl extends JdbcTemete {
@Override
public Object doinstatement(PreparedStatement statement) throws SQLException {
//
statement.setString(1, "小明");
statement.executeQuery();
return null;
}
}
怎么调用呢?
JdbcTemete jdbcTemete=new JdbcTemeteInpl();
jdbcTemete.execute("select * from user where name = ?");
}
这样,我们把查询的方法抽取成了一个模板, 但是这还不简便,每次查询要继承一次模板,能不能再简便点呢?
我们把 doinstatement()抽取到一个方法里面,变这样:
public abstract class JdbcCollBack { //我们把它叫做类B
public abstract Object doinstatement(PreparedStatement statement)throws SQLException;
}
然后模板这样一个方法:
public Object doexecute(JdbcCollBack collBack) throws SQLException{ //这个是模板的方法,叫类A中的方法 在这个方法中需要调用B的方法
Object result=collBack.doinstatement(getStatement());//但是在这里,需要传个参数,这个参数调用了类A中的方法
return result;
}
这样不好看,我们再封装,我们习惯用query
public Object query(JdbcCollBack collBack) throws SQLException{
return doexecute(collBack);
}
此时的查询,这样:
public Object get(String sql,final String name) throws SQLException{
JDBCTemete.sql = sql;
connection=ConnectionUtil.getConnection();
return query(new JdbcCollBack() {
@Override
public Object doinstatement(PreparedStatement statement)
throws SQLException {
statement.setString(1, name);
ResultSet resultSet= statement.executeQuery();
while(resultSet.next()){
String nameString=resultSet.getString("name");
String passwString=resultSet.getString("pwd");
User user=new User(nameString, passwString);
return user;
}
return null;
}
});
}
这样,我们就可以自己写find load update 等,只要return
query(new JdbcCollBack());这是个匿名内部类回调
这怎么回事呢?
类A中的方法: doexecute(JdbcCollBack collBack) 需要类B,然后调用B 的方法--- collBack.doinstatement(getStatement()),即A调B
类B 中的 doinstatement(PreparedStatement statement)方法需要一个参数PreparedStatement ,这个参数由类A中的方法提供。B调用A
这样对PreparedStatement 的管理由交给了类A,这样就是回调。这是面向对象的回调,对于面向过程的回调,本人菜鸟一个不知道。
最后,我们来理解HibernateTemplate的原理:
HibernateTemplate:有一个很重要的方法:protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
下面看看怎么回事:
HibernateTemplate,我们用的较多的execute():
public Object execute(HibernateCallback action)
throws DataAccessException
{
return doExecute(action, false, false);//这里调用了<span style="font-family: Arial;">doExecute方法</span>
}
然后看看
doExecute方法源码:
这是个模板方法:
protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
throws DataAccessException
{
org.hibernate.Session session;
boolean existingTransaction;
FlushMode previousFlushMode;
Assert.notNull(action, "Callback object must not be null");
session = enforceNewSession ? SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession();
existingTransaction = !enforceNewSession && (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory()));
if(existingTransaction)
logger.debug("Found thread-bound Session for HibernateTemplate");
previousFlushMode = null;
Object obj;
try
{
previousFlushMode = applyFlushMode(session, existingTransaction);
enableFilters(session);
//session代理
org.hibernate.Session sessionToExpose = !enforceNativeSession && !isExposeNativeSession() ? createSessionProxy(session) : session;
//
Object result = action.doInHibernate(sessionToExpose);
flushIfNecessary(session, existingTransaction);
obj = result;
}
catch(HibernateException ex)
{
throw convertHibernateAccessException(ex);
}
catch(SQLException ex)
{
throw convertJdbcAccessException(ex);
}
catch(RuntimeException ex)
{
throw ex;
}
if(existingTransaction)
{
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
disableFilters(session);
if(previousFlushMode != null)
session.setFlushMode(previousFlushMode);
} else
if(isAlwaysUseNewSession())
SessionFactoryUtils.closeSession(session);
else
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
return obj;
Exception exception;
exception;
if(existingTransaction)
{
logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
disableFilters(session);
if(previousFlushMode != null)
session.setFlushMode(previousFlushMode);
} else
if(isAlwaysUseNewSession())
SessionFactoryUtils.closeSession(session);
else
//关闭session 用hibernateTemelete不用关闭session
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
throw exception;
}
hibernate 中还有get load find 方法,他们是如何实现的呢?
以get为例:调用 executeWithNativeSession()方法,
public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)
throws DataAccessException
{
return executeWithNativeSession(new HibernateCallback() {
public Object doInHibernate(org.hibernate.Session session)
throws HibernateException
{
if(lockMode != null)
return session.get(entityClass, id, lockMode);
else
return session.get(entityClass, id);
}
然后看看这个方法:
结果还是调用 doExecute()方法
public Object executeWithNativeSession(HibernateCallback action)
{
return doExecute(action, false, true);
}
可以看出,HibernateTemplate 中的核心方法是
doExecute 其他方法都调用这个方法,不过提供了不同的封装,而且session的管理由HibernateTemplate 来完成,对于session的开启,事物的提交,都有一个默认的设置。
由于我没有看清 executeWithNativeSession()让我纠结模板里面的get,find load 方法中的 doInHibernate(Session session)里面的session是谁传来的,现在终于清楚了。
好了到这里就结束了,每天进步一点点