我在Spring 4和Hibernate 5中进行了以下设置: 这是设置Hibernate的applicationContext.xml的摘录
<bean id="myAuditLogInterceptorManager" class="company.audit.AuditLogManager">
<constructor-arg>
<ref bean="interceptorSessionFactory" />
</constructor-arg>
</bean>
<bean id="auditInterceptor"
class="company.interceptor.audit.AuditLogInterceptor">
<property name="sessionFactory" ref="interceptorSessionFactory" />
<property name="auditLogManager" ref="myAuditLogInterceptorManager" />
</bean>
<bean id="interceptorSessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.order_inserts">${hibernate.order_inserts}</prop>
<prop key="hibernate.order_updates">${hibernate.order_updates}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
<prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource" />
</property>
</bean>
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
depends-on="flyway">
<property name="entityInterceptor" ref="auditInterceptor" />
<property name="packagesToScan">
<list>******
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.order_inserts">${hibernate.order_inserts}</prop>
<prop key="hibernate.order_updates">${hibernate.order_updates}</prop>
<prop key="hibernate.event.merge.entity_copy_observer">allow</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.use_second_level_cache">${hibernate.cache.use_second_level_cache}</prop>
<prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
</props>
</property>
<property name="dataSource">
<ref bean="myDataSource" />
</property>
</bean>
<bean id="myDataSource" class="org.apache.tomcat.jdbc.pool.DataSource"
destroy-method="close" p:driverClassName="${datasource.driverClass}"
p:url="${datasource.url}" p:username="${datasource.user}" p:password="${datasource.pass}"
p:maxWait="${datasource.maxWait}" p:minIdle="${datasource.minIdle}"
p:maxIdle="${datasource.maxIdle}" p:maxActive="${datasource.maxActive}"
p:fairQueue="true" p:jmxEnabled="${datasource.jmxEnabled}"
p:removeAbandoned="${datasource.removeAbandoned}"
p:removeAbandonedTimeout="${datasource.removeAbandonedTimeout}"
p:logAbandoned="${datasource.logAbandoned}" p:testOnBorrow="${datasource.testOnBorrow}"
p:timeBetweenEvictionRunsMillis="${datasource.timeBetweenEvictionRunsMillis}"
p:minEvictableIdleTimeMillis="${datasource.minEvictableIdleTimeMillis}"
p:validationInterval="${datasource.validationInterval}"
p:abandonWhenPercentageFull="${datasource.abandonWhenPercentageFull}"
p:validationQuery="SELECT 1"
p:jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer;org.apache.tomcat.jdbc.pool.interceptor.ConnectionState" />
我有两个会话工厂,一个用于AuditLogManager,另一个用于其余的应用程序。 AuditLogManager是负责在数据库中编写审核的类:
然后是AuditLogManager类:
public class AuditLogManager {
private final Logger log = Logger.getLogger(this.getClass().getName());
protected SessionFactory sessionFactory;
public AuditLogManager(final SessionFactory sessionFactory) {
super();
this.sessionFactory = sessionFactory;
}
private static Long getCurrentUserId() {
Object currentUserID = null;
if (SecurityContextHolder.getContext().getAuthentication() != null) {
currentUserID = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (currentUserID == null)
return Long.valueOf(-1);
else if (currentUserID.toString().contains("anonymousUser"))
return Long.valueOf(-1);
return Long.parseLong(currentUserID.toString());
}
return Long.valueOf(-1);
}
public void log(final String message, final AuditType type, final Long customerGroupId, final String objectType, final String objectName) {
if (message.isEmpty())
return;
this.log(message, type, customerGroupId, objectType, objectName, "");
}
public SessionFactory getSessionFactory() {
final SessionFactory mySessionFactory = this.sessionFactory;
return mySessionFactory;
}
public void log(final String message, final AuditType type, final Long customerGroupId, final String objectType, final String objectName, final String operation) {
if (message.isEmpty())
return;
final Long userId = AuditLogManager.getCurrentUserId();
final Date timestamp = new Date();
StatelessSession session = null;
try {
session = this.getSessionFactory().openStatelessSession();
final StringBuilder query = new StringBuilder();
query.append(" SET NOCOUNT ON; ");
query.append(" INSERT INTO [dbo].[SystemAudits] ");
query.append(" ( [message] ");
query.append(" ,[user_fk] ");
query.append(" ,[customerGroup_fk] ");
query.append(" ,[type] ");
query.append(" ,[operation] ");
query.append(" ,[timestamp] ");
query.append(" ,[objectType] ");
query.append(" ,[objectName]) ");
query.append(" VALUES ");
query.append(" ( :message ");
query.append(" , :userId ");
query.append(" , :customerGroupId ");
query.append(" , :type ");
query.append(" , :operation ");
query.append(" , :timestamp ");
query.append(" , :objectType ");
query.append(" , :objectName");
query.append(" ) ");
query.append(" SET NOCOUNT OFF; ");
final Transaction tx = session.beginTransaction();
final SQLQuery sqlQuery = session.createSQLQuery(query.toString());
sqlQuery.setParameter("message", message);
sqlQuery.setParameter("userId", userId);
sqlQuery.setParameter("customerGroupId", customerGroupId);
sqlQuery.setParameter("type", type.name());
sqlQuery.setParameter("operation", operation);
sqlQuery.setParameter("timestamp", timestamp);
sqlQuery.setParameter("objectType", objectType);
sqlQuery.setParameter("objectName", objectName);
sqlQuery.executeUpdate();
tx.commit();
} catch (final Exception e) {
this.log.error(e, "Error");
} finally {
if (session != null)
session.close();
}
}
}
拦截器收集实现接口IAuditLog的对象。我根据对象的状态将它们放在三个Set中(Create / Delete / Update)。在postFlush函数上,我迭代对象列表并记录一个条目:
public class AuditLogInterceptor extends EmptyInterceptor {
protected Logger log = Logger.getLogger(this.getClass().getName());
private AuditLogManager auditLogManager;
private final Set<IAuditLog> inserts = Collections.synchronizedSet(new HashSet());
private final Set<IAuditLog> updates = Collections.synchronizedSet(new HashSet());
private final Set<IAuditLog> deletes = Collections.synchronizedSet(new HashSet());
@Override
public boolean onSave(final Object entity, final Serializable id, final Object[] state, final String[] propertyNames, final Type[] types) throws CallbackException {
this.log.trace("onSave");
if (entity instanceof IAuditLog)
this.inserts.add((IAuditLog) entity);
return false;
}
@Override
public boolean onFlushDirty(final Object entity, final Serializable id, final Object[] currentState, final Object[] previousState, final String[] propertyNames, final Type[] types) throws CallbackException {
this.log.trace("onFlushDirty");
if (entity instanceof IAuditLog)
this.updates.add((IAuditLog) entity);
return false;
}
@Override
public void onDelete(final Object entity, final Serializable id, final Object[] state, final String[] propertyNames, final Type[] types) {
this.log.trace("onDelete");
if (entity instanceof IAuditLog)
this.deletes.add((IAuditLog) entity);
}
// called before commit into database
@Override
public void preFlush(final Iterator iterator) {
}
// called after committed into database
@Override
public void postFlush(final Iterator iterator) {
this.log.trace("postFlush");
try {
final Iterator<IAuditLog> iter = this.inserts.iterator();
while (iter.hasNext()) {
final IAuditLog entity = iter.next();
final String objectType = entity.getAuditLogObjectType();
if (objectType != null) {
final String objectName = entity.getAuditLogObjectName();
final AuditType type = entity.getAuditType();
final Long customerGroupId = entity.getAuditCustomerAdministratorId();
final List<String> changes = entity.getChanges();
this.auditLogManager.log(StringUtils.join(changes, ","), type, customerGroupId, objectType, objectName, "CREATE");
}
}
} catch (final Exception e) {
this.log.error(e, "Error");
} finally {
this.inserts.clear();
}
try {
final Iterator<IAuditLog> iter = this.updates.iterator();
while (iter.hasNext()) {
final IAuditLog entity = iter.next();
final String objectType = entity.getAuditLogObjectType();
if (objectType != null) {
final String objectName = entity.getAuditLogObjectName();
final AuditType type = entity.getAuditType();
final Long customerGroupId = entity.getAuditCustomerAdministratorId();
final List<String> changes = entity.getChanges();
this.auditLogManager.log(StringUtils.join(changes, ","), type, customerGroupId, objectType, objectName, "UPDATE");
}
}
} catch (final Exception e) {
this.log.error(e, "Error");
} finally {
this.updates.clear();
}
try {
final Iterator<IAuditLog> iter = this.deletes.iterator();
while (iter.hasNext()) {
final IAuditLog entity = iter.next();
final String objectType = entity.getAuditLogObjectType();
if (objectType != null) {
final String objectName = entity.getAuditLogObjectName();
final AuditType type = entity.getAuditType();
final Long customerGroupId = entity.getAuditCustomerAdministratorId();
final List<String> changes = entity.getChanges();
this.auditLogManager.log(StringUtils.join(changes, ","), type, customerGroupId, objectType, objectName, "DELETE");
}
}
} catch (final Exception e) {
this.log.error(e, "Error");
} finally {
this.deletes.clear();
}
}
public AuditLogManager getAuditLogManager() {
return this.auditLogManager;
}
public void setAuditLogManager(final AuditLogManager auditLogManager) {
this.auditLogManager = auditLogManager;
}
}
有时,我会收到以下错误消息:
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1442)
at java.util.HashMap$KeyIterator.next(HashMap.java:1466)
at compnay.interceptor.audit.AuditLogInterceptor.postFlush(AuditLogInterceptor.java:72)
我不知道怎么了 谢谢