在我的应用程序中基于struts2,Spring IoC和Transasctions,jpa,Hibernate我想引入一个“审计日志功能”,它将记录所有重要事件,例如:用户已被创建/更新,或者有人打开了一张票......
我想将这个日志保存在数据库中,所以为此我将有一个DAO。我还为此创建了一个服务类'AuditLogService',它将具有事务行为“propagation =”REQUIRES_NEW“,因为我想记录事件,无论记录的事件是否成功。
问题是如果我的用户服务中有这样的东西:
@Override
public boolean saveUser(UserDto userDto) {
User u = new User();
u.setFirstName(userDto.getFirstName());
u.setLastName(userDto.getLastName());
u.setUserName(userDto.getUserName());
u.setPassword(userDto.getPassword());
u.setIsLdapUser(userDto.getIsLdapUser());
u.setId(userDto.getId());
u.setAgentId(userDto.getAgentId());
Boolean eventStatus = true;
String event="";
try{
if (u.getId()!=null){
dao.update(u);
event = "UPDATE_USER";
}else{
dao.create(u);
event = "CREATE_USER";
}
}catch (Exception e) {
e.printStackTrace();
eventStatus = false;
return false;
}
finally {
AuditLogEvent ale = auditLogEventDao.getAuditLogEvent(event);
auditLogService.addAuditLogEvent(ale, eventStatus,u.toString());
}
return false;
}
审核日志方法在提交保存用户方法之前执行,并报告事件为真,但事实上该事件为假。
知道怎么解决这个问题?或者这种方法不是最好的......?
更新!
在Michael的建议之后,我将我的服务转变为一个方面
@Aspect
@Service
class AuditLogAspectImpl implements AuditLogAspect {
@Autowired
private AuditLogDao dao;
@Autowired
private UserDao userDao;
@Override
@AfterReturning(pointcut = "execution(* xxx.yy.services..*.save*(..))", returning = "retVal")
public boolean afterLogEvent(JoinPoint joinPoint,Object retVal){
}
}
现在我的方法签名就像这里一样。一切正常,我可以检测操作是否失败或是否成功,我可以将其记录到日志文件中,但是如果我想通过dao类将其记录到数据库中的表中,则当操作失败并且事务被滚动时我没有插入我的审核条目 首先我认为这是发生的,因为两个操作,需要审计的实际方法和审计事件都在同一个事务上下文中运行,如果其中一个回滚整个事务,我创建了一个方面记录部分的新事务。但这似乎不起作用。
任何想法为什么?
答案 0 :(得分:1)
方法不正确,因为声明性事务是通过around advice(AOP)实现的,所以整个方法执行,包括你的审计finally块,然后返回并提交事务。
我建议您编写自己的审核方面,因为审核或日志记录是横切问题的主要示例。
查看Aspect Oriented Programming with Spring
我选择After (finally) advice,以便您可以审核失败的成功资料。
实际上并不复杂......你不会需要AspectJ,Spring Aspects足以满足特定目的。