@AfterThrowing无法正常工作 [英] @AfterThrowing not work as expected

查看:112
本文介绍了@AfterThrowing无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用AOP拦截服务层中抛出的所有运行时异常,然后将其作为域异常重新抛出.

I want to use AOP to intercept all runtime exceptions thrown in service layer and rethrow as domain exceptions.

@Aspect
@Component
public class ExceptionWrapperInterceptor {

    @Pointcut("within(*.service.*)")
    public void onlyServiceClasses() {}

    @AfterThrowing(pointcut = "onlyServiceClasses()", throwing = "ex")
    public void intercept(DataAccessException ex) throws Exception {
        //throw DatabaseException
    }

    @AfterThrowing(pointcut = "onlyServiceClasses()", throwing = "ex")
    public void intercept(RuntimeException ex) throws Exception {
        //throw ServiceException
    }

}

这里的问题是,使用DataAccessException的子类,运行时将执行错误的方法.有一个优雅的解决方案吗?

The problem here is that, with a subclass of DataAccessException, the runtime execute the wrong method. There is an elegant solution to this?

春季版本:4.2.4.释放

Spring Version: 4.2.4.RELEASE

P.S.一个具有很多instanceof的通用方法(从其他问题中读取)对我来说并不理想;-)

P.S. A single generic method (read from other questions) with a lot of instanceof is not elegant for me ;-)

谢谢 弗朗切斯科

推荐答案

我相信您的期望是错误的(只有一个拦截方法会与方法重载类似地匹配).

I believe, that your expectation is wrong (that only one intercept method will match similarly as for method overloading).

但是,当RuntimeExceptionDataAccessException的父级时,两种方法都将执行...

But while RuntimeException is parent of DataAccessException both methods are executed...

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

    <context:component-scan base-package="test" />

    <aop:aspectj-autoproxy />

</beans>

AopTest

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {

    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring.xml");
        MyService ms = ac.getBean(MyService.class);
        try {
            ms.throw1();
        } catch (Exception e) {
//          e.printStackTrace();
        }
        try {
            ms.throw2();
        } catch (Exception e) {
//          e.printStackTrace();
        }
    }
}

MyAspect

package test;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {

    @AfterThrowing(pointcut = "execution(public * *(..))", throwing = "ex")
    public void intercept(DataAccessException ex) throws Exception {
        //throw DatabaseException
        System.out.println("DAE");
    }

    @AfterThrowing(pointcut = "execution(public * *(..))", throwing = "ex")
    public void intercept(RuntimeException ex) throws Exception {
        //throw ServiceException
        System.out.println("RE - " + ex.getClass());
    }

}

我的服务

package test;

import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    public void throw1() throws DataAccessException {
        throw new MyDataAccessException("test");
    }

    public void throw2()  {
        throw new NullPointerException();
    }

    static class MyDataAccessException extends DataAccessException {

        public MyDataAccessException(String msg) {
            super(msg);
        }

    }
}

在日志中有:

DAE
RE - class test.MyService$MyDataAccessException
RE - class java.lang.NullPointerException

Maven依赖项:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>

从Spring文档中:

当在相同方面定义的两条建议都需要在同一连接点上运行时,其顺序是不确定的(因为无法通过反射来获取javac编译类的声明顺序).考虑将这些建议方法折叠成每个方面类中每个连接点的一个建议方法,或将建议重构为单独的方面类-可以在方面级别进行排序.

When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefined (since there is no way to retrieve the declaration order via reflection for javac-compiled classes). Consider collapsing such advice methods into one advice method per join point in each aspect class, or refactor the pieces of advice into separate aspect classes - which can be ordered at the aspect level.

当我尝试对MyAspect进行以下修改时:

When I tried following modification of MyAspect:

package test;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {

    @AfterThrowing(pointcut = "execution(public * *(..))", throwing = "ex")
    public void intercept(DataAccessException ex) throws Exception {
        //throw DatabaseException
        System.out.println("DAE");
        throw new IllegalArgumentException("DAE"); // added
    }

    @AfterThrowing(pointcut = "execution(public * *(..))", throwing = "ex")
    public void intercept(RuntimeException ex) throws Exception {
        //throw ServiceException
        System.out.println("RE - " + ex.getClass());
        throw new IllegalArgumentException("RE"); // added
    }

}

日志更改为:

DAE
RE - class java.lang.IllegalArgumentException
RE - class java.lang.NullPointerException

,当修改为Exception时,我得到了:

and when modified to Exception I got:

package test;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {

    @AfterThrowing(pointcut = "execution(public * *(..))", throwing = "ex")
    public void intercept(DataAccessException ex) throws Exception {
        //throw DatabaseException
        System.out.println("DAE");
        throw new Exception("DAE2"); // changed
    }

    @AfterThrowing(pointcut = "execution(public * *(..))", throwing = "ex")
    public void intercept(RuntimeException ex) throws Exception {
        //throw ServiceException
        System.out.println("RE - " + ex.getClass());
        throw new Exception("RE2"); // changed
    }

}

日志是

DAE
RE - class java.lang.NullPointerException

我相信,解决您的问题"的方法是拥有两个方面而不是一个方面,并定义顺序:

I believe, that solution to your "problem" is to have two Aspects instead of one and define the ordering:

package test;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DaeAspect implements Ordered {

    public int getOrder() {
        return 200;
    }

    @AfterThrowing(pointcut = "execution(public * *(..))", throwing = "ex")
    public void intercept(DataAccessException ex) throws Exception {
        //throw DatabaseException
        System.out.println("DAE");
        throw new IllegalAccessException("DAE2"); // based on my testing, this stops second aspect to apply
    }

}

package test;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class ReAspect implements Ordered {

    public int getOrder() {
        return 100;
    }

    @AfterThrowing(pointcut = "execution(public * *(..))", throwing = "ex")
    public void intercept(RuntimeException ex) throws Exception {
        //throw ServiceException
        System.out.println("RE - " + ex.getClass());
        throw new IllegalAccessException("RE2");
    }

}

这篇关于@AfterThrowing无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆