Interceptor接口提供了从会话(session)回调(callback)应用程序(application)的机制, 这种回调机制可以允许应用程序在持久化对象被保存、更新、删除或是加载之前,检查并(或)修改其 属性。一个可能的用途,就是用来跟踪审核(auditing)信息。例如:下面的这个拦截器
,会在一个实现了 Auditable
接口的对象被创建时自动地设置createdBy和createdDt
属性。
创建AuditInfo.java这个bean封装这些Audit的信息
public class AuditInfo { private int createdBy; private Date createdDT; public int getCreatedBy() { return createdBy; } public void setCreatedBy(int createdBy) { this.createdBy = createdBy; } public Date getCreatedDT() { return createdDT; } public void setCreatedDT(Date createdDT) { this.createdDT = createdDT; } }
创建Auditable.java.我这里为方便采用的是abstract class,建议使用interface.
Auditable接口是用来让hibernate PO来继承的
public class User extends Auditable {}
我这里将AuditInfo和UserTo都放入Auditable,所有继承Auditable的PO都会继承这两个属性
UserTo是用户登录后存放在session中的用户信息,如userid,username之类的.
public abstract class Auditable implements java.io.Serializable { private static final long serialVersionUID = 1L; private AuditInfo auditInfo; private UserTo userTo; public UserTo getUserTo() { return userTo; } public void setUserTo(UserTo userTo) { this.userTo = userTo; } public AuditInfo getAuditInfo() { return auditInfo; } public void setAuditInfo(AuditInfo auditInfo) { this.auditInfo = auditInfo; } }
让PO继承Auditable,
public class User extends Auditable {}
同时需要在对应的mapping配置文件中设置映设关系
<hibernate-mapping package="report.model.hibernate.po"> <class name="User" table="c_user"> <id name="userId" type="int" column="user_id"> <generator class="identity"> </generator> </id> <property name="userName" type="java.lang.String" column="user_name" /> <property name="password" type="java.lang.String" column="password" /> <component name="auditInfo" class="report.common.hibernate.interceptor.AuditInfo"> <property name="createdBy" type="int" column="created_by" /> <property name="createdDT" type="java.sql.Date" column="created_dt" /> </component> </class> </hibernate-mapping>
现在开始写AuditInterceptor
public class AuditInterceptor extends EmptyInterceptor { private static final Log log = LogFactory.getLog(UserServiceImpl.class); public boolean onSave(Object entity, Serializable id, Object state[], String as[], Type atype[]) { log.info("AuditInterceptor onSave begin"); if (entity instanceof Auditable) { AuditInfo info = new AuditInfo(); info.setCreatedBy(((Auditable) entity).getUserTo().getUserId()); info.setCreatedDT(new Date(System.currentTimeMillis())); for(int i=0;i<as.length;i++){ if("auditInfo".equals(as[i])){ state[i]=info; log.info("insert audit info"); return true; } } log.info("Created by "+((Auditable) entity).getUserTo().getUserName()); } return false; } public boolean onLoad(Object entity, Serializable id, Object state[], String as[], Type atype[]) { log.info("AuditInterceptor onLoad begin"); return false; } }
拦截器可以有两种:Session
范围内的,和SessionFactory
范围内的。
当使用某个重载的SessionFactory.openSession()使用Interceptor
作为参数调用打开一个session的时候,就指定了Session
范围内的拦截器。
Session session = sf.openSession( new AuditInterceptor() );
SessionFactory
范围内的拦截器要通过Configuration
中注册,而这必须在创建SessionFactory
之前。在这种情况下,给出的拦截器会被这个SessionFactory
所打开的所有session使用了;除非session打开时明确指明了使用的拦截器。SessionFactory
范围内的拦截器,必须是线程安全的,因为多个session可能并发使用这个拦截器,要因此小心不要保存与session相关的状态。
new Configuration().setInterceptor( new AuditInterceptor() );
在Spring中配置Interceptor:
<!-- Transaction config start --> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> <property name="entityInterceptor" ref="auditInterceptor" /> </bean> <!-- HibernateTemplate Begin--> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate"> <constructor-arg ref="sessionFactory" /> <property name="entityInterceptor" ref="auditInterceptor" /> </bean> <!-- HibernateTemplate End -->