问题描述
|
目的是处理所有持久性异常并将其包装为简单的常规异常,以便服务层可以轻松地处理它们。
解决方案是使用AOP拦截DAO实现中的异常。这是弹簧配置:
<bean id=\"DBExceptions\" class=\"com.dao.impl.DAOExceptionTranslator\" />
<aop:config>
<aop:aspect id=\"dbExceptionsAspect\" ref=\"DBExceptions\">
<aop:after-throwing throwing=\"ex\"
pointcut=\"execution(* com.dao.impl.*.*(*))\" method=\"doDAOActions\" />
</aop:aspect>
</aop:config>
这是DAO的实现:
@Transactional
public class UserDAOImpl extends GenericDAOImpl implements UserDAO {
@PersistenceContext
protected EntityManager entityManager;
@Override
public User findUserByUsername(String username) throws DAOException {
Query query = entityManager
.createquery(\"select u from User u where u.username=:username\");
query.setParameter(\"username\",username);
Object userObject = query.getSingleResult();
return (User) userObject;
}
这是使用DAO的代码:
private UserDAO userDAO;
public User getUserById(int id) throws UserServiceException {
try {
Object user = userDAO.findById(User.class,id);
...
userDAO的实现是由spring注入的,但是对于普通的db异常,它可以被拦截,而对于连接异常,则它失败。
我认为是因为在spring注入DAO实现之前,它将首先构造连接,但是失败了,因此它没有调用目标操作。
我想拦截来自DAO的所有异常,如何通过弹簧注入解决代理的副作用。
这是两个不同的堆栈:
db逻辑错误:
UserDAOImpl.findUserByUsername(String) line: 23
NativeMethodAccessorImpl.invoke0(Method,Object,Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object,Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object,Object[]) line: 25
Method.invoke(Object,Object...) line: 597
AopUtils.invokeJoinpointUsingReflection(Object,Method,Object[]) line: 309
ReflectiveMethodInvocation.invokeJoinpoint() line: 183
ReflectiveMethodInvocation.proceed() line: 150
AspectJAfterThrowingAdvice.invoke(MethodInvocation) line: 55
ReflectiveMethodInvocation.proceed() line: 172
TransactionInterceptor.invoke(MethodInvocation) line: 110
ReflectiveMethodInvocation.proceed() line: 172
ExposeInvocationInterceptor.invoke(MethodInvocation) line: 89
ReflectiveMethodInvocation.proceed() line: 172
JdkDynamicAopProxy.invoke(Object,Object[]) line: 202
$Proxy17.findUserByUsername(String) line: not available
UserService.getUser(String) line: 74
但是如果是数据库连接错误:
at org.springframework.orm.jpa.JpaTransactionManager.dobegin(JpaTransactionManager.java:382)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy17.findUserByUsername(UnkNown Source)
at com.service.UserService.getUser(UserService.java:74)
如何解决问题?
解决方案是指示每个代理的顺序,更改为
<aop:config>
<aop:aspect id=\"dbExceptionsAspect\" ref=\"DBExceptions\" order=\"1\">
<aop:after-throwing throwing=\"ex\"
pointcut=\"execution(* com.dao.impl.*.*(*))\" method=\"doDAOActions\" />
</aop:aspect>
</aop:config>
添加关键字顺序后,将首先调用DBExceptions代理,更改后请参见堆栈。
DAOExceptionTranslator.doDAOActions(Exception) line: 12
NativeMethodAccessorImpl.invoke0(Method,Object...) line: 597
AspectJAfterThrowingAdvice(AbstractAspectJAdvice).invokeAdviceMethodWithGivenArgs(Object[]) line: 621
AspectJAfterThrowingAdvice(AbstractAspectJAdvice).invokeAdviceMethod(JoinPointMatch,Throwable) line: 603
AspectJAfterThrowingAdvice.invoke(MethodInvocation) line: 59
ReflectiveMethodInvocation.proceed() line: 172
ExposeInvocationInterceptor.invoke(MethodInvocation) line: 89
ReflectiveMethodInvocation.proceed() line: 172
JdkDynamicAopProxy.invoke(Object,Object[]) line: 202
$Proxy17.findUserByUsername(String) line: not available
UserService.getUser(String) line: 74
解决方法
您应该在Service方法上移动@Transactional批注。当使用@Transaction注释一个类时,Spring将从中创建一个代理。
问题在于@Transactional拦截器(代理)尝试启动事务,但是由于没有与数据库的连接而失败。该错误未被DAOExceptionTranslator拦截,因为它是在拦截代码之前执行的。