设为首页 收藏本站
查看: 1402|回复: 0

[经验分享] Solr4.8.0源码分析(7)之Solr SPI

[复制链接]

尚未签到

发表于 2015-7-17 07:53:55 | 显示全部楼层 |阅读模式
Solr4.8.0源码分析(7)之Solr SPI
  查看Solr源码时候会发现,每一个package都会由对应的resources. 如下图所示:
DSC0000.png
  一时对这玩意好奇了,看了文档以后才发现,这个services就是java SPI机制。首先介绍下java SPI机制,然后再结合Solr谈一下SPI。

1. JAVA SPI
  当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
  基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。
  jdk提供服务实现查找的一个工具类:java.util.ServiceLoader
  假设有一个内容搜索系统,分为展示和搜索两个模块。展示和搜索基于接口编程。搜索的实现可能是基于文件系统的搜索,也可能是基于数据库的搜索。实例代码如下:
  Search.java: 搜索接口



1 package search;
2
3 import java.util.List;
4
5 import definition.Doc;
6
7 public interface Search {
8     List search(String keyword);
9 }
  FileSearch.java:文件系统的搜索实现



1 package search;
2
3 import java.util.List;
4
5 import definition.Doc;
6
7 public class FileSearch implements Search {
8
9     @Override
10     public List search(String keyword) {
11         System.out.println("now use file system search. keyword:" + keyword);
12         return null;
13     }
14
15 }
  DatabaseSearch.java



1 package search;
2
3 import java.util.List;
4
5 import definition.Doc;
6
7 public class DatabaseSearch implements Search {
8
9     @Override
10     public List search(String keyword) {
11         System.out.println("now use database search. keyword:" + keyword);
12         return null;
13     }
14
15 }
  SearchTest.java



1 package search;
2
3 import java.util.Iterator;
4 import java.util.ServiceLoader;
5
6 public class SearchTest {
7
8     public static void main(String[] args) {
9         ServiceLoader s = ServiceLoader.load(Search.class);
10         Iterator searchs = s.iterator();
11         if (searchs.hasNext()) {
12             Search curSearch = searchs.next();
13             curSearch.search("test");
14         }
15     }
16 }
  最后创建在META-INF/searvices/search.Search文件。
  当search.Search文件内容是"search.FileSearch"时,程序输出是:
  now use file system search. keyword:test
  当search.Search文件内容是"search.DatabaseSearch"时,程序输出是:
  now use database search. keyword:test
可以看出SearchTest里没有任何和具体实现有关的代码,而是基于spi的机制去查找服务的实现。
  

2. Solr SPI
  以Codec类为例,查看resources/META-INF/services/org.apache.lucene.codecs.Codec:可以看出Codec服务接口具有以下具体的实现类。这就很好的解释了Solrconfig.xml里面的LuceneVersion的配置,也为Lucene的向前兼容提供了保障。



1 #  Licensed to the Apache Software Foundation (ASF) under one or more
2 #  contributor license agreements.  See the NOTICE file distributed with
3 #  this work for additional information regarding copyright ownership.
4 #  The ASF licenses this file to You under the Apache License, Version 2.0
5 #  (the "License"); you may not use this file except in compliance with
6 #  the License.  You may obtain a copy of the License at
7 #
8 #       http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #  Unless required by applicable law or agreed to in writing, software
11 #  distributed under the License is distributed on an "AS IS" BASIS,
12 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 #  See the License for the specific language governing permissions and
14 #  limitations under the License.
15
16 org.apache.lucene.codecs.lucene40.Lucene40Codec
17 org.apache.lucene.codecs.lucene3x.Lucene3xCodec
18 org.apache.lucene.codecs.lucene41.Lucene41Codec
19 org.apache.lucene.codecs.lucene42.Lucene42Codec
20 org.apache.lucene.codecs.lucene45.Lucene45Codec
21 org.apache.lucene.codecs.lucene46.Lucene46Codec
  接下来可以看下Codec服务接口的实现代码



  1 package org.apache.lucene.codecs;
  2
  3 /*
  4  * Licensed to the Apache Software Foundation (ASF) under one or more
  5  * contributor license agreements.  See the NOTICE file distributed with
  6  * this work for additional information regarding copyright ownership.
  7  * The ASF licenses this file to You under the Apache License, Version 2.0
  8  * (the "License"); you may not use this file except in compliance with
  9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.util.Set;
21 import java.util.ServiceLoader; // javadocs
22
23 import org.apache.lucene.index.IndexWriterConfig; // javadocs
24 import org.apache.lucene.util.NamedSPILoader;
25
26 /**
27  * Encodes/decodes an inverted index segment.
28  *
29  * Note, when extending this class, the name ({@link #getName}) is
30  * written into the index. In order for the segment to be read, the
31  * name must resolve to your implementation via {@link #forName(String)}.
32  * This method uses Java's
33  * {@link ServiceLoader Service Provider Interface} (SPI) to resolve codec names.
34  *
35  * If you implement your own codec, make sure that it has a no-arg constructor
36  * so SPI can load it.
37  * @see ServiceLoader
38  */
39 public abstract class Codec implements NamedSPILoader.NamedSPI {
40   
41   private static final NamedSPILoader loader =
42     new NamedSPILoader(Codec.class);
43
44   private final String name;
45
46   /**
47    * Creates a new codec.
48    *
49    * The provided name will be written into the index segment: in order to
50    * for the segment to be read this class should be registered with Java's
51    * SPI mechanism (registered in META-INF/ of your jar file, etc).
52    * @param name must be all ascii alphanumeric, and less than 128 characters in length.
53    */
54   protected Codec(String name) {
55     NamedSPILoader.checkServiceName(name);
56     this.name = name;
57   }
58   
59   /** Returns this codec's name */
60   @Override
61   public final String getName() {
62     return name;
63   }
64   /**
65    * 以下几个Format跟Lucene的索引文件格式有关
66    * */
67   /** Encodes/decodes postings */
68   public abstract PostingsFormat postingsFormat();
69
70   /** Encodes/decodes docvalues */
71   public abstract DocValuesFormat docValuesFormat();
72   
73   /** Encodes/decodes stored fields */
74   public abstract StoredFieldsFormat storedFieldsFormat();
75   
76   /** Encodes/decodes term vectors */
77   public abstract TermVectorsFormat termVectorsFormat();
78   
79   /** Encodes/decodes field infos file */
80   public abstract FieldInfosFormat fieldInfosFormat();
81   
82   /** Encodes/decodes segment info file */
83   public abstract SegmentInfoFormat segmentInfoFormat();
84   
85   /** Encodes/decodes document normalization values */
86   public abstract NormsFormat normsFormat();
87
88   /** Encodes/decodes live docs */
89   public abstract LiveDocsFormat liveDocsFormat();
90   
91   /**
92    * 根据名字在已有的Codec实例中寻找符合
93    * */
94   /** looks up a codec by name */
95   public static Codec forName(String name) {
96     if (loader == null) {
97       throw new IllegalStateException("You called Codec.forName() before all Codecs could be initialized. "+
98           "This likely happens if you call it from a Codec's ctor.");
99     }
100     return loader.lookup(name);
101   }
102   
103   /**
104    * 返回有效的Codecs实例
105    * */
106   /** returns a list of all available codec names */
107   public static Set availableCodecs() {
108     if (loader == null) {
109       throw new IllegalStateException("You called Codec.availableCodecs() before all Codecs could be initialized. "+
110           "This likely happens if you call it from a Codec's ctor.");
111     }
112     return loader.availableServices();
113   }
114   
115   /**
116    * 更新Codec实例列表,Codec实例列表只能添加,不能删除与更改。
117    * */
118   /**
119    * Reloads the codec list from the given {@link ClassLoader}.
120    * Changes to the codecs are visible after the method ends, all
121    * iterators ({@link #availableCodecs()},...) stay consistent.
122    *
123    * NOTE: Only new codecs are added, existing ones are
124    * never removed or replaced.
125    *
126    * This method is expensive and should only be called for discovery
127    * of new codecs on the given classpath/classloader!
128    */
129   public static void reloadCodecs(ClassLoader classloader) {
130     loader.reload(classloader);
131   }
132   
133   /**
134    * 默认为Lucene46,也就是说默认调用的是org.apache.lucene.codecs.lucene46.Lucene46Codec
135    * */
136   private static Codec defaultCodec = Codec.forName("Lucene46");
137   
138   /**
139    * 返回默认的Codec实例
140    * */
141   /** expert: returns the default codec used for newly created
142    *  {@link IndexWriterConfig}s.
143    */
144   // TODO: should we use this, or maybe a system property is better?
145   public static Codec getDefault() {
146     return defaultCodec;
147   }
148   
149   /**
150    * 设置默认的Codec实例
151    * */
152   /** expert: sets the default codec used for newly created
153    *  {@link IndexWriterConfig}s.
154    */
155   public static void setDefault(Codec codec) {
156     defaultCodec = codec;
157   }
158
159   /**
160    * returns the codec's name. Subclasses can override to provide
161    * more detail (such as parameters).
162    */
163   @Override
164   public String toString() {
165     return name;
166   }
167 }
  代码比较简单明了,接下来再看下NamedSPILoader.NamedSPI,它封装了JAVA SPI的实现:



  1 package org.apache.lucene.util;
  2
  3 /*
  4  * Licensed to the Apache Software Foundation (ASF) under one or more
  5  * contributor license agreements.  See the NOTICE file distributed with
  6  * this work for additional information regarding copyright ownership.
  7  * The ASF licenses this file to You under the Apache License, Version 2.0
  8  * (the "License"); you may not use this file except in compliance with
  9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.util.Collections;
21 import java.util.Iterator;
22 import java.util.Map;
23 import java.util.LinkedHashMap;
24 import java.util.Set;
25 import java.util.ServiceConfigurationError;
26
27 /**
28  * Helper class for loading named SPIs from classpath (e.g. Codec, PostingsFormat).
29  * @lucene.internal
30  */
31 public final class NamedSPILoader implements Iterable {
32
33   /**
34    * SPI service Map,存放服务对应的实例类。
35    * */
36   private volatile Map services = Collections.emptyMap();
37   private final Class clazz;
38
39   public NamedSPILoader(Class clazz) {
40     this(clazz, Thread.currentThread().getContextClassLoader());
41   }
42   
43   public NamedSPILoader(Class clazz, ClassLoader classloader) {
44     this.clazz = clazz;
45     // if clazz' classloader is not a parent of the given one, we scan clazz's classloader, too:
46     final ClassLoader clazzClassloader = clazz.getClassLoader();
47     if (clazzClassloader != null && !SPIClassIterator.isParentClassLoader(clazzClassloader, classloader)) {
48       reload(clazzClassloader);
49     }
50     reload(classloader);
51   }
52   
53   /**
54    * 更新SPI MAP services。遍历META-INF/services文件,如果services MAP没有该实例,则新建实例,并放入services MAP
55    * */
56   /**
57    * Reloads the internal SPI list from the given {@link ClassLoader}.
58    * Changes to the service list are visible after the method ends, all
59    * iterators ({@link #iterator()},...) stay consistent.
60    *
61    * NOTE: Only new service providers are added, existing ones are
62    * never removed or replaced.
63    *
64    * This method is expensive and should only be called for discovery
65    * of new service providers on the given classpath/classloader!
66    */
67   public synchronized void reload(ClassLoader classloader) {
68     final LinkedHashMap services = new LinkedHashMap(this.services);
69     final SPIClassIterator loader = SPIClassIterator.get(clazz, classloader);
70     while (loader.hasNext()) {
71       final Class

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-87419-1-1.html 上篇帖子: solr性能调优 下篇帖子: 关于 solr solrconfig.xml 的配置说明
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表