目的是處理所有持久性異常並將其包裝爲簡單的一般異常,以便服務層可以輕鬆處理它們。春季因春季注入代理副作用導致AOP無法捕捉DAO異常
解決方法是使用AOP從DAO實現中攔截異常。下面是Spring配置:
<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的的實現是由彈簧注入,但是對於正常的db異常,它可以被攔截,並且對於連接異常,它失敗了。
我覺得因爲在spring注入DAO之前,它會先構造連接,然後失敗,所以它沒有調用目標操作。
我想攔截DAO的所有異常,如何通過彈簧注入來解決代理的副作用。
這裏是兩個不同的堆棧:
的數據庫邏輯錯誤:
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, Method, Object[]) line: 202
$Proxy17.findUserByUsername(String) line: not available
UserService.getUser(String) line: 74
但如果是DB連接錯誤:
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, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
AspectJAfterThrowingAdvice(AbstractAspectJAdvice).invokeAdviceMethodWithGivenArgs(Object[]) line: 621
AspectJAfterThrowingAdvice(AbstractAspectJAdvice).invokeAdviceMethod(JoinPointMatch, Object, Throwable) line: 603
AspectJAfterThrowingAdvice.invoke(MethodInvocation) line: 59
ReflectiveMethodInvocation.proceed() line: 172
ExposeInvocationInterceptor.invoke(MethodInvocation) line: 89
ReflectiveMethodInvocation.proceed() line: 172
JdkDynamicAopProxy.invoke(Object, Method, Object[]) line: 202
$Proxy17.findUserByUsername(String) line: not available
UserService.getUser(String) line: 74
解決方法是指出每個代理的順序。 添加關鍵字順序後,首先調用DBExceptions代理,更改後查看堆棧。 – 2011-04-13 07:01:43
是的,那是另一種方式。但請注意,通常最好在服務層上保留@Transactional註釋,以保證多次調用Dao層的事務流程。 – 2011-04-13 07:14:37
謝謝,我們將檢查服務層事務控制。 – 2011-04-13 08:59:39