ディレクトリ
- 概説原則
- なぜデザイン@Adaptiveコメント
- 使用にソースコードを配置ダボは、特定の方法を反映するようにすると
- @Adaptive拡張ローディングプロセスのソースコード解析
- 概要
概説原則
まず、公式サイトの適応拡大の次の説明を見て:
ダボでは、多くはそのようなプロトコル、クラスタ、ロードバランスなどなどSPIメカニズムを通して展開ロードされます。時には、いくつかの拡張は、スタートアップ段階の枠組みの中でロードされたくないが、我々は、メソッドが呼び出されたときに拡大することを願って、ベースの実行時パラメータをロードしました。これは、やや矛盾して聞こえるかもしれません。拡張は、(静的メソッドを除く)と呼ばれることができない方法を拡張し、ロードされていません。拡張メソッドは、それがロードすることはできません拡大し、呼び出されません。この矛盾した問題については、良い解決策を拡大するための適応機構を介してダボ。ロジックを実装する適応型拡張機構は、インタフェースを拡張するためにプロキシ機能ダボ生成される最初のコードを有する、より複雑です。Javassistのは、コードをコンパイルするJDKまたはクラスのクラスを取得します。最後に、反射、より複雑なプロセス全体でプロキシクラスを作成します。
まだ少し抽象思われるもの、SPI下ダボ最初のレビューです:SPIが拡張メカニズムで、目的は、オブジェクトを取得することです。ExtensionLoader.getExtension(文字列名)、)によって得られたそれの適応特定のクラスのこの拡張に適応する方法を、ExtensionLoader.getAdaptiveExtension(によって拡張されたクラスを取得し、見下し続けます
ソースの定義を見@Adaptive注釈は、注釈は、これはメソッドやクラスで使用できることがわかります
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Adaptive {
String[] value() default {};
}
なぜデザイン@Adaptiveコメント
適応注釈のデザインは、クラスをコーディング人工を区別することで、動的に生成します
アノテーションクラスは、動的プロキシクラスを生成するために人工的なエンコードされ、不要の論理的な拡張を表す場合(Javaプログラムのソースコードファイルが既に存在に相当する);ダボに、2つだけのクラスは適応、それぞれAdaptiveCompiler注釈されていますそしてAdaptiveExtensionFactory; AdaptiveCompiler JavassistCompiler実装クラスと2つだけJdkCompiler; AdaptiveExtensionFactoryは、2つのクラスだけ、SpiExtensionFactoryとSpringExtensionFactoryを達成しました。
注釈インターフェース方法は、論理が(動的に起動した後に生成された文字列の連結などの対応するJavaファイル、ローディングコンパイル)自動的に生成された拡張て表現フレームを示し、例えばプロトコルインターフェース実装クラスDubboProtocol、InjvmProtocol、HttpProtcol等を有しています
以降AdaptiveCompilerプロトコルは、例として、ローディングプロセスの展開を分析するであろう
使用にソースコードを配置ダボは、特定の方法を反映するようにすると
最も基本的な分析のXML設定ファイルからスタートしましょう:
<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"/>
その解決DubboNamespaceHandler spring.handlersから
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
}
}
registerBeanDefinitionParser(「サービス」、新DubboBeanDefinitionParserから (ServiceBean.class、真)); 添字サービスを解析すること
ServiceBeanに対応するオブジェクトに署名するとき、ServiceBeanはServiceConfigを継承しました
public class ServiceConfig<T> extends AbstractServiceConfig {
private static final long serialVersionUID = 3033787999037024738L;
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();
private final List<URL> urls = new ArrayList<URL>();
private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
2 ServiceConfig静的初期化があります
ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension()は、
ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
ここでは次のプロトコルに使用される適応分析ロードを拡張
@Adaptive拡張ローディングプロセスのソースコード解析
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
このライン上のブレークポイントをヒットは、最初getAdaptiveExtension()メソッドの入力
コードブロック1.1
public T getAdaptiveExtension() {
//先从缓存中找
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError == null) {
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//第一次进来缓存中没有,会到这里
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
}
}
}
} else {
throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
}
}
return (T) instance;
}
キャッシュ・ルックアップが作成されていない既存の、createAdaptiveExtension()入力
コード・ブロック2.1
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
}
}
injectExtension()、記事がされているが言ったときにIOCダボ実現;
見てみましょうgetAdaptiveExtensionClass()メソッド:
ブロック3.1
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
getExtensionClasses();このメソッドは、非常に重要であり、読み取り主に、拡張されたエイリアス名と完全クラス名を取得するためにMET-INF /ダボ/内部ディレクトリを設定する際に、同じクラスにありかどうか@Adaptiveコメントを決定し、キャッシュ変数cachedAdaptiveClassを追加する必要がありましたコード、ノートの以下の部分で:@Adaptiveは注釈を追加、このクラスのキャッシュとクラスの前にに置かれ
たコードブロック4.1
if (clazz.isAnnotationPresent(Adaptive.class)) {
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException("More than 1 adaptive class found: "
+ cachedAdaptiveClass.getClass().getName()
+ ", " + clazz.getClass().getName());
}
} else {
:バックgetAdaptiveExtensionClass()メソッドは、このcachedAdaptiveClassが空である次のように、それはcreateAdaptiveExtensionClass()メソッドを実行する
コードブロック4.2
private Class<?> createAdaptiveExtensionClass() {
String code = createAdaptiveExtensionClassCode();
ClassLoader classLoader = findClassLoader();
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
ライン分析によって行:
列= createAdaptiveExtensionClassCodeコード();
このコードは、プロトコル$ Adaptice生産の文字列を連結することによってオブジェクト、この方法で、以前のコメント、オブジェクトに反映適応拡張は、次の通り前記の場合です。
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
}
URL値を渡さない場合、値がパスを渡された場合、デフォルト値のダボで本当に適応、ここに反映需要の負荷特定の実現、EXTNAME、。
4.2バックは、このラインをブロックします
com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
ここで見つけるとgetAdaptiveExtension()メソッド、サイクル呼び出しを呼び出しますか?ここでは上記の言った@Adaptive負荷クラスのノートの状況があり、この時間は、動的なクラスを生成する必要はありません
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
この方法は、cachedAdaptiveClassに再び呼び出されたときに空ではない、サイクルを終了するには、直接返されます。
注:別の拡張子をロードするたびにExtensionLoaderの新しいインスタンスを使用しています
概要
この記事では、どのような適応的な拡張メカニズム、および目的@Adaptiveデザインだけでなく、アプローチやクラスのノートの違いの話、およびソースコードがどのように達成するかを解析します。
ここで適応@Adaptive原理は、SPIとAdaptive原則ダボソースはユビキタス使用ExtensionLoaderのソースと理解しなければならないかどうかを確認するために、終了しました。