记录一次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
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())); }