• 记录一次spring cglib代理导致空指针异常


    说明

    很低级的一个错误,本次记录只是加深对spring代理的理解

    现象

    1.同样一个类2个不同的方法一个空指针一个不空指针

        @Resource
        IProviderRegistryService providerRegistryService;
    
        /**
         * providerRegistryService不报空指针方法
         *
         * @return
         */
        @ResponseBody
        @RequestMapping(value = "/api/v1/provider/industry_list", method = RequestMethod.GET)
        public OpenApiResponseEntity providerIndustryList() {
            return successful(providerRegistryService.providerIndustryList());
        }
    
        /**
         * providerRegistryService 报空指针方法
         *
         * @param request
         * @return
         */
        @ResponseBody
        @RequestMapping(value = "/api/v1/provider/submit_info", method = RequestMethod.POST)
        private OpenApiResponseEntity submitProviderInfo(@RequestBody @Validated ProviderSubmitInfoRequest request) {
            return successful(providerRegistryService.submitProviderInfo(
                    request.getProviderId(), request.getEmail(), request.getIndustryIds(),
                    request.getScale(), request.getLaunchPlanned(), request.getLaunchTime(), request.getScene()));
        }

    解决思路

    1.首先我想着是调用2个方法打断点看this是不是同一个

    报空指针的 cglib是继承方式代理所以继承的成员变量是空 是正常的

    不报空指针的

    2.为什么一个是走代理一个没走代理 首先想到是跟spring mvc源码 看HandelMapping看如何获取handle是否是一个获取到代理一个没获取到

    看源码是根据映射的bean name根据容器获取 2个接口都是获取的同一个代理类 那是不是handleAdapter在后面某个时机替换掉了呢

     public HandlerMethod createWithResolvedBean() {
            Object handler = this.bean;
            if (this.bean instanceof String) {
                String beanName = (String)this.bean;
                handler = this.beanFactory.getBean(beanName);
            }
    
            return new HandlerMethod(this, handler);
        }

    3.spring mvc有对象和方法最后是通过反射调用 根据打断点正常的接口走了这样一个类

    org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept

     public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object oldProxy = null;
                boolean setProxyContext = false;
                Class<?> targetClass = null;
                Object target = null;
    
                Object var11;
                try {
                    if (this.advised.exposeProxy) {
                        oldProxy = AopContext.setCurrentProxy(proxy);
                        setProxyContext = true;
                    }
                     //拿到被代理对象,调用
                    target = this.getTarget();
                    if (target != null) {
                        targetClass = target.getClass();
                    }
    
                    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                    Object retVal;
                    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                        retVal = methodProxy.invoke(target, args);
                    } else {
                        retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
                    }
                    //反射调用
                    retVal = CglibAopProxy.processReturnType(proxy, target, method, retVal);
                    var11 = retVal;
                } finally {
                    if (target != null) {
                        this.releaseTarget(target);
                    }
    
                    if (setProxyContext) {
                        AopContext.setCurrentProxy(oldProxy);
                    }
    
                }
    
                return var11;
            }

    4.那为什么不正常的接口没有走呢

    CGLIB是基于类继承代理 而不正常的方法定义是私有的

    那是否有疑问既然是继承 私有方法又不能继承 如何可以正常执行, 因为spring mvc用的是反射调用.反射是可以调用父类私有方法的,但是this是代理类 代理类的成员变量都是null

    @ResponseBody
        @RequestMapping(value = "/api/v1/provider/submit_info", method = RequestMethod.POST)
        private OpenApiResponseEntity submitProviderInfo(@RequestBody @Validated ProviderSubmitInfoRequest request) {
            return successful(providerRegistryService.submitProviderInfo(
                    request.getProviderId(), request.getEmail(), request.getIndustryIds(),
                    request.getScale(), request.getLaunchPlanned(), request.getLaunchTime(), request.getScene()));
        }
  • 相关阅读:
    Eclipse快捷键大全(转载)
    IE9浏览Flash页面时显示错位并不停地闪烁
    flash全屏事件和键盘按下事件部分不能触发问题
    AS3摘要(转载)
    【as3手册小记】ActionScript 中处理全屏模式的注意事项
    巧用FlashPaper 让Word文档变Flash
    AS3视频照相截图(转载)
    Json串到json对象的转换
    映射文件详解(转)
    Jquery .ajax方法分析(一)
  • 原文地址:https://www.cnblogs.com/LQBlog/p/16243239.html
Copyright © 2020-2023  润新知