1、获取拦截方法的返回值和抛的异常信息
获取方法返回的值分为两个步骤:
1、在返回值通知的方法中,追加一个参数 Object result
2、然后在@AfterReturning注解中添加参数returning=“参数名”
获取方法抛出的异常分为两个步骤:
1、在异常通知的方法中,追加一个参数Exception exception
2、然后在@AfterThrowing 注解中添加参数 throwing=“参数名”
修改LogUtil切面类的代码
@AfterReturning(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))"+ " || " + "execution(public * com.atguigu.aop.Calculator.d*(..))", returning = "result")public static void logAfterReturn(JoinPoint joinPoint, Object result) {System.out.println("返回之后: 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"+ Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);}@AfterThrowing(value = "execution(public int com.atguigu.aop.Calculator.add(int, int))"+ " || " + "execution(public * com.atguigu.aop.Calculator.d*(..))", throwing = "exception")public static void logThrowException(JoinPoint joinPoint, Exception exception) {System.out.println("抛异常:日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"+ Arrays.asList(joinPoint.getArgs()) + ",异常对象:" + exception);}
测试结果
2、Spring的环绕通知
1、环绕通知使用@Around注解。
2、环绕通知如果和其他通知同时执行。环绕通知会优先于其他通知之前执行。
3、环绕通知一定要有返回值(环绕如果没有返回值。后面的其他通知就无法接收到目标方法执行的结果)。
4、在环绕通知中。如果拦截异常。一定要往外抛。否则其他的异常通知是无法捕获到异常的。
在LogUtil切面类中添加环绕通知
@Around(value = "execution(* *(..))")public static Object logAround(ProceedingJoinPoint proceedingJoinPoint) {//获取请求参数Object[] args = proceedingJoinPoint.getArgs();Object resultObject = null;try {System.out.println("环绕前置");//调用目标方法resultObject = proceedingJoinPoint.proceed(args);System.out.println("环绕后置");} catch (Throwable e) {System.out.println("环绕异常:" + e);throw new RuntimeException(e);} finally {System.out.println("环绕返回后");}//返回返回值return resultObject;}
修改测试的代码
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {@Autowiredprivate Calculator calculator;@Testpublic void test1() {//加法calculator.add(1, 2);}
}
执行结果
3、切入点表达式的重用
切入点表达式的重点,需要分三个步骤:
1、在切面类中定义一个空的方法
public static void pointcut1() {}
2、在方法中使用@Pointcut定义一个切入连表达式
@Pointcut(value="execution(public int com.atguigu.aop.Calculator.add(int, int))" + " || "+ "execution(public * com.atguigu.aop.Calculator.*(..))")public static void pointcut1() {}
3、其他的通知注解中使用方法名()的形式引用方法上定义的切入点表达式。
比如:@Before("pointcut1()")
4、多个通知的执行顺序
当有多个切面,多个通知的时候:
1、通知的执行顺序默认是由切面类的字母先后顺序决定。
2、在切面类上使用@Order注解决定通知执行的顺序(值越小,越先执行)
再添加另一个切面类
@Component
@Aspect
@Order(1)
public class Validation {@Before(value = "com.atguigu.aop.LogUtil.pointcut1()")public static void before(JoinPoint joinPoint) {System.out.println("这是Validation的前置通知,拦截的方法是:" + joinPoint.getSignature().getName());}@After(value = "com.atguigu.aop.LogUtil.pointcut1()")public static void after(JoinPoint joinPoint) {System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName());}@AfterReturning(value = "com.atguigu.aop.LogUtil.pointcut1()", returning = "result")public static void afterReturning(JoinPoint joinPoint, Object result) {System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName()+ ", 返回值:" + result);}}
修改原来LogUtil中的切面内容(去掉环绕通知,留下前置,后置,返回后通知)
@Aspect
@Component
@Order(2)
public class LogUtil {@Pointcut(value="execution(public int com.atguigu.aop.Calculator.add(int, int))" + " || "+ "execution(public * com.atguigu.aop.Calculator.*(..))")public static void pointcut1() {}
测试的代码
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {@Autowiredprivate Calculator calculator;@Testpublic void test1() {//加法calculator.add(1, 0);}
}
运行的结果
5、如何基于xml配置aop程序
需要导入的包
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.3.jar
log4j-1.2.17.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-test-4.0.0.RELEASE.jar
工程中编写的类
public class Calculator {public int div(int num1, int num2) {return num1 / num2;}public int add(int num1, int num2) {return num1 + num2;}
}
LogUtil切面类
public class LogUtil {public static void logBefore(JoinPoint joinPoint) {System.out.println("前置 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用前 。参数是:"+ Arrays.asList(joinPoint.getArgs()));}public static void logAfter(JoinPoint joinPoint) {System.out.println("后置 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"+ Arrays.asList(joinPoint.getArgs()));}public static void logAfterReturn(JoinPoint joinPoint, Object result) {System.out.println("返回之后: 日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"+ Arrays.asList(joinPoint.getArgs()) + ",返回值:" + result);}public static void logThrowException(JoinPoint joinPoint, Exception exception) {System.out.println("抛异常:日记 :【" + joinPoint.getSignature().getName() + "】 方法调用 。参数是:"+ Arrays.asList(joinPoint.getArgs()) + ",异常对象:" + exception);}
}
Validation切面类
public class Validation {public static void before(JoinPoint joinPoint) {System.out.println("这是Validation的前置通知,拦截的方法是:" + joinPoint.getSignature().getName());}public static void after(JoinPoint joinPoint) {System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName());}public static void afterReturning(JoinPoint joinPoint, Object result) {System.out.println("这是Validation的后置通知,拦截的方法是:" + joinPoint.getSignature().getName()+ ", 返回值:" + result);}
}
ApplicationContext.xml配置文件中的内容
<!-- 注册bean对象添加@Component--><bean id="calculator" class="com.atguigu.aop.Calculator" /><bean id="logUtil" class="com.atguigu.aop.LogUtil" /><bean id="validation" class="com.atguigu.aop.Validation" /><!-- 配置AOP --><aop:config><!-- 定义可以共用的切入点 --><aop:pointcut expression="execution(* com.atguigu.aop.Calculator.*(..))" id="pointcut1"/><!-- 定义切面类 --><aop:aspect order="1" ref="logUtil"><!-- 这是前置通知 method属性配置通知的方法pointcut配置切入点表达式--><aop:before method="logBefore" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/><aop:after method="logAfter" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/><aop:after-returning method="logAfterReturn" returning="result" pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/><aop:after-throwing method="logThrowException" throwing="exception"pointcut="execution(* com.atguigu.aop.Calculator.*(..))"/></aop:aspect><!-- 定义切面类 --><aop:aspect order="2" ref="validation"><aop:before method="before" pointcut-ref="pointcut1"/><aop:after method="after" pointcut-ref="pointcut1"/><aop:after-returning method="afterReturning" returning="result" pointcut-ref="pointcut1"/></aop:aspect></aop:config>
测试的代码
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringAopTest {@AutowiredCalculator calculator;@Testpublic void test1() {calculator.add(1, 2);}
}