Solr 6.0 学习(八) SolrDispatchFilter源码解析及solr扩展
来源:互联网 发布:淘宝折扣代购 编辑:程序博客网 时间:2024/06/01 20:37
传送门:老版SolrDispatchFilter源码解析
SolrDispatchFilter做了什么
我们发布好我们的solr6.X之后我们可以看到项目下web.xml中一段配置
<!-- Any path (name) registered in solrconfig.xml will be sent to that filter --> <filter> <filter-name>SolrRequestFilter</filter-name> <filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class> <!-- Exclude patterns is a list of directories that would be short circuited by the SolrDispatchFilter. It includes all Admin UI related static content. NOTE: It is NOT a pattern but only matches the start of the HTTP ServletPath. --> <init-param> <param-name>excludePatterns</param-name> <param-value>/css/.+,/js/.+,/img/.+,/tpl/.+</param-value> </init-param> </filter> <filter-mapping> <!-- NOTE: When using multicore, /admin JSP URLs with a core specified such as /solr/coreName/admin/stats.jsp get forwarded by a RequestDispatcher to /solr/admin/stats.jsp with the specified core put into request scope keyed as "org.apache.solr.SolrCore". It is unnecessary, and potentially problematic, to have the SolrDispatchFilter configured to also filter on forwards. Do not configure this dispatcher as <dispatcher>FORWARD</dispatcher>. --> <filter-name>SolrRequestFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
我们注意其中org.apache.solr.servlet.SolrDispatchFilter
这个是个全局的过滤器Filter。下面我们来一步步的研究一下其源码主要做了些什么
BaseSolrFilter
package org.apache.solr.servlet;import javax.servlet.Filter;abstract class BaseSolrFilter implements Filter{ static { CheckLoggingConfiguration.check(); }}
CheckLoggingConfiguration
package org.apache.solr.servlet;import org.slf4j.LoggerFactory;final class CheckLoggingConfiguration{ static void check() { try { LoggerFactory.getLogger(CheckLoggingConfiguration.class); } catch (NoClassDefFoundError e) { throw new NoClassDefFoundError("Failed to initialize Apache Solr: Could not find necessary SLF4j logging jars. If using Jetty, the SLF4j logging jars need to go in the jetty lib/ext directory. For other containers, the corresponding directory should be used. For more information, see: http://wiki.apache.org/solr/SolrLogging"); } }}
SolrDispatchFilter
package org.apache.solr.servlet;import java.io.ByteArrayInputStream;import java.io.IOException;import java.lang.invoke.MethodHandles;import java.lang.invoke.MethodHandles.Lookup;import java.nio.file.Path;import java.nio.file.Paths;import java.util.ArrayList;import java.util.Properties;import java.util.concurrent.atomic.AtomicBoolean;import java.util.concurrent.atomic.AtomicReference;import java.util.regex.Matcher;import java.util.regex.Pattern;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.RequestDispatcher;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.ServletInputStream;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang.StringUtils;import org.apache.http.client.HttpClient;import org.apache.solr.common.SolrException;import org.apache.solr.common.SolrException.ErrorCode;import org.apache.solr.common.cloud.SolrZkClient;import org.apache.solr.common.util.ExecutorUtil;import org.apache.solr.core.CoreContainer;import org.apache.solr.core.NodeConfig;import org.apache.solr.core.SolrCore;import org.apache.solr.core.SolrResourceLoader;import org.apache.solr.core.SolrXmlConfig;import org.apache.solr.request.SolrRequestInfo;import org.apache.solr.security.AuthenticationPlugin;import org.apache.solr.update.UpdateShardHandler;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class SolrDispatchFilter extends BaseSolrFilter{ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); protected volatile CoreContainer cores; protected String abortErrorMessage = null; protected HttpClient httpClient; private ArrayList<Pattern> excludePatterns; public static final String PROPERTIES_ATTRIBUTE = "solr.properties"; public static final String SOLRHOME_ATTRIBUTE = "solr.solr.home"; public void init(FilterConfig config) throws ServletException { log.info("SolrDispatchFilter.init(): {}", getClass().getClassLoader()); //获取filter配置中的excludePatterns,实际上就是配置不经过filter的路径 String exclude = config.getInitParameter("excludePatterns"); if (exclude != null) { String[] excludeArray = exclude.split(","); this.excludePatterns = new ArrayList(); for (String element : excludeArray) this.excludePatterns.add(Pattern.compile(element)); } try { Properties extraProperties = (Properties)config.getServletContext().getAttribute("solr.properties"); if (extraProperties == null) { extraProperties = new Properties(); } String solrHome = (String)config.getServletContext().getAttribute("solr.solr.home"); ExecutorUtil.addThreadLocalProvider(SolrRequestInfo.getInheritableThreadLocalProvider()); this.cores = createCoreContainer(solrHome == null ? SolrResourceLoader.locateSolrHome() : Paths.get(solrHome, new String[0]), extraProperties); this.httpClient = this.cores.getUpdateShardHandler().getHttpClient(); log.info("user.dir=" + System.getProperty("user.dir")); } catch (Throwable t) { log.error("Could not start Solr. Check solr/home property and the logs"); SolrCore.log(t); if ((t instanceof Error)) { throw ((Error)t); } } log.info("SolrDispatchFilter.init() done"); } protected CoreContainer createCoreContainer(Path solrHome, Properties extraProperties) { NodeConfig nodeConfig = loadNodeConfig(solrHome, extraProperties); this.cores = new CoreContainer(nodeConfig, extraProperties, true); this.cores.load(); return this.cores; } public static NodeConfig loadNodeConfig(Path solrHome, Properties nodeProperties) { SolrResourceLoader loader = new SolrResourceLoader(solrHome, null, nodeProperties); if (!StringUtils.isEmpty(System.getProperty("solr.solrxml.location"))) { log.warn("Solr property solr.solrxml.location is no longer supported. Will automatically load solr.xml from ZooKeeper if it exists"); } String zkHost = System.getProperty("zkHost"); if (!StringUtils.isEmpty(zkHost)) { try { SolrZkClient zkClient = new SolrZkClient(zkHost, 30000); Throwable localThrowable4 = null; try { if (zkClient.exists("/solr.xml", true).booleanValue()) { log.info("solr.xml found in ZooKeeper. Loading..."); byte[] data = zkClient.getData("/solr.xml", null, null, true); return SolrXmlConfig.fromInputStream(loader, new ByteArrayInputStream(data)); } } catch (Throwable localThrowable2) { localThrowable4 = localThrowable2; throw localThrowable2; } finally { if (zkClient != null) if (localThrowable4 != null) try { zkClient.close(); } catch (Throwable localThrowable3) { localThrowable4.addSuppressed(localThrowable3); } else zkClient.close(); } } catch (Exception e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error occurred while loading solr.xml from zookeeper", e); } log.info("Loading solr.xml from SolrHome (not found in ZooKeeper)"); } return SolrXmlConfig.fromSolrHome(loader, loader.getInstancePath()); } public CoreContainer getCores() { return this.cores; } public void destroy() { if (this.cores != null) try { this.cores.shutdown(); this.cores = null; } finally { this.cores = null; } } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { doFilter(request, response, chain, false); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain, boolean retry) throws IOException, ServletException { if (!(request instanceof HttpServletRequest)) return; try { if ((this.cores == null) || (this.cores.isShutDown())) { log.error("Error processing the request. CoreContainer is either not initialized or shutting down."); throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE, "Error processing the request. CoreContainer is either not initialized or shutting down."); } AtomicReference wrappedRequest = new AtomicReference(); if (!authenticateRequest(request, response, wrappedRequest)) { return; } if (wrappedRequest.get() != null) { request = (ServletRequest)wrappedRequest.get(); } if (this.cores.getAuthenticationPlugin() != null) log.debug("User principal: {}", ((HttpServletRequest)request).getUserPrincipal()); String requestPath; if (this.excludePatterns != null) { requestPath = ((HttpServletRequest)request).getServletPath(); String extraPath = ((HttpServletRequest)request).getPathInfo(); if (extraPath != null) { requestPath = requestPath + extraPath; } for (Pattern p : this.excludePatterns) { Matcher matcher = p.matcher(requestPath); if (matcher.lookingAt()) { chain.doFilter(request, response); return; } } } HttpSolrCall call = getHttpSolrCall((HttpServletRequest)request, (HttpServletResponse)response, retry); ExecutorUtil.setServerThreadFlag(Boolean.TRUE); try { Action result = call.call(); switch (2.$SwitchMap$org$apache$solr$servlet$SolrDispatchFilter$Action[result.ordinal()]) { case 1: chain.doFilter(request, response); break; case 2: doFilter(request, response, chain, true); break; case 3: request.getRequestDispatcher(call.getPath()).forward(request, response); } } finally { call.destroy(); ExecutorUtil.setServerThreadFlag(null); } } finally { consumeInputFully((HttpServletRequest)request); } } private void consumeInputFully(HttpServletRequest req) { try { ServletInputStream is = req.getInputStream(); while ((!is.isFinished()) && (is.read() != -1)); } catch (IOException e) { log.info("Could not consume full client request", e); } } protected HttpSolrCall getHttpSolrCall(HttpServletRequest request, HttpServletResponse response, boolean retry) { return new HttpSolrCall(this, this.cores, request, response, retry); } private boolean authenticateRequest(ServletRequest request, ServletResponse response, final AtomicReference<ServletRequest> wrappedRequest) throws IOException { final AtomicBoolean isAuthenticated = new AtomicBoolean(false); AuthenticationPlugin authenticationPlugin = this.cores.getAuthenticationPlugin(); if (authenticationPlugin == null) { return true; } String header = ((HttpServletRequest)request).getHeader("SolrAuth"); if ((header != null) && (this.cores.getPkiAuthenticationPlugin() != null)) authenticationPlugin = this.cores.getPkiAuthenticationPlugin(); try { log.debug("Request to authenticate: {}, domain: {}, port: {}", new Object[] { request, request.getLocalName(), Integer.valueOf(request.getLocalPort()) }); authenticationPlugin.doAuthenticate(request, response, new FilterChain() { public void doFilter(ServletRequest req, ServletResponse rsp) throws IOException, ServletException { isAuthenticated.set(true); wrappedRequest.set(req); } } ); } catch (Exception e) { e.printStackTrace(); throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error during request authentication, ", e); } if (!isAuthenticated.get()) { response.flushBuffer(); return false; } return true; } static enum Action { PASSTHROUGH, FORWARD, RETURN, RETRY, ADMIN, REMOTEQUERY, PROCESS; }}
源码很多,我们拆分来看。
- 初始化solr core容器
this.cores = createCoreContainer(solrHome == null ? SolrResourceLoader.locateSolrHome() : Paths.get(solrHome, new String[0]), extraProperties);
我们看到SolrResourceLoader.locateSolrHome()
截取部分代码
/* *可以找到源码中读取配置文件代码* Context c = new InitialContext();* home = (String)c.lookup("java:comp/env/solr/home");* 补充说明:* env -entry元素声明Web应用的环境项。它由一个可选的description元素、一个* env-entry-name元素(一个相对于java: comp/env环境JNDI名)、一个env-entry-value元素(项值)以及一个env-entry-type元素* (java.lang程序包中一个类型的完全限定类名,java.lang.Boolean、java.lang.String等)组成。* 那么实际上就是去找web.xml下* <!-- 配置solr home位置 --> <env-entry> <env-entry-name>solr/home</env-entry-name> <env-entry-value>D:\solr\apache-tomcat-8.0.33\webapps\solr\solrhome</env-entry-value> <env-entry-type>java.lang.String</env-entry-type> </env-entry>*/ public static Path locateSolrHome() { String home = null; try { Context c = new InitialContext(); home = (String)c.lookup("java:comp/env/solr/home"); log.info(new StringBuilder().append("Using JNDI solr.home: ").append(home).toString()); } catch (NoInitialContextException e) { log.info("JNDI not configured for solr (NoInitialContextEx)"); } catch (NamingException e) { log.info("No /solr/home in JNDI"); } catch (RuntimeException ex) { log.warn(new StringBuilder().append("Odd RuntimeException while testing for JNDI: ").append(ex.getMessage()).toString()); } if (home == null) { String prop = "solr.solr.home"; home = System.getProperty(prop); if (home != null) { log.info(new StringBuilder().append("using system property ").append(prop).append(": ").append(home).toString()); } } if (home == null) { home = "solr/"; log.info(new StringBuilder().append("solr home defaulted to '").append(home).append("' (could not find system property or JNDI)").toString()); } return Paths.get(home, new String[0]); }
/** * 创建solr core容器 * @param solrHome * @param extraProperties * @return */ protected CoreContainer createCoreContainer(Path solrHome, Properties extraProperties) { NodeConfig nodeConfig = loadNodeConfig(solrHome, extraProperties); this.cores = new CoreContainer(nodeConfig, extraProperties, true); this.cores.load(); return this.cores; }/** * 获取配置文件 包含zookeeper的配置 * @param solrHome * @param nodeProperties * @return */ public static NodeConfig loadNodeConfig(Path solrHome, Properties nodeProperties) { SolrResourceLoader loader = new SolrResourceLoader(solrHome, null, nodeProperties); if (!StringUtils.isEmpty(System.getProperty("solr.solrxml.location"))) { log.warn("Solr property solr.solrxml.location is no longer supported. Will automatically load solr.xml from ZooKeeper if it exists"); } String zkHost = System.getProperty("zkHost"); if (!StringUtils.isEmpty(zkHost)) { try { SolrZkClient zkClient = new SolrZkClient(zkHost, 30000); Throwable localThrowable4 = null; try { if (zkClient.exists("/solr.xml", true).booleanValue()) { log.info("solr.xml found in ZooKeeper. Loading..."); byte[] data = zkClient.getData("/solr.xml", null, null, true); return SolrXmlConfig.fromInputStream(loader, new ByteArrayInputStream(data)); } } catch (Throwable localThrowable2) { localThrowable4 = localThrowable2; throw localThrowable2; } finally { if (zkClient != null) if (localThrowable4 != null) try { zkClient.close(); } catch (Throwable localThrowable3) { localThrowable4.addSuppressed(localThrowable3); } else zkClient.close(); } } catch (Exception e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error occurred while loading solr.xml from zookeeper", e); } log.info("Loading solr.xml from SolrHome (not found in ZooKeeper)"); } return SolrXmlConfig.fromSolrHome(loader, loader.getInstancePath()); }
2、doFilter:全局性的过滤,将对特定的需要全文检索的请求进行一个过滤然后提供全文检索服务
HttpSolrCall call = getHttpSolrCall((HttpServletRequest)request, (HttpServletResponse)response, retry);
获取httpSolrCall实例
protected HttpSolrCall getHttpSolrCall(HttpServletRequest request, HttpServletResponse response, boolean retry) { return new HttpSolrCall(this, this.cores, request, response, retry); }
调用call
Action result = call.call();
下面我们重点看下HttpSolrCall 做了些什么,Solr 6.0 学习(九)会对HttpSolrCall做更详细的解答。
0 0
- Solr 6.0 学习(八) SolrDispatchFilter源码解析及solr扩展
- Solr 6.0 学习(九) SolrDispatchFilter源码解析之HttpSolrCall及扩展
- Solr 6.0 学习(十)QueryResponseWriter 源码解析
- Solr 6.0 学习(六)solr集群
- Solr 6.0 学习(五)solr集群
- Solr 6.0 学习(十三)Solr缓存
- Solr 6.0 学习(十四)Solr RequstHandler
- Solr 6.0 学习(十五)Solr SearchComponent
- Solr学习(八)多表导入
- Scaling Solr(Solr的扩展)
- Scaling Solr(Solr的扩展)
- Scaling Solr(Solr的扩展)
- solr创建索引源码解析
- solr索引过程源码解析
- 扩展 Solr
- Solr 6.0 学习(七) solr创建索引原理
- Solr 6.0 学习(六) solr创建索引原理
- Solr 6.0 学习(十一)solr writer自定义
- spring task 定时任务实现
- java爬虫(使用jsoup设置代理,抓取网页内容)
- 使用hexo在github搭建自己的博客
- jQuery对象跟DOM对象相互转换
- 关于数据库范式
- Solr 6.0 学习(八) SolrDispatchFilter源码解析及solr扩展
- Spring中控制反转IOC和依赖注入DI
- 欢迎使用CSDN-markdown编辑器
- linux shell “永久环境变量”、“临时环境变量”和普通变量之完全解读
- 动态生成select,赋值问题
- Android中连续点击版本号打开开发者选项的实现方式
- Oracle安装,运行setup未知名异常
- 错误:The request sent by the client was syntactically incorrect的解决
- SPP-Net 是怎么让 CNN 实现输入任意尺寸图像的?