Solr4.8.0源码分析(2)之Solr的启动(一)
2014-08-13 23:57 追风的蓝宝 阅读(1660) 评论(0) 编辑 收藏 举报上文写到Solr的启动过程是在SolrDispatchFilter的init()里实现,当Tomcat启动时候会自动调用init();
Solr的启动主要在 this.cores = createCoreContainer();语句中实现。
/** *初始化,当tomcat启动时候开始初始化,其中主要调用createCoreContainer来实现Solr的初始化 */ 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"); }
Solr的启动过程主要包括:
1. 获取SolrHome:分别先后通过JNDI,System property,default directory三种方式尝试获取
2. 实例化启动过程中使用的类加载器SolrResourceLoader
3. 加载solrhome下的solr.xml文件,封装为ConfigSolr
4. 实例化一个CoreContainer,通过CoreContainer来加载cores
5. 遍历SolrHome,当寻找到含有core.properties的文件夹,则作为一个core
6. 多线程加载cores
7. 加载每个core时先加载solrconfig.xml封装为SolrConfig
8. 再加载schema.xml封装为IndexSchema
9. 最后实例化SolrCore
以下是createCoreContainer()实现代码,该函数就包含了以上的启动过程。
1 /** 2 * Override this to change CoreContainer initialization 3 * @return a CoreContainer to hold this server's cores 4 */ 5 protected CoreContainer createCoreContainer() { 6 SolrResourceLoader loader = new SolrResourceLoader(SolrResourceLoader.locateSolrHome()); 7 ConfigSolr config = loadConfigSolr(loader); 8 CoreContainer cores = new CoreContainer(loader, config); 9 cores.load(); 10 return cores; 11 }
1. 获取SolrHome信息
Solr通过三种方式来获取SolrHome,分别是JNDI,System property,以及当前路径。
JNDI的java:comp/env/solr/home的获取,主要通过在tomcat/conf/Catalina/localhost目录下新建solr.xml。Tomcat启动的时候就会该目录下自动获取 SolrHome的信息.
System property的SolrHome获取是直接在tomcat启动脚本catalina.sh中加入set JAVA_OPTS -Dsolr.solr.home=/Users/rcf/workspace/java/solr 。
最后的获取SolrHome的方式就是在当前目录下查找。
1 /** 2 * Determines the solrhome from the environment. 3 * Tries JNDI (java:comp/env/solr/home) then system property (solr.solr.home); 4 * if both fail, defaults to solr/ 5 * @return the instance directory name 6 */ 7 /** 8 * Finds the solrhome based on looking up the value in one of three places: 9 * <ol> 10 * <li>JNDI: via java:comp/env/solr/home</li> 11 * <li>The system property solr.solr.home</li> 12 * <li>Look in the current working directory for a solr/ directory</li> 13 * </ol> 14 * 15 * The return value is normalized. Normalization essentially means it ends in a trailing slash. 16 * @return A normalized solrhome 17 * @see #normalizeDir(String) 18 */ 19 public static String locateSolrHome() { 20 21 String home = null; 22 // Try JNDI 23 try { 24 Context c = new InitialContext(); 25 home = (String)c.lookup("java:comp/env/"+project+"/home"); 26 log.info("Using JNDI solr.home: "+home ); 27 } catch (NoInitialContextException e) { 28 log.info("JNDI not configured for "+project+" (NoInitialContextEx)"); 29 } catch (NamingException e) { 30 log.info("No /"+project+"/home in JNDI"); 31 } catch( RuntimeException ex ) { 32 log.warn("Odd RuntimeException while testing for JNDI: " + ex.getMessage()); 33 } 34 35 // Now try system property 36 if( home == null ) { 37 String prop = project + ".solr.home"; 38 home = System.getProperty(prop); 39 if( home != null ) { 40 log.info("using system property "+prop+": " + home ); 41 } 42 } 43 44 // if all else fails, try 45 if( home == null ) { 46 home = project + '/'; 47 log.info(project + " home defaulted to '" + home + "' (could not find system property or JNDI)"); 48 } 49 return normalizeDir( home ); 50 }
1 <Context docBase="/Users/rcf/workspace/java/tomcat/apache-tomcat-8.0.9/webapps/solr.war" debug="0" crossContext="true" > 2 <Environment name="solr/home" type="java.lang.String" value="/Users/rcf/workspace/java/solr" override="true" /> 3 </Context>
获取完SolrHome后,就会实例化SolrResourceLoader。因为传进去的parent是null,所以parents是ContextClassLoader,并且加载了SolrHome/lib/下的文件.
1 /** 2 * <p> 3 * This loader will delegate to the context classloader when possible, 4 * otherwise it will attempt to resolve resources using any jar files 5 * found in the "lib/" directory in the specified instance directory. 6 * </p> 7 * 8 * @param instanceDir - base directory for this resource loader, if null locateSolrHome() will be used. 9 * @see #locateSolrHome 10 */ 11 public SolrResourceLoader( String instanceDir, ClassLoader parent, Properties coreProperties ) 12 { 13 if( instanceDir == null ) { 14 this.instanceDir = SolrResourceLoader.locateSolrHome(); 15 log.info("new SolrResourceLoader for deduced Solr Home: '{}'", 16 this.instanceDir); 17 } else{ 18 this.instanceDir = normalizeDir(instanceDir); 19 log.info("new SolrResourceLoader for directory: '{}'", 20 this.instanceDir); 21 } 22 23 this.classLoader = createClassLoader(null, parent); 24 addToClassLoader("./lib/", null, true); 25 reloadLuceneSPI(); 26 this.coreProperties = coreProperties; 27 }
1 /** 2 * Convenience method for getting a new ClassLoader using all files found 3 * in the specified lib directory. 4 */ 5 static URLClassLoader createClassLoader(final File libDir, ClassLoader parent) { 6 if ( null == parent ) { 7 parent = Thread.currentThread().getContextClassLoader(); 8 } 9 return replaceClassLoader(URLClassLoader.newInstance(new URL[0], parent), 10 libDir, null); 11 }
1 /** 2 * Adds every file/dir found in the baseDir which passes the specified Filter 3 * to the ClassLoader used by this ResourceLoader. This method <b>MUST</b> 4 * only be called prior to using this ResourceLoader to get any resources, otherwise 5 * it's behavior will be non-deterministic. You also have to {link @reloadLuceneSPI} 6 * before using this ResourceLoader. 7 * 8 * <p>This method will quietly ignore missing or non-directory <code>baseDir</code> 9 * folder. 10 * 11 * @param baseDir base directory whose children (either jars or directories of 12 * classes) will be in the classpath, will be resolved relative 13 * the instance dir. 14 * @param filter The filter files must satisfy, if null all files will be accepted. 15 * @param quiet Be quiet if baseDir does not point to a directory or if no file is 16 * left after applying the filter. 17 */ 18 void addToClassLoader(final String baseDir, final FileFilter filter, boolean quiet) { 19 File base = FileUtils.resolvePath(new File(getInstanceDir()), baseDir); 20 if (base != null && base.exists() && base.isDirectory()) { 21 File[] files = base.listFiles(filter); 22 if (files == null || files.length == 0) { 23 if (!quiet) { 24 log.warn("No files added to classloader from lib: " 25 + baseDir + " (resolved as: " + base.getAbsolutePath() + ")."); 26 } 27 } else { 28 this.classLoader = replaceClassLoader(classLoader, base, filter); 29 } 30 } else { 31 if (!quiet) { 32 log.warn("Can't find (or read) directory to add to classloader: " 33 + baseDir + " (resolved as: " + base.getAbsolutePath() + ")."); 34 } 35 } 36 }