本站首页    管理页面    写新日志    退出


«September 2025»
123456
78910111213
14151617181920
21222324252627
282930


公告
 本博客在此声明所有文章均为转摘,只做资料收集使用。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:1304
评论数量:2242
留言数量:5
访问次数:7608082
建立时间:2006年5月29日




[Hibernate]use AOP to simplify hibernateTemplate (Hibernate3)
软件技术

lhwork 发表于 2007/1/23 12:08:54

Spring ORM 替 Hibernate 的 API (Session and Query) 做了一番修整,也就是 HibernateTemplate ,它最主要的目的是 resource 控管及 exception 的轉換。有了這個 persistence layer 的 code 就可以大量的減少並且降低出錯的機會。然而這個 API 卻抹剎了 Hibernate API 的簡單易用優點,舉例來說,如果藉由 hibernateTemplate 控制 Hibernate Session (ex. Criteria),唯一的做法就是寫很難看的 Callback:public MyData findByNo(final String no) { final String hql = " select data from MyData data " + " where data.no = :no "; HibernateCallback hc = new HibernateCallback() { public Object doInHibernate(Session session) { Query q = session.createQuery(hql); q.setString("no", no); return q.uniqueResult(); } }; return (MyData) hibernateTemplate.execute(hc);}inner class + final.... 有夠難看。下面要介紹的是,利用 Spring AOP 的 AutoProxy 的功能,自動將 DAO 的所有 method 用 HibernateCallback 包起來。如此一來,便可以自由在 DAO 中自由存取 Hibernate Session 了:總共需要三個 class:第一個是 Advice,也就是將所有 method 都先用 HibernateCallback 包起來,然後將 Hibernate Session 放入 HibernateDAOWarpper 裡。public class HibernateDAOWrapperMethodInterceptor implements MethodInterceptor { private HibernateTemplate hibernateTemplate; public Object invoke(final MethodInvocation methodInvocation) throws Throwable { try { return hibernateTemplate.execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { HibernateDAOWrapper.currentSession.set(session); try { return methodInvocation.proceed(); } catch (Throwable e) { if (e instanceof HibernateException) { throw (HibernateException) e; } else if (e instanceof SQLException) { throw (SQLException) e; } else { //must re-throw as RuntimeException, and let //hibernateTemplate deal with resource management throw new ExceptionCarrier(e); } } } }); } catch (ExceptionCarrier e) { throw e.throwable; } } private static class ExceptionCarrier extends RuntimeException { private Throwable throwable; public ExceptionCarrier(Throwable t) { this.throwable = t; } } public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; }}接下來就是 AutoProxyCreator,當它遇到 bean 的 class 為 HibernateDAOWrapper 的 subclass 時,它就會自動替該 bean 做 proxy。public class HibernateDAOWrapperAutoProxyCreator extends AbstractAutoProxyCreator { protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource customTargetSource) throws BeansException { if (HibernateDAOWrapper.class.isAssignableFrom(beanClass)) { return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS; } else { return DO_NOT_PROXY; } }}有了這個,再搭配上面的 Advice,我們就可以將所有 HibernateDAOWrapper 的 subclass 的所有 method 都用 HibernateCallback 包起來。Spring 的設定如下:<bean id="hibernateDAOWrapperAutoProxyCreator" class="org.bioinfo.util.spring.dao.HibernateDAOWrapperAutoProxyCreator"> <property name="interceptorNames"> <list> <value>hibernateDAOWrapperMethodInterceptor</value> </list> </property> <!-- for use CGlib to create proxy, (default to false, which will use Proxy if it detects interface presence) --> <property name="proxyTargetClass"> <value>true</value> </property></bean> <bean id="hibernateDAOWrapperMethodInterceptor" class="org.bioinfo.util.spring.dao.HibernateDAOWrapperMethodInterceptor"> <property name="hibernateTemplate"> <ref local="hibernateTemplate"/> </property></bean>這個只要設一次就夠了。接下來我們再來看看主角:/** * A special HibernateTemplate wrapper for DAO. You need to do: * * (1) Extends this class and use getSession() to obtain Hibernate3 Session * * <code> * public class YourDAO extends HibernateDAOWrapper { * * public MyProject findByProjectCode(String code) { * String hql = "select prj from MyProject prj where prj.code = :code"; * * return (MyProject) getSession().createQuery(hql) * .setString("code",code").uniqueResult(); * } * } * </code> * * (2) At your spring *.xml, just write one line: * * <code> * <bean id="yourDAO" class="some.thing.YourDAO"></bean> * </code> * * done !! * @author ingram * */public abstract class HibernateDAOWrapper { final static ThreadLocal currentSession = new ThreadLocal(); protected final Session getSession() { return (Session) currentSession.get(); }}呵,小的可憐,它的功能就是提供 getSession() 的 method 給 subclass 的 DAO 而已。這個 session 來自於 Advice,並且放在 ThreadLocal裡,因此是 thread-safe 的。使用方式就如上面的 javadoc 所說,將 DAO 直接 subclass 這個 Wrapper,並在 spring 裡定義即可。這樣一來 DAO 就可以快快樂樂的用 Hibernate API 啦,爽!(註:僅適用 Hibernate3,於 Hibernate 3.0.3 + Spring 1.2 final 測試 )


阅读全文(4061) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.047 second(s), page refreshed 144772779 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号