首页 > 编程语言 >Spring源码(13)--AOP 连接点及通知的方法调用的源码

Spring源码(13)--AOP 连接点及通知的方法调用的源码

时间:2024-10-04 11:12:46浏览次数:10  
标签:web 13 catalina -- Object springframework 源码 apache org

AOP基础知识

AOP基础知识,详情见: https://blog.csdn.net/sinat_32502451/article/details/142291052

AOP 源码,详情见: https://blog.csdn.net/sinat_32502451/article/details/142291110

ProceedingJoinPoint

在上面的示例中,运用到了 ProceedingJoinPoint 。

ProceedingJoinPoint 是继承 JoinPoint(连接点) 的类。
从以上示例代码看出, ProceedingJoinPoint拥有 JoinPoint(连接点)的特性,
可以获取类的信息,包括类名、方法名、参数等(joinPoint.getArgs()),
还可以执行目标对象方法的逻辑(joinPoint.proceed())。

代码: org.aspectj.lang.ProceedingJoinPoint

/**
 *   ProceedingJoinPoint 继承 JoinPoint(连接点) .
 *   ProceedingJoinPoint 公开了progress(..)方法,以支持@AJ aspects.
 *
 */
public interface ProceedingJoinPoint extends JoinPoint {

    /**
     *  joinpoint需要知道它的AroundClosure,以便proceed可以委托给closure.run()
     * 
     */
    void set$AroundClosure(AroundClosure arc);

    /**
     * 继续下一个advice或目标方法调用
     *
     */
    public Object proceed() throws Throwable;

    /**
     * 继续下一个advice或目标方法调用
     *
     */
    public Object proceed(Object[] args) throws Throwable;

}

ReflectiveMethodInvocation的proceed

不管是 @Pointcut 还是 @Around(环绕通知,包含前置和后置两个) 都会调用这个 proceed 方法。

代码: org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

    @Override
    @Nullable
    public Object proceed() throws Throwable {

        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
          //以下会调用 Joinpoint(连接点) 
          // 通过 invokeJoinpoint 的调用, 可以拿到目标方法的返回值。 
          
          //注意: 这里的 invokeJoinpoint() 调用的是 
          // org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#invokeJoinpoint
          //并不是自身的 invokeJoinpoint()方法。
            return invokeJoinpoint();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                return proceed();
            }
        }
        else {
            // 拦截器调用方法。@Around 环绕通知的前置和后置都会走这里
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

CglibAopProxy.CglibMethodInvocation

调用 joinPoint.proceed(); 这一行代码后,最后会调用这里的 Cglib 动态代理。

Cglib 动态代理,调用连接点的方法。

通过 invokeJoinpoint 的调用, 可以拿到目标方法的返回值。

代码: org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation#invokeJoinpoint

    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

        private final MethodProxy methodProxy;

        private final boolean publicMethod;

        public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
                Object[] arguments, @Nullable Class<?> targetClass,
                List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

            super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
            this.methodProxy = methodProxy;
            this.publicMethod = Modifier.isPublic(method.getModifiers());
        }

        /**
         * 调用 JoinPoint(连接点) 的方法
         */
        @Override
        protected Object invokeJoinpoint() throws Throwable {
            if (this.publicMethod) {
                // 通过这里的调用, 可以拿到目标方法的返回值。
                return this.methodProxy.invoke(this.target, this.arguments);
            }
            else {
                return super.invokeJoinpoint();
            }
        }
    }

CglibAopProxy.DynamicAdvisedInterceptor

代码: org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor

调用 JoinPoint(连接点) 的方法后,会进行后置通知,调用 CglibAopProxy.DynamicAdvisedInterceptor。

    /**
     * 通用AOP回调。当目标是动态的或代理未冻结时使用。
     *
     */
    private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {

        private final AdvisedSupport advised;

        public DynamicAdvisedInterceptor(AdvisedSupport advised) {
            this.advised = advised;
        }

        @Override
        @Nullable
        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            Object target = null;
            TargetSource targetSource = this.advised.getTargetSource();
            try {
                if (this.advised.exposeProxy) {
                   
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }
                target = targetSource.getTarget();
                Class<?> targetClass = (target != null ? target.getClass() : null);
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                Object retVal;
                // 这里面的逻辑,重点看看。
                // 检查是否没有真正的advice,只是对目标的反射调用。
                if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                    // 我们可以跳过创建 MethodInvocation:直接调用目标。
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    retVal = methodProxy.invoke(target, argsToUse);
                }
                else {
                    // 创建一个方法调用。
                    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                }
                retVal = processReturnType(proxy, target, method, retVal);
                return retVal;
            }
            finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }
                if (setProxyContext) {
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }

调用的方法栈:

这些代码也可以看看。

processReturnType:394, CglibAopProxy (org.springframework.aop.framework)
access$000:84, CglibAopProxy (org.springframework.aop.framework)
intercept:690, CglibAopProxy$DynamicAdvisedInterceptor (org.springframework.aop.framework)
getValue:-1, TestController$$EnhancerBySpringCGLIB$$682df634 (com.example.demo.controller)
invoke:-1, GeneratedMethodAccessor68 (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
doInvoke:209, InvocableHandlerMethod (org.springframework.web.method.support)
invokeForRequest:136, InvocableHandlerMethod (org.springframework.web.method.support)
invokeAndHandle:102, ServletInvocableHandlerMethod (org.springframework.web.servlet.mvc.method.annotation)
invokeHandlerMethod:891, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
handleInternal:797, RequestMappingHandlerAdapter (org.springframework.web.servlet.mvc.method.annotation)
handle:87, AbstractHandlerMethodAdapter (org.springframework.web.servlet.mvc.method)
doDispatch:991, DispatcherServlet (org.springframework.web.servlet)
doService:925, DispatcherServlet (org.springframework.web.servlet)
processRequest:974, FrameworkServlet (org.springframework.web.servlet)
doGet:866, FrameworkServlet (org.springframework.web.servlet)
service:635, HttpServlet (javax.servlet.http)
service:851, FrameworkServlet (org.springframework.web.servlet)
service:742, HttpServlet (javax.servlet.http)
internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:52, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:99, RequestContextFilter (org.springframework.web.filter)
doFilter:107, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:109, HttpPutFormContentFilter (org.springframework.web.filter)
doFilter:107, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:93, HiddenHttpMethodFilter (org.springframework.web.filter)
doFilter:107, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:200, CharacterEncodingFilter (org.springframework.web.filter)
doFilter:107, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
invoke:198, StandardWrapperValve (org.apache.catalina.core)
invoke:96, StandardContextValve (org.apache.catalina.core)
invoke:493, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:140, StandardHostValve (org.apache.catalina.core)
invoke:81, ErrorReportValve (org.apache.catalina.valves)
invoke:87, StandardEngineValve (org.apache.catalina.core)
service:342, CoyoteAdapter (org.apache.catalina.connector)
service:800, Http11Processor (org.apache.coyote.http11)
process:66, AbstractProcessorLight (org.apache.coyote)
process:806, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1498, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1142, ThreadPoolExecutor (java.util.concurrent)
run:617, ThreadPoolExecutor$Worker (java.util.concurrent)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:745, Thread (java.lang)

标签:web,13,catalina,--,Object,springframework,源码,apache,org
From: https://www.cnblogs.com/expiator/p/18446433

相关文章

  • Jdk动态代理源码
    Proxy代码:java.lang.reflect.ProxyProxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。构造一个新的Proxy实例,并指定调用处理器InvocationHandler。protectedProxy(InvocationHandlerh){Objects.requireNonNull(h);......
  • Spring源码(14) -- Aop动态代理CglibAopProxy
    AOP基础知识AOP基础知识,详情见:https://blog.csdn.net/sinat_32502451/article/details/142291052AOP源码,详情见:https://blog.csdn.net/sinat_32502451/article/details/142291110AopProxyAopProxy接口是配置的AOP代理的委托接口,允许创建实际的代理对象。开箱即用的实现可......
  • Spring源码(15) -- Aop动态代理之 Enhancer
    Enhancer用途Enhancer(增强器)是标准Jdk动态代理的替代品,用于生成动态子类以启用方法拦截,还允许代理扩展具体的基类。原始且最通用的回调类型是MethodInterceptor(方法拦截器)。通常,每个Enhancer都会使用一个Callback回调,但可以使用callbackFilter控制每个方法使用哪......
  • [题解]SFMOI Round I A~C
    Portal:https://www.luogu.com.cn/contest/179008\(\bf{100+50+50+25+5=\color{indianred}225\color{black}\,\rk.\184}\)A-StrangeCakeGame显然对于小W,向下移动蛋糕刀是最有利的;对于小M,向右移动是最有利的。所以双方以最佳状态移动,最终\(x\ley\)的巧克力是小W的。直接......
  • Vue3的项目搭建
    有两种方式可以搭建:一:使用vue-cli中的webpack创建 第二:推荐使用vite来创建项目vite是新一代前端构建工具,新的前端构建工具,比webpack要快一些。npmcreatevue@latest创建完项目后,我们可以看到项目最外层有index.htmlVite项目中,index.html是项目的入口文件,在项目最外层。......
  • 完全私有化部署!一款开源轻量级网站防火墙!
    大家好,我是Java陈序员。今天,给大家介绍一款开源轻量级网站防火墙!关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。项目介绍SamWaf——是一款适用于小公司、工作室和个人网站的开源轻量级网站防火墙,完全私有化部署,数据加密且仅......
  • qwq
    呃呃呃这是赛时自以为AK(实际可能四个题全假)后挂着拍子没事干随便写点。呃呃呃正序开题,t1只会暴力dp啊,很不牛。看t2,哦好典,我会了。看t3,哦数论,不会了。写掉t2,发现题面写了坨什么玩意,发了一堆提问没人回。回去看t1,哦哦哦原来数据范围还可以这么写啊,会了然后写了,此时差不多......
  • 11-网络物理隔离技术原理与应用
    11.1概述1)概念目的:既能满足内外网信息及数据交换需求,又能防止网络安全事件出现基本原理:避免两台计算机之间直接的信息交换以及物理上的连通,以阻断两台计算机之间的直接在线网络攻击2)风险网络非法外联U盘摆渡攻击网络物理隔离产品安全隐患针对物理隔离的攻击新方法利用......
  • 华为OD机试真题---整数对最小和
    题目描述给定两个整数数组array1和array2,数组元素按升序排列。假设从array1和array2中分别取出一个元素可构成一对元素。现在需要取出K个元素对(即从两个数组中各取一个元素组成一个对,共取K个这样的对),并对取出的所有元素求和,计算和的最小值。注意:两对元素如果对应于array1和......
  • 华为OD机试真题---第k个排列
    针对华为OD机试真题中的“第k个排列”问题,以下是对题目的详细解析及解答方法:题目描述给定参数n,从1到n会有n个整数:1,2,3,…,n。这n个数字共有n!种排列。按大小顺序升序列出所有排列的情况,并一一标记。给定n和k,返回第k个排列。输入与输出输入:第一行为n,给定n的范围是......