1

in my app which is based on struts2, spring IoC and Transasctions, jpa, Hibernate i want to introduce an "audit log function" which will log all the important events, such as : a user has been created/updated, or a ticket was opened by somebody...
I want to keep this log in the database so for this i will have a DAO. I created also a service class for this purpose 'AuditLogService' which will have transactional behavior " propagation="REQUIRES_NEW" due to the fact that i want to log the event no matter if the logged event was successful or not.
The problem is that if i have something like this in my user service :

@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;
}

the audit log method is executed before committing the save user method and reports that the event was true, but in fact the event was false.
Any idea how can i solve this ? or maybe this approach is not the best... ?

  • updates !
    After Michael`s advices i have transformed my Service also into an Aspect

    @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){
    }
    

    }

and now i have my method signature like here. everything works ok, i can detect if a operation failed or was successful and i can log this into a log file, but if i want to log this into a table from database via a dao class, when the operations fail and the transaction is rolled back my audit entry is not inserted.
First i thought that this is happening because the both operations, the actual method that need to be audited and the audit event are running in the same transactional context, and if one of them is rolled back the entire transaction is, and i have created a new transaction for the aspect logging part. But this seems not to work.

Any ideea why ?

4

1 回答 1

1

The approach is not correct, because the declarative transaction are implemented through an around advice (AOP) so the whole method executes, including your finally block with the audit, then returns and the transaction is committed.

I'd recommend to write your own auditing Aspect as something like auditing or logging is a prime example for cross cutting concerns.

Have a look at Aspect Oriented Programming with Spring

I'd go with the After (finally) advice so you can audit failed and successful stuff.

It's actually not that complicated… You won't need AspectJ, Spring Aspects will be enough for the given purpose.

于 2012-07-25T08:27:21.963 回答