Solr4.7源码分析-启动篇(一)

来源:互联网 发布:怎么下载淘宝app 编辑:程序博客网 时间:2024/06/06 07:48

Solr的web.xml配置文件中,配置了一个filter:

  <!-- 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 >  </ filter>  < filter-mapping>    <filter-name >SolrRequestFilter </filter-name >    <url-pattern >/* </url-pattern >  </ filter-mapping>
Solr启动时,通过这个SolrDispatchFilter的init方法来加载配置文件和实例化各个组件。

Solr使用本地文件启动的大概流程为:(暂不考虑SolrCloud的情况)
1. 获取solrhome:先后通过JNDI,system property,default directory三种方式尝试获取
2. 实例化启动过程中使用的类加载器SolrResourceLoader
3. 加载solrhome下的solr.xml文件,封装为ConfigSolr
4. 实例化一个CoreContainer,通过CoreContainer来加载cores
5. (CoreContainer加载cores)先遍历solrhome,寻找含有core.properties的文件夹,视为找到一个core
6. 多线程加载cores
7. 加载每个core时先加载solrconfig.xml封装为SolrConfig
8. 再加载schema.xml封装为IndexSchema
9. 最后实例化SolrCore

下面具体通过代码详细分析启动过程:

先来看下init方法:

  @Override  public void init(FilterConfig config) throws ServletException  {    log.info("SolrDispatchFilter.init()");    try {      // web.xml configuration      this.pathPrefix = config.getInitParameter( "path-prefix" );      this.cores = createCoreContainer();      log.info("user.dir=" + System.getProperty("user.dir"));    }    catch( Throwable t ) {      // catch this so our filter still works      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");  }

其中主要的一行代码是调用createCoreContainer方法,从这个方法已经可以看出大致的流程:

  /**   * Override this to change CoreContainer initialization   * @return a CoreContainer to hold this server's cores   */  protected CoreContainer createCoreContainer() {    SolrResourceLoader loader = new SolrResourceLoader(SolrResourceLoader.locateSolrHome());    // 加载solrhome/solr.xml作为ConfigSolr    ConfigSolr config = loadConfigSolr(loader);    CoreContainer cores = new CoreContainer(loader, config);    cores.load();    return cores;  }
先看下第一句中的SolrResourceLoader.locateSolrHome(),这个方法看出获取solrhome的流程,先尝试JNDI,在尝试system property,最后使用默认地址:

  /**   * Finds the solrhome based on looking up the value in one of three places:   * <ol>   *  <li>JNDI: via java:comp/env/solr/home </li>   *  <li>The system property solr.solr.home </li>   *  <li>Look in the current working directory for a solr/ directory</li>   * </ol>   *   * The return value is normalized.  Normalization essentially means it ends in a trailing slash.   * @return A normalized solrhome   * @see #normalizeDir(String)   */  public static String locateSolrHome() {    String home = null;    // Try JNDI    try {      Context c = new InitialContext();      home = (String)c.lookup("java:comp/env/" +project+"/home");      log.info("Using JNDI solr.home: "+home );    } catch (NoInitialContextException e) {      log.info("JNDI not configured for "+ project+ " (NoInitialContextEx)");    } catch (NamingException e) {      log.info("No /"+project+"/home in JNDI");    } catch( RuntimeException ex ) {      log.warn("Odd RuntimeException while testing for JNDI: " + ex.getMessage());    }       // Now try system property    if( home == null ) {      String prop = project + ".solr.home";      home = System.getProperty(prop);      if( home != null ) {        log.info("using system property "+prop+ ": " + home );      }    }       // if all else fails, try    if( home == null ) {      home = project + '/';      log.info(project + " home defaulted to '" + home + "' (could not find system property or JNDI)" );    }    return normalizeDir( home );  }
之后实例化一个SolrResourceLoader,这个SolrResourceLoader的parents是ContextClassLoader,并且加载了./lib/下的文件:

  /**   * <p>   * This loader will delegate to the context classloader when possible,   * otherwise it will attempt to resolve resources using any jar files   * found in the "lib/" directory in the specified instance directory.   * </p>   *   * @param instanceDir - base directory for this resource loader, if null locateSolrHome() will be used.   * @see #locateSolrHome   */  public SolrResourceLoader( String instanceDir, ClassLoader parent, Properties coreProperties )  {    if( instanceDir == null ) {      this.instanceDir = SolrResourceLoader.locateSolrHome();      log.info("new SolrResourceLoader for deduced Solr Home: '{}'",               this. instanceDir);    } else{      this.instanceDir = normalizeDir(instanceDir );      log.info("new SolrResourceLoader for directory: '{}'",               this. instanceDir);    }       this. classLoader = createClassLoader (null, parent);    addToClassLoader("./lib/", null, true);    reloadLuceneSPI();    this.coreProperties = coreProperties;  }参数parent此时传的null,所以parent取的ContextClassLoader  /**   * Convenience method for getting a new ClassLoader using all files found   * in the specified lib directory.   */  static URLClassLoader createClassLoader(final File libDir, ClassLoader parent) {    if ( null == parent ) {      parent = Thread.currentThread().getContextClassLoader();    }    return replaceClassLoader(URLClassLoader. newInstance( new URL[0], parent),                              libDir, null);  }  /**   * Adds every file/dir found in the baseDir which passes the specified Filter   * to the ClassLoader used by this ResourceLoader.  This method <b>MUST</b>   * only be called prior to using this ResourceLoader to get any resources, otherwise   * it's behavior will be non -deterministic. You also have to {link @reloadLuceneSPI }   * before using this ResourceLoader.   *   * <p>This method will quietly ignore missing or non-directory <code> baseDir</code>   *  folder.   *   * @param baseDir base directory whose children (either jars or directories of   *                classes) will be in the classpath, will be resolved relative   *                the instance dir.   * @param filter The filter files must satisfy, if null all files will be accepted.   * @param quiet  Be quiet if baseDir does not point to a directory or if no file is   *               left after applying the filter.   */  void addToClassLoader( final String baseDir, final FileFilter filter, boolean quiet ) {    // 拼绝对路径    File base = FileUtils.resolvePath(new File(getInstanceDir()), baseDir );    if (base != null && base .exists() && base.isDirectory()) {      File[] files = base .listFiles(filter );      if (files == null || files. length == 0) {        if (!quiet) {          log.warn( "No files added to classloader from lib: "                   + baseDir + " (resolved as: " + base.getAbsolutePath() + ").");        }      } else {        this.classLoader = replaceClassLoader(classLoader, base , filter );      }    } else {      if (!quiet) {        log.warn("Can't find (or read) directory to add to classloader: "            + baseDir + " (resolved as: " + base.getAbsolutePath() + ").");      }    }  }<span style="font-family:Tahoma;font-size:18px;color:#e30000;"></span>
接着回到createCoreContainer里的loadConfigSolr,开始加载solr.xml:
  private ConfigSolr loadConfigSolr(SolrResourceLoader loader) {    String solrxmlLocation = System.getProperty( "solr.solrxml.location" , "solrhome");    if (solrxmlLocation == null || "solrhome".equalsIgnoreCase(solrxmlLocation))      return ConfigSolr. fromSolrHome(loader, loader.getInstanceDir());    if ("zookeeper".equalsIgnoreCase(solrxmlLocation)) {      String zkHost = System. getProperty("zkHost");      log.info("Trying to read solr.xml from " + zkHost);      if (StringUtils.isEmpty(zkHost))        throw new SolrException( ErrorCode. SERVER_ERROR,            "Could not load solr.xml from zookeeper: zkHost system property not set");      SolrZkClient zkClient = new SolrZkClient(zkHost, 30000);      try {        if (!zkClient. exists( "/solr.xml", true ))          throw new SolrException( ErrorCode. SERVER_ERROR, "Could not load solr.xml from zookeeper: node not found");        byte[] data = zkClient.getData( "/solr.xml", null , null, true );        return ConfigSolr. fromInputStream(loader, new ByteArrayInputStream(data));      } catch (Exception e) {        throw new SolrException( ErrorCode. SERVER_ERROR, "Could not load solr.xml from zookeeper" , e);      } finally {        zkClient.close();      }    }    throw new SolrException( ErrorCode. SERVER_ERROR,        "Bad solr.solrxml.location set: " + solrxmlLocation + " - should be 'solrhome' or 'zookeeper'");  }

在ConfigSolr.fromSolrHome()中加载:

  public static ConfigSolr fromSolrHome(SolrResourceLoader loader , String solrHome ) {    // 默认“solr.xml”    return fromFile( loader, new File(solrHome, SOLR_XML_FILE ));  }   public static ConfigSolr fromFile(SolrResourceLoader loader, File configFile) {    log.info("Loading container configuration from {}", configFile.getAbsolutePath());    InputStream inputStream = null;    try {      // solrhome/solr.xml不存在的话,看是不是zk中有,如果没有就用默认的DEF_SOLR_XML      if (!configFile.exists()) {         // 这个if里面的方法是根据zkHost和zkRun判断是否有zk,看注释5.0后要有变化        if (ZkContainer.isZkMode()) {          throw new SolrException(SolrException.ErrorCode .SERVER_ERROR,              "solr.xml does not exist in " + configFile.getAbsolutePath() + " cannot start Solr" );        }        log.info("{} does not exist, using default configuration", configFile.getAbsolutePath());        inputStream = new ByteArrayInputStream(ConfigSolrXmlOld.DEF_SOLR_XML .getBytes(Charsets.UTF_8));      } else {        // 这里的configFile是solrhome/solr.xml        inputStream = new FileInputStream(configFile);      }      return fromInputStream(loader , inputStream);    }    catch (Exception e) {      throw new SolrException(SolrException.ErrorCode .SERVER_ERROR,          "Could not load SOLR configuration", e);    }    finally {      IOUtils.closeQuietly(inputStream);    }  }  public static ConfigSolr fromInputStream(SolrResourceLoader loader , InputStream is) {    try {      ByteArrayOutputStream baos = new ByteArrayOutputStream();      ByteStreams.copy(is , baos);      String originalXml = IOUtils.toString( new ByteArrayInputStream(baos.toByteArray()), "UTF-8" );      ByteArrayInputStream dup = new ByteArrayInputStream(baos.toByteArray());      Config config = new Config( loader, null, new InputSource(dup), null, false );      return fromConfig (config, originalXml);    }    catch (Exception e) {      throw new SolrException(SolrException.ErrorCode .SERVER_ERROR, e);    }  }  public static ConfigSolr fromConfig(Config config , String originalXml) {    // 这里兼容了solr.xml的新旧两种格式    boolean oldStyle = ( config.getNode("solr/cores" , false ) != null);    return oldStyle ? new ConfigSolrXmlOld( config, originalXml)                    : new ConfigSolrXml( config);  }看看ConfigSolrXml的构造函数:  public ConfigSolrXml(Config config) {    super(config);    try {      // 校验旧格式的solr.xml,如果发现旧的格式抛SolrException      checkForIllegalConfig();      // 填充所有属性      fillPropMap();      config.substituteProperties();      coresLocator = new CorePropertiesLocator(getCoreRootDirectory());    }    catch (IOException e) {      throw new SolrException(SolrException.ErrorCode .SERVER_ERROR, e);    }  }
fillPropMap()中将所有solr.xml的属性填充到一个HashMap<CfgProp, String>中:propMap,到此就加载完了solr.xml,封装为了ConfigSolr。

(待续)

0 0
原创粉丝点击