分析笔记(二):RESTEASY-828 Issue with injected ServletContext in Resteasy/SpringMVC setup
尝试自己注入httpServlet
至ResteasyContext
。
ResteasyContext
的设计:
ResteasyContext
在resteasy
当中的使用位置:
在对resteasy-spring
模块的分析完成之后,发现没有地方通过ResteasyContext
保存servletContext
。
写一个MyServletRequestListener
:
它实现了javax.servlet.ServletRequestListener
接口:
使用「debug」模式启动服务:
在「IntelliJ」里面加载项目,分析启动过程,第一次启动的时候,会触发ResteasyDeploymentImpl
的start()
方法:
这个逻辑定义在resteasy-spring
提供的springmvc-resteasy.xml
里面:
ResteasyDeploymentImpl
初始化完成后,接着初始化依赖ResteasyDeploymentImpl
的SpringBeanProcessor
:
上面是初始化过程。总结一下,springmvc-resteasy.xml
里面定义的几个「bean」如下:
ResteasyDeployment
Dispatcher
Registry
ProviderFactory
此外,注意到Dispatcher
,Registry
,ProviderFactory
。最后,SpringBeanProcess
在初始化过程使用ResteasyDeploymentImpl
(是ResteasyDeployment
的接口实现)。
下面是SpringBeanProcessor
的初始化过程截图:
查看上面断点停下来时候的「stacktrace」,看到几个beans对应的实际instances:
如上面截图所示,分别是:
ResteasyDeploymentImpl
ResourceMethodRegistry
SynchronousDispatcher
ResteasyProviderFactoryImpl
综合上面的分析,相关的classes组成如下:
接下来继续分析服务的启动过程:SpringBeanProcessor
和相关的beans初始化完成后,就要处理用户的请求,此时走的是ResteasyHandlerAdapter
的handle()
方法:
上面这个handle()
方法,是用户每次请求都要执行的,是处理请求的入口。
继续往下执行,注意因为这是第一次启动,虽然MyServletRequestListener
工作了,但是注入servletContext
失败:
初步分析,是因为第一次访问的时候,springmvc-resteasy.xml
的加载是「lazily initialized」的,所以里面的ResteasyDeploymentImpl
和其它组件都是会在「第一次启动」执行,而后续访问都是直接走,所以应该在MyServletRequestListener
的执行次序方面有一些冲突。
后续可以通过多次访问来验证这点:
可以看到后续的访问都不再报错了。而且只走ResteasyHandlerAdapter
的handle()
方法:
以上是对问题的分析记录,有了上面的基础,后续的工作是给出解决方案。