用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究。但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机制弄熟,才能把这个项目做好。今天分享的就是:Solr是如何启动并且初始化的。大家知道,部署solr时,分两部分:一、solr的配置文件。二、solr相关的程序、插件、依赖lucene相关的jar包、日志方面的jar。因此,在研究solr也可以顺着这个思路:加载配置文件、初始化各个core、初始化各个core中的requesthandler…

  研究solr的启动,首先从solr war程序的web.xml分析开始,下面是solr的web.xml片段:

  1. <web-app xmlns="http://java.sun.com/xml/ns/javaee"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  4. version="2.5"
  5. metadata-complete="true"
  6. >
  7.  
  8.  
  9. <!-- Uncomment if you are trying to use a Resin version before 3.0.19.
  10. Their XML implementation isn\'t entirely compatible with Xerces.
  11. Below are the implementations to use with Sun\'s JVM.
  12. <system-property javax.xml.xpath.XPathFactory=
  13. "com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl"/>
  14. <system-property javax.xml.parsers.DocumentBuilderFactory=
  15. "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"/>
  16. <system-property javax.xml.parsers.SAXParserFactory=
  17. "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"/>
  18. -->
  19.  
  20. <!-- People who want to hardcode their "Solr Home" directly into the
  21. WAR File can set the JNDI property here...
  22. -->
  23. <!-- Solr配置文件的参数,用于Solr初始化使用 -->
  24. <env-entry>
  25. <env-entry-name>solr/home</env-entry-name>
  26. <env-entry-value>R:/solrhome1/solr</env-entry-value>
  27. <env-entry-type>java.lang.String</env-entry-type>
  28. </env-entry>
  29.  
  30. <!-- org.apache.solr.servlet.SolrDispatchFilter Solr启动最重要的东东,所以针对solr源码分析,要对这个Filter开始,它主要的作用:加载solr配置文件、初始化各个core、初始化各个requestHandler和component -->
  31. <filter>
  32. <filter-name>SolrRequestFilter</filter-name>
  33. <filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class>
  34. <!-- If you are wiring Solr into a larger web application which controls
  35. the web context root, you will probably want to mount Solr under
  36. a path prefix (app.war with /app/solr mounted into it, for example).
  37. You will need to put this prefix in front of the SolrDispatchFilter
  38. url-pattern mapping too (/solr/*), and also on any paths for
  39. legacy Solr servlet mappings you may be using.
  40. For the Admin UI to work properly in a path-prefixed configuration,
  41. the admin folder containing the resources needs to be under the app context root
  42. named to match the path-prefix. For example:
  43.  
  44. .war
  45. xxx
  46. js
  47. main.js
  48. -->
  49. <!--
  50. <init-param>
  51. <param-name>path-prefix</param-name>
  52. <param-value>/xxx</param-value>
  53. </init-param>
  54. -->
  55. </filter>

  SolrDispatchFilter 是继承BaseSolrFilter的一个Filter(Filter的作用是啥,大家应该清楚吧,一般web框架级别的产品源码分析都是从filter或者servlet开始)。在介绍SolrDispatchFilter之前,先介绍一下BaseSolrFilter(也许程序员都有刨根问底的习惯)。BaseSolrFilter,是一个实现Filter接口的抽象类,功能很简单,就是判断当前程序是否已经加载日志方面的jar。代码片段如下:

  

  1. /**
  2. * All Solr filters available to the user\'s webapp should
  3. * extend this class and not just implement {@link Filter}.
  4. * This class ensures that the logging configuration is correct
  5. * before any Solr specific code is executed.
  6. */
  7. abstract class BaseSolrFilter implements Filter {
  8. static {//
  9. CheckLoggingConfiguration.check();
  10. }
  11. }

  着于篇幅,我就不介绍CheckLoggingConfiguration.check() 这里面的东东了。OK,我们回到SolrDispatchFilter上。由于BaseSolrFilter是一个抽象类,所有作为非抽象类的SolrDispatchFilter必须要实现Filter接口。Filter接口如下:

  

  1. public interface Filter {
  2.  
  3. //进行初始化
  4. public void init(FilterConfig filterConfig) throws ServletException;
  5. //拦截所有的http请求
  6. public void doFilter(ServletRequest request, ServletResponse response,
  7. FilterChain chain)
  8. throws IOException, ServletException;
  9.  
  10. //进行注销的动作
  11. public void destroy();
  12. }

  根据上面的注释,我们知道在init方法中是进行初始化的。因此,今天咱们研究SolrDispatchFilter是如何初始化,是离不开这个方法的。接下来,咱们看看SolrDispatchFilter的init方法吧:

  

  1. @Override
  2. public void init(FilterConfig config) throws ServletException
  3. {
  4. log.info("SolrDispatchFilter.init()");
  5.  
  6. try {
  7. // web.xml configuration
  8. this.pathPrefix = config.getInitParameter( "path-prefix" );
  9. //各位看客,乾坤尽在此方法中
  10. this.cores = createCoreContainer();
  11. log.info("user.dir=" + System.getProperty("user.dir"));
  12. }
  13. catch( Throwable t ) {
  14. // catch this so our filter still works
  15. log.error( "Could not start Solr. Check solr/home property and the logs");
  16. SolrCore.log( t );
  17. if (t instanceof Error) {
  18. throw (Error) t;
  19. }
  20. }
  21.  
  22. log.info("SolrDispatchFilter.init() done");
  23. }

  咱们顺藤摸瓜,来看看createCoreContainer这个方法到底干了些什么。

  

  1. protected CoreContainer createCoreContainer() {
      //看好了SolrResourceLoader 是用来加载solr home中的配置文件文件的
  2. SolrResourceLoader loader = new SolrResourceLoader(SolrResourceLoader.locateSolrHome());
  3. //加载配置文件
    ConfigSolr config = loadConfigSolr(loader);
  4. CoreContainer cores = new CoreContainer(loader, config);
       //初始化Core
  5. cores.load();
  6. return cores;
  7. }

  createCoreContainer这个方法是决定咱们今天能否弄懂Solr初始化和启动的关键。我们顺便简单分析一下这个方法中用到的几个类和方法:

  SolrResourceLoader  类如其名,是solr资源加载器。

     ConfigSolr 是通过SolrResourceLoader来读取solr配置文件的中信息的。

    loadConfigSolr,加载配置信息的方法:

  1. private ConfigSolr loadConfigSolr(SolrResourceLoader loader) {
  2. //优先读取solr.solrxml.location配置的信息,往往是通过读取zookeeper中的配置信息进行初始化的,如果没有配置,就会读取solrhome配置项配置的信息(记得web.xml第一个配置项否,就是它)
  3. String solrxmlLocation = System.getProperty("solr.solrxml.location", "solrhome");
  4. if (solrxmlLocation == null || "solrhome".equalsIgnoreCase(solrxmlLocation))
  5. return ConfigSolr.fromSolrHome(loader, loader.getInstanceDir());
  6. //ok 从zookeeper中读取配置信息吧,这是在solrcloud集群下用来solr初始化的
  7. if ("zookeeper".equalsIgnoreCase(solrxmlLocation)) {
  8. String zkHost = System.getProperty("zkHost");
  9. log.info("Trying to read solr.xml from " + zkHost);
  10. if (StringUtils.isEmpty(zkHost))
  11. throw new SolrException(ErrorCode.SERVER_ERROR,
  12. "Could not load solr.xml from zookeeper: zkHost system property not set");
  13. SolrZkClient zkClient = new SolrZkClient(zkHost, 30000);
  14. try {
  15. if (!zkClient.exists("/solr.xml", true))//solr.xml里有描述的zookeeper相关的配置信息
  16. throw new SolrException(ErrorCode.SERVER_ERROR, "Could not load solr.xml from zookeeper: node not found");
  17. byte[] data = zkClient.getData("/solr.xml", null, null, true);
    //加载配置信息
  18. return ConfigSolr.fromInputStream(loader, new ByteArrayInputStream(data));
  19. } catch (Exception e) {
  20. throw new SolrException(ErrorCode.SERVER_ERROR, "Could not load solr.xml from zookeeper", e);
  21. } finally {
  22. zkClient.close();//关闭zookeeper连接
  23. }
  24. }
  25.  
  26. throw new SolrException(ErrorCode.SERVER_ERROR,
  27. "Bad solr.solrxml.location set: " + solrxmlLocation + " - should be \'solrhome\' or \'zookeeper\'");
  28. }

  CoreContainer  就是进行Core初始化工作的。我们主要看看load方法吧,这段方法有点长,代码如下:

  

  1. public void load() {
  2.  
  3. log.info("Loading cores into CoreContainer [instanceDir={}]", loader.getInstanceDir());
  4. //加载solr共享jar包库
  5. // add the sharedLib to the shared resource loader before initializing cfg based plugins
  6. String libDir = cfg.getSharedLibDirectory();
  7. if (libDir != null) {
  8. File f = FileUtils.resolvePath(new File(solrHome), libDir);
  9. log.info("loading shared library: " + f.getAbsolutePath());
    //对classloader不熟的,可以进去看看
  10. loader.addToClassLoader(libDir, null, false);
  11. loader.reloadLuceneSPI();
  12. }
  13.  
  14. //分片相关的handler加载以及初始化
  15. shardHandlerFactory = ShardHandlerFactory.newInstance(cfg.getShardHandlerFactoryPluginInfo(), loader);
  16. updateShardHandler = new UpdateShardHandler(cfg);
  17.  
  18. solrCores.allocateLazyCores(cfg.getTransientCacheSize(), loader);
  19.  
  20. logging = LogWatcher.newRegisteredLogWatcher(cfg.getLogWatcherConfig(), loader);
  21.  
  22. hostName = cfg.getHost();
  23. log.info("Host Name: " + hostName);
  24.  
  25. zkSys.initZooKeeper(this, solrHome, cfg);
  26.  
  27. collectionsHandler = createHandler(cfg.getCollectionsHandlerClass(), CollectionsHandler.class);
  28. infoHandler = createHandler(cfg.getInfoHandlerClass(), InfoHandler.class);
  29. coreAdminHandler = createHandler(cfg.getCoreAdminHandlerClass(), CoreAdminHandler.class);
  30. //zookeeper 配置信息初始化solr core
  31. coreConfigService = cfg.createCoreConfigService(loader, zkSys.getZkController());
  32.  
  33. containerProperties = cfg.getSolrProperties("solr");
  34.  
  35. // setup executor to load cores in parallel
  36. // do not limit the size of the executor in zk mode since cores may try and wait for each other.
    //多线程初始化core 不熟悉多线的可以驻足研究一会
  37. ExecutorService coreLoadExecutor = Executors.newFixedThreadPool(
  38. ( zkSys.getZkController() == null ? cfg.getCoreLoadThreadCount() : Integer.MAX_VALUE ),
  39. new DefaultSolrThreadFactory("coreLoadExecutor") );
  40.  
  41. try {
  42. CompletionService<SolrCore> completionService = new ExecutorCompletionService<>(
  43. coreLoadExecutor);
  44.  
  45. Set<Future<SolrCore>> pending = new HashSet<>();
  46.  
  47. List<CoreDescriptor> cds = coresLocator.discover(this);
  48. checkForDuplicateCoreNames(cds);
  49.  
  50. for (final CoreDescriptor cd : cds) {
  51.  
  52. final String name = cd.getName();
  53. try {
  54.  
  55. if (cd.isTransient() || ! cd.isLoadOnStartup()) {
  56. // Store it away for later use. includes non-transient but not
  57. // loaded at startup cores.
  58. solrCores.putDynamicDescriptor(name, cd);
  59. }
  60. if (cd.isLoadOnStartup()) { // The normal case
  61.  
  62. Callable<SolrCore> task = new Callable<SolrCore>() {
  63. @Override
  64. public SolrCore call() {
  65. SolrCore c = null;
  66. try {
  67. if (zkSys.getZkController() != null) {//zookeeper模式
  68. preRegisterInZk(cd);
  69. }
  70. c = create(cd);//普通创建模式
  71. registerCore(cd.isTransient(), name, c, false, false);
  72. } catch (Exception e) {
  73. SolrException.log(log, null, e);
  74. try {
  75. /* if (isZooKeeperAware()) {
  76. try {
  77. zkSys.zkController.unregister(name, cd);
  78. } catch (InterruptedException e2) {
  79. Thread.currentThread().interrupt();
  80. SolrException.log(log, null, e2);
  81. } catch (KeeperException e3) {
  82. SolrException.log(log, null, e3);
  83. }
  84. }*/
  85. } finally {
  86. if (c != null) {
  87. c.close();
  88. }
  89. }
  90. }
  91. return c;
  92. }
  93. };
  94. pending.add(completionService.submit(task));
  95.  
  96. }
  97. } catch (Exception e) {
  98. SolrException.log(log, null, e);
  99. }
  100. }
  101.  
  102. while (pending != null && pending.size() > 0) {
  103. try {
  104. //获取创建完成的core
  105. Future<SolrCore> future = completionService.take();
  106. if (future == null) return;
  107. pending.remove(future);
  108.  
  109. try {
  110. SolrCore c = future.get();
  111. // track original names
  112. if (c != null) {
  113. solrCores.putCoreToOrigName(c, c.getName());
  114. }
  115. } catch (ExecutionException e) {
  116. SolrException.log(SolrCore.log, "Error loading core", e);
  117. }
  118.  
  119. } catch (InterruptedException e) {
  120. throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE,
  121. "interrupted while loading core", e);
  122. }
  123. }

  124. //solr core的守护线程,在容器关闭或者启动失败的时候,进行资源注销
  125. // Start the background thread
  126. backgroundCloser = new CloserThread(this, solrCores, cfg);
  127. backgroundCloser.start();
  128.  
  129. } finally {
  130. if (coreLoadExecutor != null) {
    //初始化完成,关闭线程池
  131. ExecutorUtil.shutdownNowAndAwaitTermination(coreLoadExecutor);
  132. }
  133. }
  134. if (isZooKeeperAware()) {//如果zookeeper可用 也就是solrcloud模式
  135. // register in zk in background threads
  136. Collection<SolrCore> cores = getCores();
  137. if (cores != null) {
  138. for (SolrCore core : cores) {
  139. try {
    //讲core的状态信息注册到zookeeper中
  140. zkSys.registerInZk(core, true);
  141. } catch (Throwable t) {
  142. SolrException.log(log, "Error registering SolrCore", t);
  143. }
  144. }
  145. }
    //
  146. zkSys.getZkController().checkOverseerDesignate();
  147. }
  148. }

  在这段代码,关键部分我都做了注释。当你需要优化你的solr启动速度时,你还会来研究这段代码。下面,我们将研究solr的请求过滤处理的部分,我们需要关注doFilter那个方法了(关键部分我作以注释,就不细讲了):

     

  1. if( abortErrorMessage != null ) {//500错误处理
  2. ((HttpServletResponse)response).sendError( 500, abortErrorMessage );
  3. return;
  4. }
  5. if (this.cores == null) {//solr core初始化失败或者已经关闭
  6. ((HttpServletResponse)response).sendError( 503, "Server is shutting down or failed to initialize" );
  7. return;
  8. }
  9. CoreContainer cores = this.cores;
  10. SolrCore core = null;
  11. SolrQueryRequest solrReq = null;
  12. Aliases aliases = null;
  13. if( request instanceof HttpServletRequest) {//如果是http请求
  14. HttpServletRequest req = (HttpServletRequest)request;
  15. HttpServletResponse resp = (HttpServletResponse)response;
  16. SolrRequestHandler handler = null;
  17. String corename = "";
  18. String origCorename = null;
  19. try {
  20. // put the core container in request attribute
  21. req.setAttribute("org.apache.solr.CoreContainer", cores);
  22. String path = req.getServletPath();
  23. if( req.getPathInfo() != null ) {
  24. // this lets you handle /update/commit when /update is a servlet
  25. path += req.getPathInfo();
  26. }
  27. if( pathPrefix != null && path.startsWith( pathPrefix ) ) {
  28. path = path.substring( pathPrefix.length() );
  29. }
  30. // check for management path
  31. String alternate = cores.getManagementPath();
  32. if (alternate != null && path.startsWith(alternate)) {
  33. path = path.substring(0, alternate.length());
  34. }
  35. // unused feature ?
  36. int idx = path.indexOf( \':\' );
  37. if( idx > 0 ) {
  38. // save the portion after the \':\' for a \'handler\' path parameter
  39. path = path.substring( 0, idx );
  40. }
  41.  
  42. // Check for the core admin page
  43. if( path.equals( cores.getAdminPath() ) ) {//solr admin 管理页面请求
  44. handler = cores.getMultiCoreHandler();
  45. solrReq = SolrRequestParsers.DEFAULT.parse(null,path, req);
  46. handleAdminRequest(req, response, handler, solrReq);
  47. return;
  48. }
  49. boolean usingAliases = false;
  50. List<String> collectionsList = null;
  51. // Check for the core admin collections url
  52. if( path.equals( "/admin/collections" ) ) {//管理collections
  53. handler = cores.getCollectionsHandler();
  54. solrReq = SolrRequestParsers.DEFAULT.parse(null,path, req);
  55. handleAdminRequest(req, response, handler, solrReq);
  56. return;
  57. }
  58. // Check for the core admin info url
  59. if( path.startsWith( "/admin/info" ) ) {//查看admin info
  60. handler = cores.getInfoHandler();
  61. solrReq = SolrRequestParsers.DEFAULT.parse(null,path, req);
  62. handleAdminRequest(req, response, handler, solrReq);
  63. return;
  64. }
  65. else {
  66. //otherwise, we should find a core from the path
  67. idx = path.indexOf( "/", 1 );
  68. if( idx > 1 ) {
  69. // try to get the corename as a request parameter first
  70. corename = path.substring( 1, idx );
  71. // look at aliases
  72. if (cores.isZooKeeperAware()) {//solr cloud状态
  73. origCorename = corename;
  74. ZkStateReader reader = cores.getZkController().getZkStateReader();
  75. aliases = reader.getAliases();
  76. if (aliases != null && aliases.collectionAliasSize() > 0) {
  77. usingAliases = true;
  78. String alias = aliases.getCollectionAlias(corename);
  79. if (alias != null) {
  80. collectionsList = StrUtils.splitSmart(alias, ",", true);
  81. corename = collectionsList.get(0);
  82. }
  83. }
  84. }
  85. core = cores.getCore(corename);
  86.  
  87. if (core != null) {
  88. path = path.substring( idx );
  89. }
  90. }
  91. if (core == null) {
  92. if (!cores.isZooKeeperAware() ) {
  93. core = cores.getCore("");
  94. }
  95. }
  96. }
  97. if (core == null && cores.isZooKeeperAware()) {
  98. // we couldn\'t find the core - lets make sure a collection was not specified instead
  99. core = getCoreByCollection(cores, corename, path);
  100. if (core != null) {
  101. // we found a core, update the path
  102. path = path.substring( idx );
  103. }
  104. // if we couldn\'t find it locally, look on other nodes
  105. if (core == null && idx > 0) {
  106. String coreUrl = getRemotCoreUrl(cores, corename, origCorename);
  107. // don\'t proxy for internal update requests
  108. SolrParams queryParams = SolrRequestParsers.parseQueryString(req.getQueryString());
  109. if (coreUrl != null
  110. && queryParams
  111. .get(DistributingUpdateProcessorFactory.DISTRIB_UPDATE_PARAM) == null) {
  112. path = path.substring(idx);
  113. remoteQuery(coreUrl + path, req, solrReq, resp);
  114. return;
  115. } else {
  116. if (!retry) {
  117. // we couldn\'t find a core to work with, try reloading aliases
  118. // TODO: it would be nice if admin ui elements skipped this...
  119. ZkStateReader reader = cores.getZkController()
  120. .getZkStateReader();
  121. reader.updateAliases();
  122. doFilter(request, response, chain, true);
  123. return;
  124. }
  125. }
  126. }
  127. // try the default core
  128. if (core == null) {
  129. core = cores.getCore("");
  130. }
  131. }
  132.  
  133. // With a valid core...
  134. if( core != null ) {//验证core
  135. final SolrConfig config = core.getSolrConfig();
  136. // get or create/cache the parser for the core
  137. SolrRequestParsers parser = config.getRequestParsers();
  138.  
  139. // Handle /schema/* and /config/* paths via Restlet
  140. if( path.equals("/schema") || path.startsWith("/schema/")
  141. || path.equals("/config") || path.startsWith("/config/")) {//solr rest api 入口
  142. solrReq = parser.parse(core, path, req);
  143. SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, new SolrQueryResponse()));
  144. if( path.equals(req.getServletPath()) ) {
  145. // avoid endless loop - pass through to Restlet via webapp
  146. chain.doFilter(request, response);
  147. } else {
  148. // forward rewritten URI (without path prefix and core/collection name) to Restlet
  149. req.getRequestDispatcher(path).forward(request, response);
  150. }
  151. return;
  152. }
  153.  
  154. // Determine the handler from the url path if not set
  155. // (we might already have selected the cores handler)
  156. if( handler == null && path.length() > 1 ) { // don\'t match "" or "/" as valid path
  157. handler = core.getRequestHandler( path );
  158. // no handler yet but allowed to handle select; let\'s check
  159. if( handler == null && parser.isHandleSelect() ) {
  160. if( "/select".equals( path ) || "/select/".equals( path ) ) {//solr 各种查询过滤入口
  161. solrReq = parser.parse( core, path, req );
  162. String qt = solrReq.getParams().get( CommonParams.QT );
  163. handler = core.getRequestHandler( qt );
  164. if( handler == null ) {
  165. throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "unknown handler: "+qt);
  166. }
  167. if( qt != null && qt.startsWith("/") && (handler instanceof ContentStreamHandlerBase)) {
  168. //For security reasons it\'s a bad idea to allow a leading \'/\', ex: /select?qt=/update see SOLR-3161
  169. //There was no restriction from Solr 1.4 thru 3.5 and it\'s not supported for update handlers.
  170. throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Invalid Request Handler (\'qt\'). Do not use /select to access: "+qt);
  171. }
  172. }
  173. }
  174. }
  175.  
  176. // With a valid handler and a valid core...
  177. if( handler != null ) {
  178. // if not a /select, create the request
  179. if( solrReq == null ) {
  180. solrReq = parser.parse( core, path, req );
  181. }
  182.  
  183. if (usingAliases) {
  184. processAliases(solrReq, aliases, collectionsList);
  185. }
  186. final Method reqMethod = Method.getMethod(req.getMethod());
  187. HttpCacheHeaderUtil.setCacheControlHeader(config, resp, reqMethod);
  188. // unless we have been explicitly told not to, do cache validation
  189. // if we fail cache validation, execute the query
  190. if (config.getHttpCachingConfig().isNever304() ||
  191. !HttpCacheHeaderUtil.doCacheHeaderValidation(solrReq, req, reqMethod, resp)) {//solr http 缓存 在header控制失效时间的方式
  192. SolrQueryResponse solrRsp = new SolrQueryResponse();
  193. /* even for HEAD requests, we need to execute the handler to
  194. * ensure we don\'t get an error (and to make sure the correct
  195. * QueryResponseWriter is selected and we get the correct
  196. * Content-Type)
  197. */
  198. SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, solrRsp));
  199. this.execute( req, handler, solrReq, solrRsp );
  200. HttpCacheHeaderUtil.checkHttpCachingVeto(solrRsp, resp, reqMethod);
  201. // add info to http headers
  202. //TODO: See SOLR-232 and SOLR-267.
  203. /*try {
  204. NamedList solrRspHeader = solrRsp.getResponseHeader();
  205. for (int i=0; i<solrRspHeader.size(); i++) {
  206. ((javax.servlet.http.HttpServletResponse) response).addHeader(("Solr-" + solrRspHeader.getName(i)), String.valueOf(solrRspHeader.getVal(i)));
  207. }
  208. } catch (ClassCastException cce) {
  209. log.log(Level.WARNING, "exception adding response header log information", cce);
  210. }*/
  211. QueryResponseWriter responseWriter = core.getQueryResponseWriter(solrReq);
  212. writeResponse(solrRsp, response, responseWriter, solrReq, reqMethod);
  213. }
  214. return; // we are done with a valid handler
  215. }
  216. }
  217. log.debug("no handler or core retrieved for " + path + ", follow through...");
  218. }
  219. catch (Throwable ex) {
  220. sendError( core, solrReq, request, (HttpServletResponse)response, ex );
  221. if (ex instanceof Error) {
  222. throw (Error) ex;
  223. }
  224. return;
  225. } finally {
  226. try {
  227. if (solrReq != null) {
  228. log.debug("Closing out SolrRequest: {}", solrReq);
  229. solrReq.close();
  230. }
  231. } finally {
  232. try {
  233. if (core != null) {
  234. core.close();
  235. }
  236. } finally {
  237. SolrRequestInfo.clearRequestInfo();
  238. }
  239. }
  240. }
  241. }
  242.  
  243. // Otherwise let the webapp handle the request
  244. chain.doFilter(request, response);
  245. }

  

 

 

 

文章转载请注明出处:http://www.cnblogs.com/likehua/p/4353608.html

 

  

版权声明:本文为likehua原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/likehua/p/4353608.html