solr-6.1.0源码分析---1

solr-6.1.0源码分析—SolrDispatchFilter初始化

SolrDispatchFilter继承自javax.servlet.Filter,并且在web.xml里有如下一段配置。

  <filter>
    <filter-name>SolrRequestFilter</filter-name>
    <filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class>
    <init-param>
      <param-name>excludePatterns</param-name>
      <param-value>/css/.+,/js/.+,/img/.+,/tpl/.+</param-value>
    </init-param>
  </filter>

因此,经过tomcat框架的处理后,最先会调用SolrRequestFilter的init函数。

SolrDispatchFilter::init

  public void init(FilterConfig config) throws ServletException{

    String exclude = config.getInitParameter("excludePatterns");
    if(exclude != null) {
      String[] excludeArray = exclude.split(",");
      excludePatterns = new ArrayList<>();
      for (String element : excludeArray) {
        excludePatterns.add(Pattern.compile(element));
      }
    }

    this.cores = createCoreContainer(SolrResourceLoader.locateSolrHome(), new Properties());
    this.httpClient = cores.getUpdateShardHandler().getHttpClient();
  }

首先将web.xml中配置的/css/.+、/js/.+、/img/.+和/tpl/.+添加到excludePatterns列表中。然后通过createCoreContainer创建CoreContainer并获取HttpClient。

SolrDispatchFilter::init->createCoreContainer

  protected CoreContainer createCoreContainer(Path solrHome, Properties extraProperties) {
    NodeConfig nodeConfig = loadNodeConfig(solrHome, extraProperties);
    cores = new CoreContainer(nodeConfig, extraProperties, true);
    cores.load();
    return cores;
  }

loadNodeConfig根据solrHome目录下的solr.xml文件生成NodeConfig,然后创建CoreContainer封装NodeConfig信息,最后通过load函数继续进行初始化,下面一一来看。

loadNodeConfig

SolrDispatchFilter::init->createCoreContainer->loadNodeConfig

  public static NodeConfig loadNodeConfig(Path solrHome, Properties nodeProperties) {

    SolrResourceLoader loader = new SolrResourceLoader(solrHome, null, nodeProperties);

    ...
    return SolrXmlConfig.fromSolrHome(loader, loader.getInstancePath());
  }

省略掉的部分和zookeeper相关,本章不考虑。首先创建SolrResourceLoader,然后通过fromSolrHome函数解析solrhome目录下的solr.xml配置文件并生成NodeConfig。

SolrDispatchFilter::init->createCoreContainer->loadNodeConfig->SolrResourceLoader::SolrResourceLoader

  public SolrResourceLoader(Path instanceDir, ClassLoader parent, Properties coreProperties) {

    if (parent == null)
      parent = Thread.currentThread().getContextClassLoader();
    this.classLoader = new URLClassLoader(new URL[0], parent);

    ...
    this.coreProperties = coreProperties;
  }

SolrResourceLoader构造函数主要创建了URLClassLoader,用来加载Class文件。

SolrDispatchFilter::init->createCoreContainer->loadNodeConfig->SolrXmlConfig::fromSolrHome

  public static NodeConfig fromSolrHome(SolrResourceLoader loader, Path solrHome) {
    return fromFile(loader, solrHome.resolve(SOLR_XML_FILE));
  }

  public static NodeConfig fromFile(SolrResourceLoader loader, Path configFile) {
    InputStream inputStream = Files.newInputStream(configFile);
    return fromInputStream(loader, inputStream);
  }

SOLR_XML_FILE默认为solrhome目录下的solr.xml,fromSolrHome函数将solr.xml文件变为输入流调用fromInputStream继续解析。首先看一下solr.xml的默认配置。

<solr>
  <solrcloud>
    <str name="host">${host:}</str>
    <int name="hostPort">${jetty.port:8983}</int>
    <str name="hostContext">${hostContext:solr}</str>
    <bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
    <int name="zkClientTimeout">${zkClientTimeout:30000}</int>
    <int name="distribUpdateSoTimeout">${distribUpdateSoTimeout:600000}</int>
    <int name="distribUpdateConnTimeout">${distribUpdateConnTimeout:60000}</int>
    <str name="zkCredentialsProvider">${zkCredentialsProvider:org.apache.solr.common.cloud.DefaultZkCredentialsProvider}</str>
    <str name="zkACLProvider">${zkACLProvider:org.apache.solr.common.cloud.DefaultZkACLProvider}</str>
  </solrcloud>

  <shardHandlerFactory name="shardHandlerFactory"
    class="HttpShardHandlerFactory">
    <int name="socketTimeout">${socketTimeout:600000}</int>
    <int name="connTimeout">${connTimeout:60000}</int>
  </shardHandlerFactory>
</solr>

SolrDispatchFilter::init->createCoreContainer->loadNodeConfig->SolrXmlConfig::fromSolrHome->fromFile->fromInputStream

  public static NodeConfig fromInputStream(SolrResourceLoader loader, InputStream is) {
    byte[] buf = IOUtils.toByteArray(is);
    ByteArrayInputStream dup = new ByteArrayInputStream(buf);
    Config config = new Config(loader, null, new InputSource(dup), null, false);
    return fromConfig(config);
  }

根据文件内容创建Config,Config构造函数将solr.xml中的配置信息解析成Document文档,然后通过fromConfig

SolrDispatchFilter::init->createCoreContainer->loadNodeConfig->SolrXmlConfig::fromSolrHome->fromFile->fromInputStream->Config::Config

  public Config(SolrResourceLoader loader, String name, InputSource is, String prefix, boolean substituteProps) throws ParserConfigurationException, IOException, SAXException
  {

      javax.xml.parsers.DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

      final DocumentBuilder db = dbf.newDocumentBuilder();
      db.setEntityResolver(new SystemIdResolver(loader));
      db.setErrorHandler(xmllog);

      doc = db.parse(is);
      origDoc = copyDoc(doc);
  }

DocumentBuilder的parse函数将文档输入流转变为Document对象。

SolrDispatchFilter::init->createCoreContainer->loadNodeConfig->SolrXmlConfig::fromSolrHome->fromFile->fromInputStream->fromConfig

  public static NodeConfig fromConfig(Config config) {

    config.substituteProperties();

    CloudConfig cloudConfig = null;
    UpdateShardHandlerConfig deprecatedUpdateConfig = null;

    if (config.getNodeList("solr/solrcloud", false).getLength() > 0) {
      NamedList<Object> cloudSection = readNodeListAsNamedList(config, "solr/solrcloud/*[@name]", "<solrcloud>");
      deprecatedUpdateConfig = loadUpdateConfig(cloudSection, false);
      cloudConfig = fillSolrCloudSection(cloudSection);
    }
    updateConfig = deprecatedUpdateConfig;

    NodeConfig.NodeConfigBuilder configBuilder = new NodeConfig.NodeConfigBuilder(nodeName, config.getResourceLoader());
    configBuilder.setUpdateShardHandlerConfig(updateConfig);
    configBuilder.setShardHandlerFactoryConfig(getShardHandlerFactoryPluginInfo(config));
    configBuilder.setLogWatcherConfig(loadLogWatcherConfig(config, "solr/logging/*[@name]", "solr/logging/watcher/*[@name]"));
    configBuilder.setSolrProperties(loadProperties(config));
    if (cloudConfig != null)
      configBuilder.setCloudConfig(cloudConfig);
    return fillSolrSection(configBuilder, entries);
  }

substituteProperties将一些属性由solr.propertyies属性替换。
如果solr.xml配置文件中存在solrcloud标签,则首先通过readNodeListAsNamedList函数将其中的键值对读取到cloudSection中,然后继续通过loadUpdateConfig函数从cloudSection中读取有关更新的数据并创建UpdateShardHandlerConfig用来封装这些信息,最后通过fillSolrCloudSection函数从cloudSection中提取出有关Cloud的配置并存储在CloudConfig中。
fromConfig函数接下来再次调用readNodeListAsNamedList函数读取到shardHandlerFactory标签的信息至entries中。
接下来创建NodeConfigBuilder并添加刚刚读取出来的各个信息,最后在fillSolrSection函数中会调用其build函数返回一个NodeConfig。

Load

创建完NodeConfig后,会创建CoreContainer并调用其load函数,根据NodeConfig中的配置信息创建相应的Handler。

SolrDispatchFilter::init->createCoreContainer->CoreContainer::load

  public void load()  {
    String libDir = cfg.getSharedLibDirectory();
    Path libPath = loader.getInstancePath().resolve(libDir);
    loader.addToClassLoader(SolrResourceLoader.getURLs(libPath));
    loader.reloadLuceneSPI();

    shardHandlerFactory = ShardHandlerFactory.newInstance(cfg.getShardHandlerFactoryPluginInfo(), loader);
    updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig());
    solrCores.allocateLazyCores(cfg.getTransientCacheSize(), loader);
    logging = LogWatcher.newRegisteredLogWatcher(cfg.getLogWatcherConfig(), loader);
    hostName = cfg.getNodeName();

    ...

    containerHandlers.put(ZK_PATH, new ZookeeperInfoHandler(this));
    securityConfHandler = new SecurityConfHandler(this);
    collectionsHandler = createHandler(cfg.getCollectionsHandlerClass(), CollectionsHandler.class);
    containerHandlers.put(COLLECTIONS_HANDLER_PATH, collectionsHandler);
    infoHandler        = createHandler(cfg.getInfoHandlerClass(), InfoHandler.class);
    containerHandlers.put(INFO_HANDLER_PATH, infoHandler);
    coreAdminHandler   = createHandler(cfg.getCoreAdminHandlerClass(), CoreAdminHandler.class);
    containerHandlers.put(CORES_HANDLER_PATH, coreAdminHandler);
    configSetsHandler = createHandler(cfg.getConfigSetsHandlerClass(), ConfigSetsHandler.class);
    containerHandlers.put(CONFIGSETS_HANDLER_PATH, configSetsHandler);
    containerHandlers.put(AUTHZ_PATH, securityConfHandler);
    containerHandlers.put(AUTHC_PATH, securityConfHandler);
    if(pkiAuthenticationPlugin != null)
      containerHandlers.put(PKIAuthenticationPlugin.PATH, pkiAuthenticationPlugin.getRequestHandler());

    coreConfigService = ConfigSetService.createConfigSetService(cfg, loader, zkSys.zkController);
    containerProperties.putAll(cfg.getSolrProperties());

    ...

    List<CoreDescriptor> cds = coresLocator.discover(this);

    ...

  }

libDir是solrhome目录下lib的相对路径,libPath是lib的绝对路径。首先通过addToClassLoader函数将该lib目录添加到URLClassLoader中,然后通过reloadLuceneSPI重新加载lucene的核心类文件。
load函数接下来初始化各个成员变量,其中最重要的是创建各个用来处理http请求的Handler并添加到containerHandlers列表中。
其中在创建UpdateShardHandler时,创建了HttpClient。

  public UpdateShardHandler(UpdateShardHandlerConfig cfg) {
    this.cfg = cfg;
    clientConnectionManager = new PoolingClientConnectionManager(SchemeRegistryFactory.createSystemDefault());
    clientConnectionManager.setMaxTotal(cfg.getMaxUpdateConnections());
    clientConnectionManager.setDefaultMaxPerRoute(cfg.getMaxUpdateConnectionsPerHost());

    ModifiableSolrParams clientParams = getClientParams();
    client = HttpClientUtil.createClient(clientParams, clientConnectionManager);
  }

  public static CloseableHttpClient createClient(final SolrParams params, ClientConnectionManager cm) {
    final ModifiableSolrParams config = new ModifiableSolrParams(params);
    final DefaultHttpClient httpClient = HttpClientFactory.createHttpClient(cm);
    configureClient(httpClient, config);
    return httpClient;
  }

HttpClientFactory的createHttpClient函数创建了DefaultHttpClient,然后通过configureClient进行配置。

SolrDispatchFilter::init->createCoreContainer->CoreContainer::load->CorePropertiesLocator::discover

  public List<CoreDescriptor> discover(final CoreContainer cc) {
    final List<CoreDescriptor> cds = Lists.newArrayList();
    Set<FileVisitOption> options = new HashSet<>();
    options.add(FileVisitOption.FOLLOW_LINKS);
    final int maxDepth = 256;

    Files.walkFileTree(this.rootDirectory, options, maxDepth, new SimpleFileVisitor<Path>() {
      @Override
      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        if (file.getFileName().toString().equals(PROPERTIES_FILENAME)) {
          CoreDescriptor cd = buildCoreDescriptor(file, cc);
          cds.add(cd);
          return FileVisitResult.SKIP_SIBLINGS;
        }
        return FileVisitResult.CONTINUE;
      }
    });

    return cds;
  }

PROPERTIES_FILENAME为core.properties,在solrhome目录下查找core.properties文件。
buildCoreDescriptor函数将其中的key和value封装成CoreDescriptor添加到cds列表中并返回。
下面假设该cds列表为空。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值