Spring中 Callback模式和Template模式合用 随处可见。下面以常用的HibernateTemplate为例进行简要简述。
在HibernateTemplate模板类中有一个核心的方法:doExecute,这个核心的方法采用模板方法 完成相关的固定 操作(建立连接,执行操作,释放连接) ,其中的具体步骤通过回调传入的对象(这个对象就是实现了Callback接口的类)来完成。
一。HibernateTemplate类的使用:
1。HibernateTemplate 类提供了大量方法对应Hibernate Session 接口中暴露的方法。使用这些方法时可以直接调用。save()方法使用例子:
Java代码
1.import org.springframework.orm.hibernate3.HibernateTemplate;
2.@Component("userDaoImpl")
3.public class UserDaoImpl implements UserDao {
4. private HibernateTemplate hibernateTemplate;
5. public HibernateTemplate getHibernateTemplate()
6. {
7. return hibernateTemplate;
8. }
9.
10. @Resource(name="hibernatTemplate")
11. public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
12. this.hibernateTemplate = hibernateTemplate;
13. }
14. @Override
15. public void save(User u) {
16. hibernateTemplate.save(u);
17. //这里可以直接save了,session已经被hibernateTemplate处理了。我们不需要关心它了。
18. //因为HibernateTemplate中已经注入了SessionFactory了,因为它自己会处理好session及其事务的。
19. System.out.println("user save...");
20. }}
import org.springframework.orm.hibernate3.HibernateTemplate;
@Component("userDaoImpl")
public class UserDaoImpl implements UserDao {
private HibernateTemplate hibernateTemplate;
public HibernateTemplate getHibernateTemplate()
{
return hibernateTemplate;
}
@Resource(name="hibernatTemplate")
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
@Override
public void save(User u) {
hibernateTemplate.save(u);
//这里可以直接save了,session已经被hibernateTemplate处理了。我们不需要关心它了。
//因为HibernateTemplate中已经注入了SessionFactory了,因为它自己会处理好session及其事务的。
System.out.println("user save...");
}} 因为HibernateTemplate需要交给Spring来管理,因为也需要配置bean,及注入sessionFactory:
Xml代码
1.<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
2. <property name="sessionFactory" ref="sessionFactory"/>
3.</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
2。当你需要使用的Session 方法没有在HibernateTemplate 中提供时,可以通过下面提供的基于回调的方案来实现,如下实例所示:
Java代码
1.public class ProductDaoImpl implements ProductDao {
2.
3. private HibernateTemplate hibernateTemplate;
4.
5. public void setSessionFactory(SessionFactory sessionFactory) {
6. this.hibernateTemplate = new HibernateTemplate(sessionFactory);
7. }
8.
9. public Collection loadProductsByCategory(final String category) throws DataAccessException {
10. return this.hibernateTemplate.execute(new HibernateCallback() {
11.
12. public Object doInHibernate(Session session) {
13. Criteria criteria = session.createCriteria(Product.class);
14. criteria.add(Expression.eq("category", category));
15. criteria.setMaxResults(6);
16. return criteria.list();
17. }
18. };
19. }
20.}
public class ProductDaoImpl implements ProductDao {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
Criteria criteria = session.createCriteria(Product.class);
criteria.add(Expression.eq("category", category));
criteria.setMaxResults(6);
return criteria.list();
}
};
}
}
3。HibernateDaoSupport 基类:
一个回调实现能够有效地在任何Hibernate数据访问中使用。HibernateTemplate 会确保当前Hibernate的 Session 实例的正确打开和关闭,并直接参与到事务管理中去。 Template实例不仅是线程安全的,同时它也是可重用的。因而他们可以作为外部对象的实例变量而被持有。对于那些简单的诸如find、load、saveOrUpdate或者delete操作的调用,HibernateTemplate 提供可选择的快捷函数来替换这种回调的实现。 不仅如此,Spring还提供了一个简便的 HibernateDaoSupport 基类,这个类提供了 setSessionFactory(..) 方法来接受一个 SessionFactory 对象,同时提供了 getSessionFactory() 和 getHibernateTemplate() 方法给子类使用。实例如下:
Java代码
1.public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
2.
3. public Collection loadProductsByCategory(String category) throws DataAccessException {
4. return this.getHibernateTemplate().find(
5. "from test.Product product where product.category=?", category);
6. }
7.}
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException {
return this.getHibernateTemplate().find(
"from test.Product product where product.category=?", category);
}
} 4。HibernateDaoSupport 基类使用技巧:
HibernateDaoSupport这也是使用HibernateTemplate的方法之一,只是需要dao继承这个类:
Java代码
1.public class LogDaoImpl extends HibernateDaoSupport implements LogDao {
2. @Override
3. public void save(Log log) {
4. this.getHibernateTemplate().save(log);
5. //this.save(log);
6. System.out.println("log save...");
7. }
8.}
public class LogDaoImpl extends HibernateDaoSupport implements LogDao {
@Override
public void save(Log log) {
this.getHibernateTemplate().save(log);
//this.save(log);
System.out.println("log save...");
}
} dao继承了HibernateDaoSupport类,而这个又拥有sessionFactory和hibernateTemplate的setXXX方法,只要我在初始化这个dao时,注入两个其中一个就可以了。但是这两个setXX方法都为final的,因为不可以重写,这样就不能使用annotation的方式了,只能使用xml的方法了。HibernateDaoSupport部分源代码如下:
Java代码
1.public abstract class HibernateDaoSupport extends DaoSupport{
2. private HibernateTemplate hibernateTemplate;
3.
4. public final void setSessionFactory(SessionFactory sessionFactory) {
5. //......
6. }
7. }
8.
9.public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
10. this.hibernateTemplate = hibernateTemplate;
11. }
12.
13.public final HibernateTemplate getHibernateTemplate() {
14. return this.hibernateTemplate;
15. }
16.//.......其他方法
17.}
public abstract class HibernateDaoSupport extends DaoSupport{
private HibernateTemplate hibernateTemplate;
public final void setSessionFactory(SessionFactory sessionFactory) {
//......
}
}
public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public final HibernateTemplate getHibernateTemplate() {
return this.hibernateTemplate;
}
//.......其他方法
} xml注入方法如下:
Java代码
1.<bean id="logDaoImpl" class="example.dao.impl.LogDaoImpl">
2. <property name="hibernateTemplate" ref="hibernateTemplate"></property>
3. </bean>
<bean id="logDaoImpl" class="example.dao.impl.LogDaoImpl">
<property name="hibernateTemplate" ref="hibernateTemplate"></property>
</bean>
但是问题又来了,如果dao有多个(甚至几个以上),这样就会有大量的xml配置文件,每个dao需要一个配置一个bean,并且在这个bean中需要注入一个sessionFactory或是hibernateTemplate,这样的工作量是非常的大,并且容易出错。
针对有大量的dao我们提供一个解决方案:
我们可以创建一个类,并且这个类来继承hibernateDaoSupport这个类,由于hibernateDaoSupport类的sessionFactory和hibernateTemplate的setXXX方法是final的,因此不能重写,但我们可以在这个类中注入一个sessionFactory或hibernateTemplate但是setXXX方法名,用其它的。然后让dao来继承这个类,这就dao就可以使用annotation方式注解了。代码如下:
Java代码
1.@Component
2.public class SuperDao extends HibernateDaoSupport {
3. @Resource(name="hibernateTemplate")
4. public void setSuperHibernateTemplate(HibernateTemplate hibernateTemplate ){
5. //在这里为父类HibernateDaoSuppport注入hibernateTemplate或是sessionFactory
6. super.setHibernateTemplate(hibernateTemplate);
7. }
8.}
@Component
public class SuperDao extends HibernateDaoSupport {
@Resource(name="hibernateTemplate")
public void setSuperHibernateTemplate(HibernateTemplate hibernateTemplate ){
//在这里为父类HibernateDaoSuppport注入hibernateTemplate或是sessionFactory
super.setHibernateTemplate(hibernateTemplate);
}
}
其它的dao继承这个就可以了,如下所示:
Java代码
1.@Component
2.public class LogDaoImpl extends SuperDao implements LogDao {
3. @Override
4. public void save(Log log) {
5. this.getHibernateTemplate().save(log);
6. //this.save(log);
7. System.out.println("log save...");
8. }
9.}
@Component
public class LogDaoImpl extends SuperDao implements LogDao {
@Override
public void save(Log log) {
this.getHibernateTemplate().save(log);
//this.save(log);
System.out.println("log save...");
}
}
其他的用法不在这里累述,请参看Spring的参考文档.下面重点说说Spring HibernateTemplate模板方法与Callback机制.
二。HibernateTemplate源码分析
下面以save()方法为例进行说明,先看源代码:
HibernateCallback接口的代码如下, 它只有一个方法doInHibernate方法:
Java代码
1.public interface HibernateCallback {
2. Object doInHibernate(Session session) throws HibernateException, SQLException;
3.}
public interface HibernateCallback {
Object doInHibernate(Session session) throws HibernateException, SQLException;
} HibernateTemplate中的具体操作的方法,如save(),update()的具体实现都采用匿名类的方式实现了该接口,在doInHibernate中完成具体的操作。以save()方法为例:
Java代码
1.public Serializable save(final Object entity) throws DataAccessException {
2. return (Serializable) executeWithNativeSession(new HibernateCallback() {
3. public Object doInHibernate(Session session) throws HibernateException {
4. checkWriteOperationAllowed(session);
5. return session.save(entity);
6. }
7. });
8. }
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);
}
});
} 这段代码重点注意以匿名类的方式实现了 HibernateCallback接口.
然后是executeWithNativeSession()方法如下,在此方法中调用核心方法doExecute,如下所示:
Java代码
1.public Object executeWithNativeSession(HibernateCallback action) {
2. return doExecute(action, false, true);
3. }
public Object executeWithNativeSession(HibernateCallback action) {
return doExecute(action, false, true);
} 在这个方法中使用本地已存在的Session去执行此次save操作,doExecute代码如下所示:
Java代码
1./**
2. * Execute the action specified by the given action object within a Session.
3. * @param action callback object that specifies the Hibernate action
4. * @param enforceNewSession whether to enforce a new Session for this template
5. * even if there is a pre-bound transactional Session
6. * @param enforceNativeSession whether to enforce exposure of the native
7. * Hibernate Session to callback code
8. * @return a result object returned by the action, or <code>null</code>
9. * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
10. */
11. protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
12. throws DataAccessException {
13.
14. Assert.notNull(action, "Callback object must not be null");
15.
16. Session session = (enforceNewSession ?
17. SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
18. boolean existingTransaction = (!enforceNewSession &&
19. (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
20. if (existingTransaction) {
21. logger.debug("Found thread-bound Session for HibernateTemplate");
22. }
23.
24. FlushMode previousFlushMode = null;
25. try {
26. previousFlushMode = applyFlushMode(session, existingTransaction);
27. enableFilters(session);
28. Session sessionToExpose =
29. (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
30. Object result = action.doInHibernate(sessionToExpose);
31. flushIfNecessary(session, existingTransaction);
32. return result;
33. }
34. catch (HibernateException ex) {
35. throw convertHibernateAccessException(ex);
36. }
37. catch (SQLException ex) {
38. throw convertJdbcAccessException(ex);
39. }
40. catch (RuntimeException ex) {
41. // Callback code threw application exception...
42. throw ex;
43. }
44. finally {
45. if (existingTransaction) {
46. logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
47. disableFilters(session);
48. if (previousFlushMode != null) {
49. session.setFlushMode(previousFlushMode);
50. }
51. }
52. else {
53. // Never use deferred close for an explicitly new Session.
54. if (isAlwaysUseNewSession()) {
55. SessionFactoryUtils.closeSession(session);
56. }
57. else {
58. SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
59. }
60. }
61. }
62. }
/**
* Execute the action specified by the given action object within a Session.
* @param action callback object that specifies the Hibernate action
* @param enforceNewSession whether to enforce a new Session for this template
* even if there is a pre-bound transactional Session
* @param enforceNativeSession whether to enforce exposure of the native
* Hibernate Session to callback code
* @return a result object returned by the action, or <code>null</code>
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
*/
protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Session session = (enforceNewSession ?
SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
boolean existingTransaction = (!enforceNewSession &&
(!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
if (existingTransaction) {
logger.debug("Found thread-bound Session for HibernateTemplate");
}
FlushMode previousFlushMode = null;
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
enableFilters(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 {
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
}
}
}
} doExecute这个方法有点过于复杂,不容易理解,现在我用差不多是伪代码的形式来把doExecute这个方法的大概意思写出为,以便大家理解:
Java代码
1.public class MyHibernateTemplate {
2.
3. public Object executeWithNativeSession(HibernateCallback action) {
4. return doExecute(action, false, true);
5. }
6.
7. protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession){
8. Session session = null;
9. try {
10. session = getSession();
11. session.beginTransaction();
12. action.doInHibernate(session);
13. session.getTransaction().commit();
14. } catch (Exception e) {
15. session.getTransaction().rollback();
16. }finally{
17. //....进行额外处理
18. }
19. return null;
20. }
21.
22. private Session getSession() {
23. // TODO Auto-generated method stub
24. return new Session();
25. }
26.}
public class MyHibernateTemplate {
public Object executeWithNativeSession(HibernateCallback action) {
return doExecute(action, false, true);
}
protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession){
Session session = null;
try {
session = getSession();
session.beginTransaction();
action.doInHibernate(session);
session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback();
}finally{
//....进行额外处理
}
return null;
}
private Session getSession() {
// TODO Auto-generated method stub
return new Session();
}
}
如果你觉得使用匿名内部类传参的方式不好理解,你可以先写一个特定针对save操作的实现类来帮助理解它,如下所示:
Java代码
1.public class HibernateSaveCallbackImpl implements HibernateCallback {
2.
3. private Object object ;
4. public HibernateSaveCallbackImpl(){}
5. public HibernateSaveCallbackImpl(Object object){
6. this.object = object;
7. }
8. public Object doInHibernate(Session session) throws HibernateException,
9. SQLException {
10. session.save(object);
11. return null;
12. }
13.}
public class HibernateSaveCallbackImpl implements HibernateCallback {
private Object object ;
public HibernateSaveCallbackImpl(){}
public HibernateSaveCallbackImpl(Object object){
this.object = object;
}
public Object doInHibernate(Session session) throws HibernateException,
SQLException {
session.save(object);
return null;
}
} 然后再实例化一个HibernateSaveCallbackImpl对象传给MyHibernateTemplate进行使用,如下所示:
Java代码
1.public static void main(String[] args) {
2. HibernateCallback callback = new HibernateSaveCallbackImpl();
3. HibernateCallback callback2 = new HibernateSaveCallbackImpl("save this object");
4. new MyHibernateTemplate().executeWithNativeSession(callback);
5. }
public static void main(String[] args) {
HibernateCallback callback = new HibernateSaveCallbackImpl();
HibernateCallback callback2 = new HibernateSaveCallbackImpl("save this object");
new MyHibernateTemplate().executeWithNativeSession(callback);
} 当MyHibernateTemplate中的doExecute方法执行时,执行到
Java代码
1.action.doInHibernate(session);
action.doInHibernate(session);时,它会先去执行你传入的引用(也就是你自己)的方法。所以称为回调,这与模板模式中的钩子函数基本是一样的。其实回调,简单的可以说是:将自己的引用传给别的方法,在别的方法里面,通过自己的引用调用自己的方法。
在HibernateTemplate模板类中有一个核心的方法:doExecute,这个核心的方法采用模板方法 完成相关的固定 操作(建立连接,执行操作,释放连接) ,其中的具体步骤通过回调传入的对象(这个对象就是实现了Callback接口的类)来完成。
一。HibernateTemplate类的使用:
1。HibernateTemplate 类提供了大量方法对应Hibernate Session 接口中暴露的方法。使用这些方法时可以直接调用。save()方法使用例子:
Java代码
1.import org.springframework.orm.hibernate3.HibernateTemplate;
2.@Component("userDaoImpl")
3.public class UserDaoImpl implements UserDao {
4. private HibernateTemplate hibernateTemplate;
5. public HibernateTemplate getHibernateTemplate()
6. {
7. return hibernateTemplate;
8. }
9.
10. @Resource(name="hibernatTemplate")
11. public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
12. this.hibernateTemplate = hibernateTemplate;
13. }
14. @Override
15. public void save(User u) {
16. hibernateTemplate.save(u);
17. //这里可以直接save了,session已经被hibernateTemplate处理了。我们不需要关心它了。
18. //因为HibernateTemplate中已经注入了SessionFactory了,因为它自己会处理好session及其事务的。
19. System.out.println("user save...");
20. }}
import org.springframework.orm.hibernate3.HibernateTemplate;
@Component("userDaoImpl")
public class UserDaoImpl implements UserDao {
private HibernateTemplate hibernateTemplate;
public HibernateTemplate getHibernateTemplate()
{
return hibernateTemplate;
}
@Resource(name="hibernatTemplate")
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
@Override
public void save(User u) {
hibernateTemplate.save(u);
//这里可以直接save了,session已经被hibernateTemplate处理了。我们不需要关心它了。
//因为HibernateTemplate中已经注入了SessionFactory了,因为它自己会处理好session及其事务的。
System.out.println("user save...");
}} 因为HibernateTemplate需要交给Spring来管理,因为也需要配置bean,及注入sessionFactory:
Xml代码
1.<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
2. <property name="sessionFactory" ref="sessionFactory"/>
3.</bean>
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
2。当你需要使用的Session 方法没有在HibernateTemplate 中提供时,可以通过下面提供的基于回调的方案来实现,如下实例所示:
Java代码
1.public class ProductDaoImpl implements ProductDao {
2.
3. private HibernateTemplate hibernateTemplate;
4.
5. public void setSessionFactory(SessionFactory sessionFactory) {
6. this.hibernateTemplate = new HibernateTemplate(sessionFactory);
7. }
8.
9. public Collection loadProductsByCategory(final String category) throws DataAccessException {
10. return this.hibernateTemplate.execute(new HibernateCallback() {
11.
12. public Object doInHibernate(Session session) {
13. Criteria criteria = session.createCriteria(Product.class);
14. criteria.add(Expression.eq("category", category));
15. criteria.setMaxResults(6);
16. return criteria.list();
17. }
18. };
19. }
20.}
public class ProductDaoImpl implements ProductDao {
private HibernateTemplate hibernateTemplate;
public void setSessionFactory(SessionFactory sessionFactory) {
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
}
public Collection loadProductsByCategory(final String category) throws DataAccessException {
return this.hibernateTemplate.execute(new HibernateCallback() {
public Object doInHibernate(Session session) {
Criteria criteria = session.createCriteria(Product.class);
criteria.add(Expression.eq("category", category));
criteria.setMaxResults(6);
return criteria.list();
}
};
}
}
3。HibernateDaoSupport 基类:
一个回调实现能够有效地在任何Hibernate数据访问中使用。HibernateTemplate 会确保当前Hibernate的 Session 实例的正确打开和关闭,并直接参与到事务管理中去。 Template实例不仅是线程安全的,同时它也是可重用的。因而他们可以作为外部对象的实例变量而被持有。对于那些简单的诸如find、load、saveOrUpdate或者delete操作的调用,HibernateTemplate 提供可选择的快捷函数来替换这种回调的实现。 不仅如此,Spring还提供了一个简便的 HibernateDaoSupport 基类,这个类提供了 setSessionFactory(..) 方法来接受一个 SessionFactory 对象,同时提供了 getSessionFactory() 和 getHibernateTemplate() 方法给子类使用。实例如下:
Java代码
1.public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
2.
3. public Collection loadProductsByCategory(String category) throws DataAccessException {
4. return this.getHibernateTemplate().find(
5. "from test.Product product where product.category=?", category);
6. }
7.}
public class ProductDaoImpl extends HibernateDaoSupport implements ProductDao {
public Collection loadProductsByCategory(String category) throws DataAccessException {
return this.getHibernateTemplate().find(
"from test.Product product where product.category=?", category);
}
} 4。HibernateDaoSupport 基类使用技巧:
HibernateDaoSupport这也是使用HibernateTemplate的方法之一,只是需要dao继承这个类:
Java代码
1.public class LogDaoImpl extends HibernateDaoSupport implements LogDao {
2. @Override
3. public void save(Log log) {
4. this.getHibernateTemplate().save(log);
5. //this.save(log);
6. System.out.println("log save...");
7. }
8.}
public class LogDaoImpl extends HibernateDaoSupport implements LogDao {
@Override
public void save(Log log) {
this.getHibernateTemplate().save(log);
//this.save(log);
System.out.println("log save...");
}
} dao继承了HibernateDaoSupport类,而这个又拥有sessionFactory和hibernateTemplate的setXXX方法,只要我在初始化这个dao时,注入两个其中一个就可以了。但是这两个setXX方法都为final的,因为不可以重写,这样就不能使用annotation的方式了,只能使用xml的方法了。HibernateDaoSupport部分源代码如下:
Java代码
1.public abstract class HibernateDaoSupport extends DaoSupport{
2. private HibernateTemplate hibernateTemplate;
3.
4. public final void setSessionFactory(SessionFactory sessionFactory) {
5. //......
6. }
7. }
8.
9.public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
10. this.hibernateTemplate = hibernateTemplate;
11. }
12.
13.public final HibernateTemplate getHibernateTemplate() {
14. return this.hibernateTemplate;
15. }
16.//.......其他方法
17.}
public abstract class HibernateDaoSupport extends DaoSupport{
private HibernateTemplate hibernateTemplate;
public final void setSessionFactory(SessionFactory sessionFactory) {
//......
}
}
public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public final HibernateTemplate getHibernateTemplate() {
return this.hibernateTemplate;
}
//.......其他方法
} xml注入方法如下:
Java代码
1.<bean id="logDaoImpl" class="example.dao.impl.LogDaoImpl">
2. <property name="hibernateTemplate" ref="hibernateTemplate"></property>
3. </bean>
<bean id="logDaoImpl" class="example.dao.impl.LogDaoImpl">
<property name="hibernateTemplate" ref="hibernateTemplate"></property>
</bean>
但是问题又来了,如果dao有多个(甚至几个以上),这样就会有大量的xml配置文件,每个dao需要一个配置一个bean,并且在这个bean中需要注入一个sessionFactory或是hibernateTemplate,这样的工作量是非常的大,并且容易出错。
针对有大量的dao我们提供一个解决方案:
我们可以创建一个类,并且这个类来继承hibernateDaoSupport这个类,由于hibernateDaoSupport类的sessionFactory和hibernateTemplate的setXXX方法是final的,因此不能重写,但我们可以在这个类中注入一个sessionFactory或hibernateTemplate但是setXXX方法名,用其它的。然后让dao来继承这个类,这就dao就可以使用annotation方式注解了。代码如下:
Java代码
1.@Component
2.public class SuperDao extends HibernateDaoSupport {
3. @Resource(name="hibernateTemplate")
4. public void setSuperHibernateTemplate(HibernateTemplate hibernateTemplate ){
5. //在这里为父类HibernateDaoSuppport注入hibernateTemplate或是sessionFactory
6. super.setHibernateTemplate(hibernateTemplate);
7. }
8.}
@Component
public class SuperDao extends HibernateDaoSupport {
@Resource(name="hibernateTemplate")
public void setSuperHibernateTemplate(HibernateTemplate hibernateTemplate ){
//在这里为父类HibernateDaoSuppport注入hibernateTemplate或是sessionFactory
super.setHibernateTemplate(hibernateTemplate);
}
}
其它的dao继承这个就可以了,如下所示:
Java代码
1.@Component
2.public class LogDaoImpl extends SuperDao implements LogDao {
3. @Override
4. public void save(Log log) {
5. this.getHibernateTemplate().save(log);
6. //this.save(log);
7. System.out.println("log save...");
8. }
9.}
@Component
public class LogDaoImpl extends SuperDao implements LogDao {
@Override
public void save(Log log) {
this.getHibernateTemplate().save(log);
//this.save(log);
System.out.println("log save...");
}
}
其他的用法不在这里累述,请参看Spring的参考文档.下面重点说说Spring HibernateTemplate模板方法与Callback机制.
二。HibernateTemplate源码分析
下面以save()方法为例进行说明,先看源代码:
HibernateCallback接口的代码如下, 它只有一个方法doInHibernate方法:
Java代码
1.public interface HibernateCallback {
2. Object doInHibernate(Session session) throws HibernateException, SQLException;
3.}
public interface HibernateCallback {
Object doInHibernate(Session session) throws HibernateException, SQLException;
} HibernateTemplate中的具体操作的方法,如save(),update()的具体实现都采用匿名类的方式实现了该接口,在doInHibernate中完成具体的操作。以save()方法为例:
Java代码
1.public Serializable save(final Object entity) throws DataAccessException {
2. return (Serializable) executeWithNativeSession(new HibernateCallback() {
3. public Object doInHibernate(Session session) throws HibernateException {
4. checkWriteOperationAllowed(session);
5. return session.save(entity);
6. }
7. });
8. }
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);
}
});
} 这段代码重点注意以匿名类的方式实现了 HibernateCallback接口.
然后是executeWithNativeSession()方法如下,在此方法中调用核心方法doExecute,如下所示:
Java代码
1.public Object executeWithNativeSession(HibernateCallback action) {
2. return doExecute(action, false, true);
3. }
public Object executeWithNativeSession(HibernateCallback action) {
return doExecute(action, false, true);
} 在这个方法中使用本地已存在的Session去执行此次save操作,doExecute代码如下所示:
Java代码
1./**
2. * Execute the action specified by the given action object within a Session.
3. * @param action callback object that specifies the Hibernate action
4. * @param enforceNewSession whether to enforce a new Session for this template
5. * even if there is a pre-bound transactional Session
6. * @param enforceNativeSession whether to enforce exposure of the native
7. * Hibernate Session to callback code
8. * @return a result object returned by the action, or <code>null</code>
9. * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
10. */
11. protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
12. throws DataAccessException {
13.
14. Assert.notNull(action, "Callback object must not be null");
15.
16. Session session = (enforceNewSession ?
17. SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
18. boolean existingTransaction = (!enforceNewSession &&
19. (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
20. if (existingTransaction) {
21. logger.debug("Found thread-bound Session for HibernateTemplate");
22. }
23.
24. FlushMode previousFlushMode = null;
25. try {
26. previousFlushMode = applyFlushMode(session, existingTransaction);
27. enableFilters(session);
28. Session sessionToExpose =
29. (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
30. Object result = action.doInHibernate(sessionToExpose);
31. flushIfNecessary(session, existingTransaction);
32. return result;
33. }
34. catch (HibernateException ex) {
35. throw convertHibernateAccessException(ex);
36. }
37. catch (SQLException ex) {
38. throw convertJdbcAccessException(ex);
39. }
40. catch (RuntimeException ex) {
41. // Callback code threw application exception...
42. throw ex;
43. }
44. finally {
45. if (existingTransaction) {
46. logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
47. disableFilters(session);
48. if (previousFlushMode != null) {
49. session.setFlushMode(previousFlushMode);
50. }
51. }
52. else {
53. // Never use deferred close for an explicitly new Session.
54. if (isAlwaysUseNewSession()) {
55. SessionFactoryUtils.closeSession(session);
56. }
57. else {
58. SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
59. }
60. }
61. }
62. }
/**
* Execute the action specified by the given action object within a Session.
* @param action callback object that specifies the Hibernate action
* @param enforceNewSession whether to enforce a new Session for this template
* even if there is a pre-bound transactional Session
* @param enforceNativeSession whether to enforce exposure of the native
* Hibernate Session to callback code
* @return a result object returned by the action, or <code>null</code>
* @throws org.springframework.dao.DataAccessException in case of Hibernate errors
*/
protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession)
throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Session session = (enforceNewSession ?
SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
boolean existingTransaction = (!enforceNewSession &&
(!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
if (existingTransaction) {
logger.debug("Found thread-bound Session for HibernateTemplate");
}
FlushMode previousFlushMode = null;
try {
previousFlushMode = applyFlushMode(session, existingTransaction);
enableFilters(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 {
SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
}
}
}
} doExecute这个方法有点过于复杂,不容易理解,现在我用差不多是伪代码的形式来把doExecute这个方法的大概意思写出为,以便大家理解:
Java代码
1.public class MyHibernateTemplate {
2.
3. public Object executeWithNativeSession(HibernateCallback action) {
4. return doExecute(action, false, true);
5. }
6.
7. protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession){
8. Session session = null;
9. try {
10. session = getSession();
11. session.beginTransaction();
12. action.doInHibernate(session);
13. session.getTransaction().commit();
14. } catch (Exception e) {
15. session.getTransaction().rollback();
16. }finally{
17. //....进行额外处理
18. }
19. return null;
20. }
21.
22. private Session getSession() {
23. // TODO Auto-generated method stub
24. return new Session();
25. }
26.}
public class MyHibernateTemplate {
public Object executeWithNativeSession(HibernateCallback action) {
return doExecute(action, false, true);
}
protected Object doExecute(HibernateCallback action, boolean enforceNewSession, boolean enforceNativeSession){
Session session = null;
try {
session = getSession();
session.beginTransaction();
action.doInHibernate(session);
session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback();
}finally{
//....进行额外处理
}
return null;
}
private Session getSession() {
// TODO Auto-generated method stub
return new Session();
}
}
如果你觉得使用匿名内部类传参的方式不好理解,你可以先写一个特定针对save操作的实现类来帮助理解它,如下所示:
Java代码
1.public class HibernateSaveCallbackImpl implements HibernateCallback {
2.
3. private Object object ;
4. public HibernateSaveCallbackImpl(){}
5. public HibernateSaveCallbackImpl(Object object){
6. this.object = object;
7. }
8. public Object doInHibernate(Session session) throws HibernateException,
9. SQLException {
10. session.save(object);
11. return null;
12. }
13.}
public class HibernateSaveCallbackImpl implements HibernateCallback {
private Object object ;
public HibernateSaveCallbackImpl(){}
public HibernateSaveCallbackImpl(Object object){
this.object = object;
}
public Object doInHibernate(Session session) throws HibernateException,
SQLException {
session.save(object);
return null;
}
} 然后再实例化一个HibernateSaveCallbackImpl对象传给MyHibernateTemplate进行使用,如下所示:
Java代码
1.public static void main(String[] args) {
2. HibernateCallback callback = new HibernateSaveCallbackImpl();
3. HibernateCallback callback2 = new HibernateSaveCallbackImpl("save this object");
4. new MyHibernateTemplate().executeWithNativeSession(callback);
5. }
public static void main(String[] args) {
HibernateCallback callback = new HibernateSaveCallbackImpl();
HibernateCallback callback2 = new HibernateSaveCallbackImpl("save this object");
new MyHibernateTemplate().executeWithNativeSession(callback);
} 当MyHibernateTemplate中的doExecute方法执行时,执行到
Java代码
1.action.doInHibernate(session);
action.doInHibernate(session);时,它会先去执行你传入的引用(也就是你自己)的方法。所以称为回调,这与模板模式中的钩子函数基本是一样的。其实回调,简单的可以说是:将自己的引用传给别的方法,在别的方法里面,通过自己的引用调用自己的方法。
相关推荐
spring HibernateTemplate汇总
hibernateTemplate的常用方法
HibernateTemplate的简单示例
HibernateTemplate的用法总结,我自己整理的,仅供参考
HibernateTemplate 的常规用法.doc HibernateTemplate 的常规用法.doc
关于使用HibernateTemplate
对Spring框架中,HibernateTemplate的使用,底层dao中HibernateTemplate的使用以及HibernateCallBack调用等等
HibernateTemplate的方法部分使用,还有部分的个人见解,有错的,请指出,谢谢
hibernateTemplate常用方法.htm
Spring整合hibernate(2)之基于HibernateTemplate的整合,jar需要自己添加!
HibernateTemplat技术,此文档详细描述了HibernateTemplate的方法及功能说明,并有实例。
HibernateTemplate源代码
GenericHibernateDao 继承 HibernateDao,简单封装 HibernateTemplate 各项功能,简化基于Hibernate Dao 的编写。
对于Hiberante对数据库种数据删除操作的归纳
HibernateTemplate类的使用
基于HIbernateTemplate的代码自动生成,能够自动生成dao和service文件,提高开发效率
JavaWeb开发,Sping框架,才用Hibernate Template进行字段截取,分组统计实现方法。
这是一个很好的文件,希望大家从中能找到自己的又用的部分,并且不断的进步
spring hibernatetemplate