`

Java 回调机制及其Spring 中HibernateTemplate的源码分析

阅读更多

   在分析HibernateTemplate前,首先从网上了解下一些关于回调的一些概念。我相信在了解其原理实现的基础上,可以更好的进行开发和扩展,关键得理解其思想。
   软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。
   同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用。(简单来说就是顺序执行啦。)
回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口。(个人觉得有点像模板方法的实现。)
   异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。(差不多就是异步执行吧。)
   回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础。
   由于本文章主要关注的是Java 的回调机制,所以其他就不介绍了。下面来看看Java 是怎么来实现回调机制的。

package callback;
/**
 * 
 * @author zhxing
 * @since 2010.4.16
 *
 */
public class Test{
	private Callback callback;
	public void setCallback(Callback callback){
		this.callback=callback;
	}
	//实际方法
	public void foo(){
		System.out.println("this is foo();");
		//在这里调用回调函数
		if(callback!=null){
			callback.doSomething();
		}
	}
	//测试
	public static void main(String[] args) {
		Test t=new Test();
		t.setCallback(new Callback(){
			public void doSomething() {
				System.out.println("this is callback.");
			}
		});
		
		t.foo();
	}
	
}
//回调函数
interface Callback {
	void doSomething();
}

 

 

   一般在我们数据库开发中,都会有打开和关闭数据、捕获异常等的一些固定的操作,写久了也就特别的反感了。是吧。。下面来利用回调简化数据库操作,例子很简单,对于数据的打开和关闭我只做了简单的描述。

package callback;

public class UserDao {
	private UserTemplate template=new UserTemplate();
	
	//这个实际上也是用回调方法,不过在UserTemplate 进行了封装
	public void add(final String name){
		this.template.add(name);
	}
	//这个是用回调方法来实现的
	public String getName(){
		return (String)this.template.execute(new UserCallback(){
			public Object doSomething() {
				System.out.println("成功读取数据库。。。name= zhxing");
				return "zhxing";
			}	
		});
	}
	
	//测试
	public static void main(String[] args) {
		UserDao u=new UserDao();
		u.add("zhxing");
		System.out.println(u.getName());
	}
}

package callback;
//回调函数的实现
public class UserTemplate {
	//调用回调函数,这里是不是有点像模板方法了,呵呵
	public  Object execute(UserCallback callback){
		System.out.println("打开数据库连接");
		Object o=callback.doSomething();
		System.out.println("关闭数据库连接");
		return o;
	}
	
	//这里用来简化常用的操作
	public void add(final String name){
		execute(new UserCallback(){
			public Object doSomething() {
				System.out.println("name="+name+" 成功加入数据库。。。");
				return null;
			}	
		});
	}

}

package callback;
//回调函数接口
public interface UserCallback {
	Object doSomething();
}

 

 

    好了,进入正题吧。。来研究下Spring 中HibernateTemplate 是怎么实现了。。其实上面的那个例子已经可以说明全部了,呵呵。。下面我们按照开发的流程来进行一些源码分析。
    当我们用Spring+Hibernate实现Dao层的时候,一般会去继承HibernateDaoSupport这个类。
来分析下这个HibernateDaoSupport类(具体方法细节请查看源码):

public abstract class HibernateDaoSupport extends DaoSupport {

	private HibernateTemplate hibernateTemplate;
	 //Set the Hibernate SessionFactory to be used by this DAO.
	public final void setSessionFactory(SessionFactory sessionFactory) {
	}
	protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
		}
	//返回这个HiberanteTemplate 中的成员变量SessionFactory
	public final SessionFactory getSessionFactory() {
		
	}

	public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
	public final HibernateTemplate getHibernateTemplate() {
	  return this.hibernateTemplate;
	}
//检查HibernateTemplate是否为空,如果类中的HibernateTemplate未设置则会报错
	protected final void checkDaoConfig() {
		if (this.hibernateTemplate == null) {
			throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
		}
	}


	//获得Hibernate中的session,可以在HibernateTemplate中配置是否在Session没创建时新创建一个,在事务处理中很有用
	protected final Session getSession()
	    throws DataAccessResourceFailureException, IllegalStateException {

		return getSession(this.hibernateTemplate.isAllowCreate());
	}

	//这里是获得Hibernate 的session 的主要方法
	protected final Session getSession(boolean allowCreate)
	    throws DataAccessResourceFailureException, IllegalStateException {

		return (!allowCreate ?
		    SessionFactoryUtils.getSession(getSessionFactory(), false) :
				SessionFactoryUtils.getSession(
						getSessionFactory(),
						this.hibernateTemplate.getEntityInterceptor(),
						this.hibernateTemplate.getJdbcExceptionTranslator()));
	}

	//把HibernateException异常转换成DataAccessException异常
	protected final DataAccessException convertHibernateAccessException(HibernateException ex) {
		return this.hibernateTemplate.convertHibernateAccessException(ex);
	}

	//释放Hibernate 的session
	protected final void releaseSession(Session session) {
		SessionFactoryUtils.releaseSession(session, getSessionFactory());
	}

}

 

 

   从上面可知道,HibernateDaoSupport 的主要作用是获取Hibernate 的Session (如果直接用HibernateTemplate是没有办法获得Session 的)和管理HibernateTemplate。在Spring 中可以对直接继承该类,然后在Dao 的配置上就可以直接进行注入SessionFactory了,还可以直接从Dao中获取Hibernate的Session进行操作。
   现在回到正题,进行分析下HibernateTemplate,先看下他的成员变量有哪些。

public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {
	//是否在Session不存在的时候进行创建
	private boolean allowCreate = true;
//是否每次都生成新的Session
	private boolean alwaysUseNewSession = false;
//是不是用原生的Hibernate 的session而不是用它的代理
	private boolean exposeNativeSession = false;
//检查Hibernate 的session 是否为只读模式
	private boolean checkWriteOperations = true;
//缓存Query
	private boolean cacheQueries = false;
//设置Query缓存的名称
	private String queryCacheRegion;
//设置批量获取的大小
	private int fetchSize = 0;
//设置最大的数据集
private int maxResults = 0;
}

 

   HibernateTemplate 封装了很多Hibernate 的原始的操作,但把Hibernate 的session设置为了protected,而不能在它的子类外进行获取。下面来看看我们最常用get 和save 方法。

public Object get(Class entityClass, Serializable id) throws DataAccessException {
		return get(entityClass, id, null);
	}
//实际get调用这个方法,增加了一个锁模式。
	public Object get(final Class entityClass, final Serializable id, final LockMode lockMode)
			throws DataAccessException {
//这里就是我们上面讨论的回调方法了。。
		return executeWithNativeSession(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException {
				if (lockMode != null) {
					return session.get(entityClass, id, lockMode);
				}
				else {
					return session.get(entityClass, id);
				}
			}
		});
	}

	public Serializable save(final Object entity) throws DataAccessException {
	//这里也是用了回调,和上面一样的。
		return (Serializable) executeWithNativeSession(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException {
				checkWriteOperationAllowed(session);
				return session.save(entity);
			}
		});
	}

 

 

  下面来看看这个回调函数的方法。

protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
			throws DataAccessException {

		Assert.notNull(action, "Callback object must not be null");
//判断是否强制新建Session
		Session session = (enforceNewSession ?
				SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
//判断是否设置了事务且是否强制新建session
		boolean existingTransaction = (!enforceNewSession &&
				(!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
		if (existingTransaction) {
			logger.debug("Found thread-bound Session for HibernateTemplate");
		}

		FlushMode previousFlushMode = null;
		try {
//设置并返回FlushMode
			previousFlushMode = applyFlushMode(session, existingTransaction);
//设置过滤器
			enableFilters(session);
//是否创建session 代理
			Session sessionToExpose =
					(enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
//这里调用回调函数了
			Object result = action.doInHibernate(sessionToExpose);
			flushIfNecessary(session, existingTransaction);
			return result;
		}
		catch (HibernateException ex) {
			throw convertHibernateAccessException(ex);
		}
		catch (SQLException ex) {
			throw convertJdbcAccessException(ex);
		}
		catch (RuntimeException ex) {
			// Callback code threw application exception...
			throw ex;
		}
		finally {
			if (existingTransaction) {
				logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
				disableFilters(session);
				if (previousFlushMode != null) {
					session.setFlushMode(previousFlushMode);
				}
			}
			else {
				// Never use deferred close for an explicitly new Session.
				if (isAlwaysUseNewSession()) {
					SessionFactoryUtils.closeSession(session);
				}
				else {
			//把session绑定到线程变量中(ThreadLocal)		SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
				}
			}
		}
	}

 

     到这里基本就简单分析完了,关于HibernateTemplate的其他操作,其实都差不多的,对Hibernate的一些常用操作进行了回调封装,可以自己分析下。

 

6
1
分享到:
评论
2 楼 lh870003574 2012-06-07  

回调就是A调用B时,B也会调用A,这里需要借助接口Callback,而匿名内部类是实现Callback接口最快速方便的方法。
另外在B调用A之前或者之后,可以做一些固定的操作,如数据库的连接和关闭,这也是模板方法的思想~
我说的对吗  楼主

PS:貌似Spring很喜欢使用回调来对其它框架进行封装
1 楼 lh870003574 2012-06-07  

相关推荐

    spring源码分析(1-10)

    Spring 源代码分析系列涵盖了多个关键模块,包括事务处理、IoC容器、JDBC、MVC、AOP以及与...通过这些深入的源代码分析,我们可以理解Spring框架的内部工作机制,更好地利用它来设计和构建健壮、可维护的Java应用。

    spring-orm源码

    源码分析可以让我们学习到如何在测试环境中配置和使用Spring-ORM。 通过深入研究Spring-ORM的源码,开发者不仅可以提高对Spring框架的理解,还能学习到数据库访问的最佳实践,以及如何高效地集成和使用不同的ORM...

    spring源码分析(一)

    ### Spring源码分析知识点 #### 一、Spring框架概述 Spring框架是一个全面的企业级应用开发框架,它通过一系列模块化的组件来支持不同的应用场景和技术需求。Spring的核心价值在于提供了一种简洁的方式来解决企业...

    spring1.2.6源码

    Spring框架是Java开发中不可或缺的一部分,它以其IoC(Inversion of Control)和AOP(Aspect-Oriented Programming)的核心特性赢得了广泛的认可。版本1.2.6是Spring早期的一个稳定版本,对于初学者和想要深入理解...

    spring源码分析

    在Spring中,事务管理是通过声明式和编程式两种方式实现的。声明式事务管理基于XML配置或注解,使得开发者无需编写繁琐的事务控制代码,大大提高了开发效率。在源码中,我们可以看到`PlatformTransactionManager`...

    Spring_2000_Spring_Hibernate_HibernateTemplate

    标题中的"Spring_2000_Spring_Hibernate_HibernateTemplate"显然指的是一个关于Spring框架、Hibernate ORM框架以及其在2000年左右的版本或应用方式的专题。在这个主题下,我们将深入探讨Spring框架的核心特性,以及...

    Spring_Spring_Hibernate_HibernateTemplate

    在Java企业级开发中,Spring框架和Hibernate持久层框架的结合使用是常见的技术选型。本篇将深入探讨Spring与Hibernate的集成,特别是Spring提供的HibernateTemplate,它是Spring对Hibernate的一种封装,简化了数据库...

    Spring+hibernate整合源代码

    Spring 和 Hibernate 是两个非常重要的 Java 开发框架,它们在企业级应用开发中有着广泛的应用。Spring 是一个全面的后端应用程序框架,提供了依赖注入、面向切面编程、数据访问、事务管理等多种功能。Hibernate 则...

    深入分析Spring源码.docx

    本篇将详细探讨Spring中运用的设计模式及其重要性。 首先,Spring框架中广泛应用了23种经典设计模式,如工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式等。这些模式在Spring中起到了关键作用,使得...

    java+Spring+Hibernate整合的企业OA源码

    【标题】"java+Spring+Hibernate整合的企业OA源码"所代表的是一个使用Java编程语言,结合Spring框架和Hibernate持久层框架实现的企业级办公自动化(Office Automation,简称OA)系统的源代码。这样的系统通常用于...

    跟我学spring3-源码.

    《跟我学Spring3-源码》教程是一份深入解析Spring框架3.x版本核心源码的教育资源,适合对Java和J2EE技术有一定基础的开发者学习。本教程旨在帮助读者理解Spring框架的工作原理,提高在实际项目中的应用能力。通过...

    一个模拟Spring将SessionFactory注入到HibernateTemplate的小例子

    4. **源码分析**:通过阅读Spring和Hibernate的相关源码,我们可以更深入地理解这两个库是如何协同工作的。SessionFactory的创建过程、HibernateTemplate的内部实现,以及DI的原理等,都是值得研究的部分。 在...

    spring源码分析免费资源

    Spring框架是Java开发中最常用的轻量级开源框架之一,它以其IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)为核心特性,极大地简化了企业级应用的开发。在对Spring进行...

    Spring,Hibernate整合源码

    源码分析通常涉及对配置文件的理解,如Spring的beans.xml和Hibernate的hibernate.cfg.xml,以及相关类的设计和交互。此外,还可以通过源码学习到如何处理异常、优化数据库操作,以及如何设计符合松耦合原则的架构。

    spring hibernatetemplate

    但是,如果在`HibernateTemplate`的`execute`方法中手动调用了`session.flush()`,那么这个事务就会被立即提交,而不是等待整个回调方法执行完毕。因此,如果需要确保多个操作都在同一个事务中,开发者需要自己控制...

    精通spring(及源码)

    《精通Spring(及源码)》是一本深度探讨Spring框架及其源码的书籍,旨在帮助读者全面理解Spring的核心机制,并能深入源码层面进行学习和分析。Spring作为Java企业级应用开发的重要框架,其强大的功能和灵活性使得它在...

    spring2.0宝典源码

    总之,《Spring2.0宝典》中的源码分析涵盖了Spring框架的核心特性,包括IoC、AOP、事务管理、数据访问和MVC,以及测试支持。通过学习这些源码,开发者可以深入了解Spring的工作原理,提升框架的使用技巧,从而在实际...

    spring java

    《Spring Java深度解析:源码、小项目与Hibernate整合》 Spring框架作为Java开发中的核心组件,以其强大的IoC(Inversion of Control)和AOP(Aspect Oriented Programming)特性,极大地简化了企业级应用的开发。...

    spring入门笔记源码

    通过分析这些源码,我们可以更好地理解 Spring 框架的工作原理,并将所学应用到实际项目中。 学习过程中,推荐结合官方文档、教程以及在线资源,以便深入理解每个概念。同时,动手实践是学习编程的最好方式,尝试...

    HibernateTemplate详细描述以及使用范围

    通过本文的介绍,我们可以了解到`HibernateTemplate`在Spring框架中的重要地位及其应用场景。它不仅简化了Hibernate的使用,还提供了一套完善的API用于处理常见的数据库操作。此外,通过与Spring框架的良好集成,`...

Global site tag (gtag.js) - Google Analytics