Solr,其实是一个webapp,参考网上的文章,我们去看web.xml,查看到 SolrDispatchFilter类,该类的注释:此过滤器查看传入的URL,将其映射到solrconfig.xml中定义的处理程序。既然已经传入URL了,那就是已经启动完成了呗,所以我们要看的并不是这之后的代码,而是之前的启动过程。
Solr其实是一个webapp,Apache官方给出的安装包(http://archive.apache.org/dist/lucene/solr/ )内置了一个jetty容器,这里给出启动过程的调试参数命令:
java -Xdebug -Xrunjdwp:transport=dt_socket,address=10010,server=y,suspend=y -jar start.jar --module=http
再下载Solr的源码配置idea的Remote,即可开始调试。
开始之前,先来了解一下jetty,它是一个sevlet容器,http的客户端,感觉和tomcat不同的是它本身可以以嵌入性的方式集成到自己的应用,用jetty就相当于把http服务塞进了自己的应用,而Solr就是这么做的。所以,我们要理解Solr的启动过程,需要先去看看jetty的启动过程。
参考连接:https://mp.weixin.qq.com/s/OQ24UmRHjoQObs_gpjJ7Ww
重点关注WebAppContext,先来看下WebAppContext主要做了什么,主要的初始化工作是两个方面:
主要的启动逻辑和资源加载逻辑都放在doStart()方法里,所以从dostart()方法开始分析Solr的启动过程。
可以看到当前额context已经是solr-webapp了
这里加载了solr-home/server/lib/ 目录下的jars 以及file:///C:/Solr/solr-6.4.0/server/solr-webapp/webapp/WEB-INF/lib/ 下的jars
然后调用了父类ServlerContextHandler的doStart()方法
关于ServletContextHandler:
是ContextHandler的直接子类,具有ContextHandler的大部分特征,不同的地方是ServletContextHandler中管理了三个Handler:ServletHandler、SessionHandler、SecurityHandler.
它的doStart()方法直接走到了父类(ContextHandler)的doStart() 方法。
Contexthandler是Scopehandler的直接子类,从名字来看是上下文handler,在servlet中每个web应用都有一个上下文。ContextHandler实现了CycelLife和handler接口,重写了doStart() 方法,这里我们直接去看它的doStart()方法
跟进startContext(),因为当前this对象为WebAppContext,所以会进入它的startContext
this.configure() 还是会走到WebInfConfigureation的加载jars逻辑中,resolve 解析元数据,跟进去看了一下,是对一些jar包的处理,应该是加载jar包的操作。
我们直接关注startWebapp,跟进去
well会进入super的starContext,也就是ServletContextHandler,ServletContextHandler就是重写了父类的startContext()方法,将SessionHandler、SecurityHandler、ServletHandler组成一个Handler链来对请求进行处理,并且在startContext()方法中进行了ServletHandler的初始化(remember this)。
我们继续跟进父类的startContext方法。
调用父类方法之前前两个步骤获取的都为null,继续跟进父类的方法
Scopedhandler主要是处理handler链,关键核心在doScope方法中,这里doStart() 也是直接调用了父类的doStart() 方法
AbstrachHandler是大部分handler都继承的父类,AbstractHandler并没有对父类关键方法doStart() doStop() 进行重写,也没有具体实现handler() 方法,唯一重写的就是setServer() 方法,所以还要继续往上跟。
生命周期的管理,进入启动程序:这里会依次启动各个handler
所有的handler(处理程序)都start起来了,再一层一层的返回去,回忆一下,在ServletContextHandler中有一个_servletHandler属性,它会有initalize()方法,这里就是我们的webapp(Solr)启动初始化,加载配置文件入口。
进入ServlerHandler的initialize()方法,动态调试的过程中查看一下它的各个属性再经过了一些列doStart(),startContext() 之后被初始化什么样了,看这样,Solr就是一个Webapp嘛~
这里我们重点关注一下this._filters,在读取web.xml中已经初始化(WebXmlConfiguration预加载解析web.xml),这个filters很重要,我们查看web.xml 定义了这个filter。
Jetty中所有组件都是受LifeCycle管理,首先是启动这个SolrRequestFilter,f.start(),然后进入SolrRequestFilter的初始化方法FilterHolder.initialize(),这里先将FilterHolder转化成SolrDispatchFilter,增加它的Filter属性,贴一张SolrDispatchfilter的类图
转化完成后后新建Config对象,然后进行config的初始化
跟进SolrDispatchFilter的init()方法,注释中标明了大概做了什么
将creatCoreContainer单独拎出来,因为它算是整个init里面很核心的方法,它的返回值初始化了this.cores,cores也就是CoreContainer,CoreContainer单独的分析文章:
它就是盛放core的容器,使用creatCoreContianer方法进行初始化。跟进creatCoreContianer,首先是loadNodeConfig,返回一个NodeConfig对象,NodeConfig也在上面文章中有介绍:每个私有属性都对应着solr.xml定义的字段,我们跟进loadNodeConfig方法
利用SolrResourceLoader 加载solr.xml文件,然后再调用SolrXmlConfig的fromSolrHome方法加载解析loader中存储的solr.xml
此时的调用栈(部分)
fromSolrHome:141, SolrXmlConfig (org.apache.solr.core)
loadNodeConfig:265, SolrDispatchFilter (org.apache.solr.servlet)
createCoreContainer:233, SolrDispatchFilter (org.apache.solr.servlet)
init:167, SolrDispatchFilter (org.apache.solr.servlet)