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
- Solr4.7源码分析-启动篇(一)
- Solr4.7源码分析-启动篇之Solr Cloud(一)
- Solr4.7源码分析-启动篇(二)
- Solr4.7源码分析-启动篇(三)
- Solr4.7源码分析-启动篇(四)
- Solr4.7源码分析-启动篇之Solr Cloud(二)——solr选举机制
- solr4 facet 源码流程分析
- OFBIZ源码分析(一) 启动初始化篇
- Twemproxy源码分析(一)启动过程
- Dubbo源码分析(一)启动Provider
- netty源码分析(一)-启动
- mina3源码分析,启动过程分析(一)
- Amoeba源码分析一:启动过程分析
- Kubelet源码分析(一) 启动流程分析
- Nginx源码分析-启动初始化过程(一)
- Nginx源码分析---Nginx启动初始化过程(一)
- Nginx源码分析-启动初始化过程(一)
- Giraph源码分析(一) —— 启动ZooKeeper服务
- CloudSim介绍和使用
- Android中实现下拉刷新
- Java 面试问题
- linux中ps命令解析
- 理解maven的核心概念
- Solr4.7源码分析-启动篇(一)
- Linux配置VNC服务
- 《樊江关》_0
- 栈的顺序存储结构的实现
- JAXP解析XML
- uml类图中得集中重要的逻辑关系和实现
- cocos2d-x使用python脚本创建项目的简单方法
- 在ios中的Document中创建多级文件夹以及文件
- MYSQL explain详解