我需要审核ejb bean的调用。说审计我的意思是写信息,例如当前记录的用户,方法名称,对数据库的附加描述。我决定使用CDI装饰器来做到这一点:
@Decorator
public class AccountServiceBeanDecorator implements AccountService {
@Inject
@Delegate
@Any
AccountService accountService;
@EJB
private AuditService auditService;
@Override
public Account createAccount(Account account) {
auditService.saveAudit("Method: createAccount", currentUser, "Creating account by admin");
return accountService.createAccount(account);
}
}
和装饰类:
@Stateless
public class AccountServiceBean implements AccountService {
@Override
public Account createAccount(Account account) {
...
}
}
现在,如果我从另一个ejb无状态bean调用AccountService,那么事务会发生什么?:
@Stateless
public ApplicationFacadeBean implements ApplicationFacade {
@EJB
private AccountService accountService;
@Override
public Account createAccount(Account account) {
return accountService.createAccount(account);
}
}
我想在decorator(AccountServiceBeanDecorator)和装饰类(AccountServiceBean)中记录事务状态,所以我在两个类中都将TransactionSynchronizationRegistry注入资源:
@Decorator
public class AccountServiceBeanDecorator implements AccountService {
@Inject
@Delegate
@Any
AccountService accountService;
@EJB
private AuditService auditService;
@Resource
private TransactionSynchronizationRegistry reg;
@Override
public Account createAccount(Account account) {
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
log.info("tx ({}): {}", new Object[] {reg.getTransactionStatus(), reg.getTransactionKey()});
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
auditService.saveAudit("Method: createAccount", currentUser, "Creating account by admin");
return accountService.createAccount(account);
}
}
和
@Stateless
public class AccountServiceBean implements AccountService {
@Resource
private TransactionSynchronizationRegistry reg;
@Override
public Account createAccount(Account account) {
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
log.info("tx ({}): {}", new Object[] {reg.getTransactionStatus(), reg.getTransactionKey()});
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
...
}
}
我收到了奇怪的行为:
从装饰师登录
tx (0): JavaEETransactionImpl: txId=6 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization@68fb15d0]]]
第二个日志上的NullPointerException(reg为null)。
有人可以向我解释一下吗? Wheter AccountServiceBean类是否在与ApplicationFacade相同的事务中调用?
谢谢
答案 0 :(得分:1)
首先:我不会将ejbs与cdi拦截器混在一起。 ejbs在拦截器实现上有它。
秒:拦截器在与拦截器所在的ejb相同的事务中执行。
可能的解决方案:
这将从拦截器所在的ejb当前事务内部创建一个新事务
- >我知道我的英语不是很好。但我希望你明白我认为应该有效。如果我有时间,我在github上做例子......
答案 1 :(得分:0)
虽然面对你的问题,我用拦截器做了这个,而不是装饰器。 EJB规范支持这些......无论如何,这是我的代码,你需要从你的情境中的上下文中获取变量:
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
public class InvocationCountInterceptor {
@Inject
private InvocationCounter counter;
@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
Object returnValue = ctx.proceed();
Class<? extends Object> className = ctx.getTarget().getClass();
Method methodName = ctx.getMethod();
counter.incrementCounter(className, methodName);
return returnValue;
}
}
然后,无论您想要审核哪种EJB或EJB方法,我都添加了这个:@Interceptors(InvocationCountInterceptor.class)