AOP не может поймать исключение DAO весной из-за побочного эффекта прокси при весеннем впрыске - PullRequest
0 голосов
/ 13 апреля 2011

Цель состоит в том, чтобы обработать все постоянные исключения и перейти к простому общему исключению, чтобы сервисный уровень мог легко их обработать.

Решение состоит в том, чтобы использовать 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 внедряется пружиной, но для обычного исключения из базы данных она может быть перехвачена, а для исключения соединения она не выполнена.

Я думаю, потому что до того, как весна внедрила реализацию 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

Но если это ошибка соединения с БД:

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

1 Ответ

1 голос
/ 13 апреля 2011

Вы должны переместить аннотацию @Transactional в свой метод Service.При аннотировании класса с помощью @Transaction Spring из него создается прокси.

Проблема заключается в том, что перехватчик @Transactional (прокси) пытается инициировать транзакцию, но не удается, потому что нет соединения с БД,Ошибка не была перехвачена вашим DAOExceptionTranslator, потому что он выполняется До вашего перехваченного кода.

...