服务器网站过多对排名,wordpress移动端模板,动漫网站html,海尔商务网站建设加载机制中已经存在的一些关键注解#xff0c;如SPI、Adaptive Activateo然后介绍整个加载机制中最核心的ExtensionLoader的工作流程及实现原理。最后介绍扩展中使用的类动态编译的实 现原理。
Java SPI
Java 5 中的服务提供商https://docs.oracle.com/jav… 加载机制中已经存在的一些关键注解如SPI、©Adaptive ©Activateo然后介绍整个加载机制中最核心的ExtensionLoader的工作流程及实现原理。最后介绍扩展中使用的类动态编译的实 现原理。
Java SPI
Java 5 中的服务提供商https://docs.oracle.com/javase/1.5.0/docs/guide/jar/jar.html#Service%20Provider SPI 插件扩展点使用手册
https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/reference-manual/spi/ JDK标准的SPI会一次性实例化扩展点所有实现如果有扩展实现则初始化很耗时如果没 用上也加载则浪费资源。 如果扩展加载失败则连扩展的名称都蕤取不到了。比如JDK标准的ScriptEngine,通过 getName ()获取脚本类型的名称如果RubyScriptEngine因为所依赖的j ruby .jar不存在导致 RubyScriptEngine类加载失败这个失败原因被“吃掉” 了和Ruby对应不起来当用户 执行Ruby脚本时会报不支持Ruby,而不是真正失败的原因。 增加了对扩展IoC和AOP的支持一个扩展可以直接setter注入其他扩展。在Java SPI的使 用示例章节(代码清单4-1 )中已经看到java.util.ServiceLoader会一次把Printservice 接口下的所有实现类全部初始化用户直接调用即可oDubbo SPI只是加载配置文件中的类 并分成不同的种类缓存在内存中而不会立即全部初始化在性能上有更好的表现。 ProtocolFilterWrapper 是 Dubbo 框架中的一个核心类用于在服务提供者和消费者之间添加过滤器链。ProtocolFilterWrapper 通过 Activate 注解来确定哪些过滤器适用于当前的 URL。以下是 ProtocolFilterWrapper 确定过滤器适用当前 URL 的详细过程 1. ProtocolFilterWrapper 类 ProtocolFilterWrapper 是一个装饰器模式的实现它包装了一个 Protocol 实例并在其上添加了过滤器链。以下是 ProtocolFilterWrapper 的主要逻辑
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.rpc.Exporter;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Protocol;public class ProtocolFilterWrapper implements Protocol {private final Protocol protocol;public ProtocolFilterWrapper(Protocol protocol) {this.protocol protocol;}Overridepublic int getDefaultPort() {return protocol.getDefaultPort();}Overridepublic ExporterT export(ExporterT exporter) {return new InvokerDelegator(wrapInvoker(exporter.getInvoker()), exporter);}Overridepublic T InvokerT refer(ClassT type, URL url) {return wrapInvoker(protocol.refer(type, url));}private T InvokerT wrapInvoker(InvokerT invoker) {URL url invoker.getUrl();// 获取所有激活的过滤器ListFilter filters ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(url, Constants.KEYS, Constants.DEFAULT_KEY);if (filters.size() 0) {return invoker;}return new FilterChainWrapper(invoker, filters);} SPI 提供商可以调用 ExtensionLoader.getActivateExtension(URL, String, String) 以查找具有给定条件的所有已激活的扩展。而getActivateExtension 会间接调用 com.alibaba.dubbo.common. extension.ExtensionLoader#loadExtensionClasses 其中 Type 是 由 ExtensionLoader.getExtensionLoader(Filter.class)决定为 Filter.
L565 - 567 就是解析 Filter 的接口上SPI注解信息.Filter.class 也可以替换成其他的类性
com.alibaba.dubbo.common.extension.ExtensionLoader#loadDirectory 会间接调用 com.alibaba.dubbo.common.extension.ExtensionLoader#loadClass
在此方法中会解析注解Adaptive、Activate /*** param extensionClasses ExtensionLoader#cachedClasses 成员变量* param resourceURL* param clazz ExtensionLoader#loadResource 中 加载 Class.forName( 类全限定名 )* param name ExtensionLoader#loadResource 中 在配置文件中设置的别名* 上两参数请参考 com.alibaba.dubbo.common.extension.SPI* throws NoSuchMethodException*/private void loadClass(MapString, Class? extensionClasses, java.net.URL resourceURL, Class? clazz, String name) throws NoSuchMethodException {if (!type.isAssignableFrom(clazz)) {throw new IllegalStateException(Error when load extension class(interface: type , class line: clazz.getName() ), class clazz.getName() is not subtype of interface.);}if (clazz.isAnnotationPresent(Adaptive.class)) {// 由于调用者 ExtensionLoader.loadResource 循环调用了 loadClass 如果类上标注了 Adaptive 注解则该类为 Adaptive 类并且只能有一个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 if (isWrapperClass(clazz)) {// 判断为 包装类,则维护到 ExtensionLoader.cachedWrapperClassesSetClass? wrappers cachedWrapperClasses;if (wrappers null) {cachedWrapperClasses new ConcurrentHashSetClass?();wrappers cachedWrapperClasses;}wrappers.add(clazz);} else {clazz.getConstructor();if (name null || name.length() 0) {// 如果没有名字则尝试扫描 Extension 注解 Extension 注解已经弃用了name findAnnotationName(clazz);if (name.length() 0) {throw new IllegalStateException(No such extension name for the class clazz.getName() in the config resourceURL);}}// 将首个类上Activate 信息维护到 ExtensionLoader.cachedActivates 中// 将 别名 维护到 ExtensionLoader.cachedNames 中// 将 别名类 维护到 ExtensionLoader#cachedClasses 中String[] names NAME_SEPARATOR.split(name);if (names ! null names.length 0) {Activate activate clazz.getAnnotation(Activate.class);if (activate ! null) {cachedActivates.put(names[0], activate);}for (String n : names) {if (!cachedNames.containsKey(clazz)) {cachedNames.put(clazz, n);}Class? c extensionClasses.get(n);if (c null) {extensionClasses.put(n, clazz);} else if (c ! clazz) {throw new IllegalStateException(Duplicate extension type.getName() name n on c.getName() and clazz.getName());}}}}} 工作流程 框架读取SPI对应路径下的配置文件并根据配置加载所有扩展类并缓存(不初始化)。根据传入的名称初始化对应的扩展类。尝试查找符合条件的包装类包含扩展点的setter方法返回对应的扩展类实例。 getAdaptiveExtension也相对独立只有加载配置信息部分与getExtension共用了同一个 方法。和获取普通扩展类一样框架会先检查缓存中是否有已经初始化化好的Adaptive实例 没有则调用createAdaptiveExtension重新初始化。初始化过程分为4步 和getExtension 一样先加载配置文件。
生成自适应类的代码字符串。 获取类加载器和编译器并用编译器编译刚才生成的代码字符串。Dubbo 一共有三种 类型的编译器实现。返回对应的自适应类实例。
getExtension 的实现原理
ExtensionLoader#getExtension 会调用ExtensionLoader#createExtension 方法 /*** 创建扩展实例* param name 别名* return*/private T createExtension(String name) {Class? clazz getExtensionClasses().get(name);if (clazz null) {throw findException(name);}try {// 先尝试从缓存中获取实例T instance (T) EXTENSION_INSTANCES.get(clazz);if (instance null) {// 不存在的话则通过反射创建实例EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());instance (T) EXTENSION_INSTANCES.get(clazz);}// 反射执行 setter 方法injectExtension(instance);SetClass? wrapperClasses cachedWrapperClasses;if (wrapperClasses ! null !wrapperClasses.isEmpty()) {// 检查是否有包装类for (Class? wrapperClass : wrapperClasses) {// 通过反射创建包装类实例,再执行包装实例的 setter 方法, 最后更新包装类实例// 这里我们能看出 包装类需要 实现 接口并且包装类需要有一个构造函数构造参数是接口类型instance injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));}}return instance;} catch (Throwable t) {throw new IllegalStateException(Extension instance(name: name , class: type ) could not be instantiated: t.getMessage(), t);}}
getAdaptiveExtension 的实现原理 在getAdaptiveExtension()方法中会为扩展点接口自动生成实现类字符串实现类主要包含以下逻辑为接口中每个有^Adaptive注解的方法生成默实现(没有注解的方法则生成空实现)每个默认实现都会从URL中提取Adaptive参数值并以此为依据动态加载扩展点。然后框架会使用不同的编译器把实现类字符串编译为自适应类并返回。 生成完代码之后就要对代码进行编译生成一个新的Classo Dubbo中的编译器也是一个自 适应接口但Adaptive注解是加在实现类AdaptiveCompiler上的。这样一来AdaptiveCompiler 就会作为该自适应类的默认实现不需要再做代码生成和编译就可以使用了。 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);}
// TODO 待续