记录一次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;
//判断方法是不是公共方法 是的话直接使用target去调用
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()));
    }

 

posted @   意犹未尽  阅读(789)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
历史上的今天:
2016-05-07 java陷阱之spring事物未提交和回滚导致不可预知问题
点击右上角即可分享
微信分享提示