程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-06(3)

第6章:JavaSpring中AOP的技术点详解

发布于2021-06-12 15:06     阅读(185)     评论(0)     点赞(16)     收藏(3)


       本文书接上文《第5章:JavaSpringAOP的使用》内容,解释与补充Spring框架中的切片关键字,并对Arround关键字的使用进行补充。

1. 注解关键字

       对于上文中使用的Before、After、AfterReturning、AfterThrowing四个关键字对比《第4章:Java中代理模式的实现》大致就可以看到其实现的地方了。为了方便各位看官,可以直接查看下述代码实现。

public static ICalculator getCalculator(final ICalculator calculator){
    //获取被代理对象的类加载器
    ClassLoader loader =calculator.getClass().getClassLoader();
    //被代理对象的所有接口
    Class<?>[] interfaces=calculator.getClass().getInterfaces();
    //用来执行被代理类所需要执行的方法
    InvocationHandler hander=new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = 0;
            try {

                //Before
                LogUtil.start(method, args);

                result=method.invoke(args);

                //After
                LogUtil.stop(method, result);

            } catch (Exception e) {

                //AfterThrowing
                LogUtil.logException(method, e);

            } finally {

                //AfterReturning
                LogUtil.logFinally(method);

            }
            return result;
        }
    };
    Object objReturn= Proxy.newProxyInstance(loader,interfaces,hander);
    return (ICalculator)objReturn;
}

1.1. 通知的执行顺序

  • 正常情况下:@Before->@After->@AfterReturning

  • 异常情况下:@Before->@After->@AfterThrowing

1.2. 获取切片参数信息

  • 则需要在函数中使用JoinPoint对象进行获取

    @Before(value="myPointCur()")
    public void start(JoinPoint pjp){
    }
  • 需要使用其他参数信息进行补充

    @AfterThrowing(value="myPointCur()",throwing = "e")
    public void logException(JoinPoint joinPoint,Exception e){
    }

2.环绕通知

       环绕的意思就是将需要切片的内容进行‘包装’,在需要切片的函数上下文中再进行业务逻辑封装

  • 环绕通知再执行的时候式优于普通通知的

  • 如果环绕通知正常结束,那么执行顺序为:

环绕前置通知->@Before->环绕后置通知->环绕返回通知->@After->@AfterReturning

  • 如果环绕通知异常结束,那么执行顺序为:

环绕前置通知->@Before->环绕异常通知->环绕返回通知->@After->@AfterReturn

  • 如果出现异常的时候,在环绕通知中解决了,那么普通通知时接受不到的,如果想让普通通知接收到需要在环绕通知中throw。

上述中废话说了很多我们接着在代码中实现@Around环绕通知

@Pointcut("execution(* calc.MyCalculator.*(..))")
public void myPointCur(){}

@Around(value = "myPointCur()")
public Object around(ProceedingJoinPoint pjp) {
    Signature signature = pjp.getSignature();
    Object[] args = pjp.getArgs();
    Object result = null;
    try {
        System.out.println(String.format("环绕通知Start:%s方法开始执行,参数为:%s", signature.getName(),Arrays.asList(args)));
        result = pjp.proceed(args);
        System.out.println(String.format("环绕通知Start:%s方法结束执行", signature.getName()));
    } catch (Throwable throwable) {
        throwable.printStackTrace();
        System.out.println(String.format("环绕通知Start:%s方法结束异常:%s", signature.getName(),throwable.getMessage()));
    }
    return result;
}
MyCalculator初始化
环绕通知Start:add方法开始执行,参数为:[10, 10]
函数[add]开始执行,参数为:[10, 10]
函数[add]开始完毕,返回值为:Integer calc.ICalculator.add(Integer,Integer)
函数[add]开始完毕
环绕通知Start:add方法结束执行
20
环绕通知Start:sub方法开始执行,参数为:[10, 10]
函数[sub]开始执行,参数为:[10, 10]
函数[sub]开始完毕,返回值为:Integer calc.ICalculator.sub(Integer,Integer)
函数[sub]开始完毕
环绕通知Start:sub方法结束执行
0
环绕通知Start:mul方法开始执行,参数为:[10, 10]
函数[mul]开始执行,参数为:[10, 10]
函数[mul]开始完毕,返回值为:Integer calc.ICalculator.mul(Integer,Integer)
函数[mul]开始完毕
环绕通知Start:mul方法结束执行
100
环绕通知Start:div方法开始执行,参数为:[10, 10]
函数[div]开始执行,参数为:[10, 10]
函数[div]开始完毕,返回值为:Integer calc.ICalculator.div(Integer,Integer)
函数[div]开始完毕
环绕通知Start:div方法结束执行
1
环绕通知Start:div方法开始执行,参数为:[10, 0]
函数[div]开始执行,参数为:[10, 0]
函数[div]执行异常,异常信息为:div
函数[div]开始完毕
环绕通知Start:div方法结束异常:/ by zero
null
java.lang.ArithmeticException: / by zero
	at calc.MyCalculator.div(MyCalculator.java:43)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:49)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:102)
	at calc.LogUtilAspect.around(LogUtilAspect.java:72)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
	at com.sun.proxy.$Proxy18.div(Unknown Source)
	at SpringAspectDemoMain.main(SpringAspectDemoMain.java:36)

3.切片嵌套切片

当有多个切片需要嵌套使用时,同时要控制顺序时,可以在切面上使用@Order来进行指定

package calc;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * @Classname LogUtilAspect
 * @Description 日志Spring切片
 * @Date 2021/6/2 18:20
 * @Created by xiaocai
 */
@Aspect
@Component
@Order(0)
public class LogUtilAspect {

    @Pointcut("execution(* calc.MyCalculator.*(..))")
    public void myPointCur(){}

    /**
     * 函数开始执行信息
     * @param method
     * @param pars
     */
    @Before(value="myPointCur()")
    public void start(JoinPoint pjp){
        System.out.println(String.format("函数[%s]开始执行,参数为:%s",pjp.getSignature().getName(), Arrays.asList(pjp.getArgs())));
    }

    /**
     * 函数结束执行信息
     * @param method
     * @param pars
     */
    @AfterReturning(value="myPointCur()")
    public void stop(JoinPoint pjp){
        System.out.println(String.format("函数[%s]开始完毕,返回值为:%s",pjp.getSignature().getName(),pjp.getSignature()));
    }

    /**
     * 函数异常信息
     * @param method
     * @param pars
     */
    @AfterThrowing(value="myPointCur()",throwing = "e")
    public void logException(JoinPoint joinPoint,Exception e){
        System.out.println(String.format("函数[%s]执行异常,异常信息为:%s",joinPoint.getSignature().getName(),joinPoint.getSignature().getName()));
    }

    /**
     * 函数完毕信息
     * @param method
     * @param pars
     */
    @After(value="myPointCur()")
    public  void logFinally(JoinPoint pjp){
        System.out.println(String.format("函数[%s]开始完毕",pjp.getSignature().getName()));
    }

//    @Around(value = "myPointCur()")
    public Object around(ProceedingJoinPoint pjp) {
        Signature signature = pjp.getSignature();
        Object[] args = pjp.getArgs();
        Object result = null;
        try {
            System.out.println(String.format("环绕通知Start:%s方法开始执行,参数为:%s", signature.getName(),Arrays.asList(args)));
            result = pjp.proceed(args);
            System.out.println(String.format("环绕通知Start:%s方法结束执行", signature.getName()));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println(String.format("环绕通知Start:%s方法结束异常:%s", signature.getName(),throwable.getMessage()));
        }
        return result;
    }
}

//

package calc;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @Classname LogUtilAspect
 * @Description 日志Spring切片
 * @Date 2021/6/2 18:20
 * @Created by xiaocai
 */
@Aspect
@Component
@Order(1)
public class LogUtilAspect01 {

    @Pointcut("execution(* calc.MyCalculator.*(..))")
    public void myPointCur(){}

    /**
     * 函数开始执行信息
     * @param method
     * @param pars
     */
    @Before(value="myPointCur()")
    public void start(JoinPoint pjp){
        System.out.println(String.format("后置切片:函数[%s]开始执行,参数为:%s",pjp.getSignature().getName(), Arrays.asList(pjp.getArgs())));
    }

    /**
     * 函数结束执行信息
     * @param method
     * @param pars
     */
    @AfterReturning(value="myPointCur()")
    public void stop(JoinPoint pjp){
        System.out.println(String.format("后置切片:函数[%s]开始完毕,返回值为:%s",pjp.getSignature().getName(),pjp.getSignature()));
    }

    /**
     * 函数异常信息
     * @param method
     * @param pars
     */
    @AfterThrowing(value="myPointCur()",throwing = "e")
    public void logException(JoinPoint joinPoint,Exception e){
        System.out.println(String.format("后置切片:函数[%s]执行异常,异常信息为:%s",joinPoint.getSignature().getName(),joinPoint.getSignature().getName()));
    }

    /**
     * 函数完毕信息
     * @param method
     * @param pars
     */
    @After(value="myPointCur()")
    public  void logFinally(JoinPoint pjp){
        System.out.println(String.format("后置切片:函数[%s]开始完毕",pjp.getSignature().getName()));
    }

//    @Around(value = "myPointCur()")
    public Object around(ProceedingJoinPoint pjp) {
        Signature signature = pjp.getSignature();
        Object[] args = pjp.getArgs();
        Object result = null;
        try {
            System.out.println(String.format("后置切片:环绕通知Start:%s方法开始执行,参数为:%s", signature.getName(),Arrays.asList(args)));
            result = pjp.proceed(args);
            System.out.println(String.format("后置切片:环绕通知Start:%s方法结束执行", signature.getName()));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println(String.format("后置切片:环绕通知Start:%s方法结束异常:%s", signature.getName(),throwable.getMessage()));
        }
        return result;
    }
}

MyCalculator初始化
函数[add]开始执行,参数为:[10, 10]
后置切片:函数[add]开始执行,参数为:[10, 10]
后置切片:函数[add]开始完毕,返回值为:Integer calc.ICalculator.add(Integer,Integer)
后置切片:函数[add]开始完毕
函数[add]开始完毕,返回值为:Integer calc.ICalculator.add(Integer,Integer)
函数[add]开始完毕
20
函数[sub]开始执行,参数为:[10, 10]
后置切片:函数[sub]开始执行,参数为:[10, 10]
后置切片:函数[sub]开始完毕,返回值为:Integer calc.ICalculator.sub(Integer,Integer)
后置切片:函数[sub]开始完毕
函数[sub]开始完毕,返回值为:Integer calc.ICalculator.sub(Integer,Integer)
函数[sub]开始完毕
0
函数[mul]开始执行,参数为:[10, 10]
后置切片:函数[mul]开始执行,参数为:[10, 10]
后置切片:函数[mul]开始完毕,返回值为:Integer calc.ICalculator.mul(Integer,Integer)
后置切片:函数[mul]开始完毕
函数[mul]开始完毕,返回值为:Integer calc.ICalculator.mul(Integer,Integer)
函数[mul]开始完毕
100
函数[div]开始执行,参数为:[10, 10]
后置切片:函数[div]开始执行,参数为:[10, 10]
后置切片:函数[div]开始完毕,返回值为:Integer calc.ICalculator.div(Integer,Integer)
后置切片:函数[div]开始完毕
函数[div]开始完毕,返回值为:Integer calc.ICalculator.div(Integer,Integer)
函数[div]开始完毕
1
函数[div]开始执行,参数为:[10, 0]
后置切片:函数[div]开始执行,参数为:[10, 0]
后置切片:函数[div]执行异常,异常信息为:div
后置切片:函数[div]开始完毕
函数[div]执行异常,异常信息为:div
函数[div]开始完毕
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at calc.MyCalculator.div(MyCalculator.java:43)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:49)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:49)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
	at com.sun.proxy.$Proxy18.div(Unknown Source)
	at SpringAspectDemoMain.main(SpringAspectDemoMain.java:36)
Disconnected from the target VM, address: '127.0.0.1:50169', transport: 'socket'

Process finished with exit code 1

原文链接:https://blog.csdn.net/a13407142317/article/details/117689292



所属网站分类: 技术文章 > 博客

作者:java之恋

链接:http://www.javaheidong.com/blog/article/222524/e2cfa8fa259fc7229255/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

16 0
收藏该文
已收藏

评论内容:(最多支持255个字符)