Dubbo

概念

Dubbo是一个分布式RPC中间件。RPC(Remote Procedure Call)

远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,

而不需要了解底层网络技术的协议。

spi(service provider interface)

是JDK内置的一种服务提供发现机制。其实也就是一种动态替换发现的机制。

eg:有个接口,想运行时动态的给它添加实现,这时只需要添加一个实现。

JAVA的spi机制

1、需要一个目录 META/service,置于ClassPath下面

2、目录下面放置一个配置文件

(1)文件名是要扩展的接口全名

(2)文件内部要为实现的接口实现类

(3)文件必须为UTF-8编码

eg:

配置文件的名字:接口或者抽象类的全名

配置文件的内容:里面是两个扩展的实现类的全名

com.spi.impl.TextHellocom.chaochao.spi.impl.ImageHello

3、使用方法,主要是ServiceLoad

(1)ServiceLoad.load(xx.class)

(2)ServiceLoad<HelloInterface> loads = ServiceLoad.load(HelloInterface.class)

4、把新加的实现,描述给JDK,让JDK知晓即可(通过修改一个文本文件)

DUBBO的SPI机制

基于java的spi机制,不同点

1、可以方便的获取某一个想要的扩展实现,Java的Spi机制是没有提供此功能的
2、对于扩展实现IOC依赖注入功能

eg: 接口A,实现者A1,A2

​ 接口B,实现者B1,B2

现在实现者A1含有setB()方法,会自动注入一个接口B的实现者,此时注入B1还是B2不得而知,这个时候其注入的是一个动态生成的接口B的实现者B$Adpative(可以理解为接口B的代理实现),改实现者可以根据传入参数的不同,自动引用B1或者B2来完成相应的功能。

3、对扩展采用装饰器模式进行功能增强,类似AOP实现的功能

装饰器模式:动态的给对象添加新的功能(提供了比继承更加有弹性的替代方案)

ExtensionLoder中含有一个静态变量,用于缓存所有的扩展加载实例


 ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();

以Protocol为例子

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

这里加载Protocol.class,就以Protocol.class为key,创建的ExtensionLoader为value存储到上述EXTENSION_LOADERS中

接着,ExtensionLoader实例是如何加载Protocol的实现类的:

1、先解析Protocol上的Extension注解的name,存至String cachedDefaultName属性中,作为默认的实现。

2、到类路径下的加载 MEATA-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol文件

ps:dubbo可以从以下路径去加载配置文件,在alibaba提供的源码中,是在META-INF/dubbo/internal下加载配置文件的

  • META-INF/dubbo/internal

  • META-INF/dubbo

  • META-INF/services

配置文件的名字:接口的全名

org.apache.dubbo.rpc.Protocol

配置文件的内容格式: 别名 = 接口扩展的全名

filter=org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=org.apache.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=org.apache.dubbo.rpc.support.MockProtocol

DUBBO的关键注解

@SPI : 作用在扩展点的接口上,表面该接口是一个扩展点。可以被Dubbo的ExtensionLoader加载。如果没有这个注解,ExtensionLoader调用会报异常,注解里面如果配置了参数,则表示默认的实现类别名。

@Adaptive: 作用在扩展接口的方法上,表示该方法是一个自适应方法。Dubbo在为扩展点生成自适应实例时,如果方法有@Adaptive注解,会为该方法生成对应的代码。方法内部会根据方法的参数,来决定使用哪个扩展。

设配类的作用是根据url.getProtocol()的值extName,去ExtensionLoader. getExtension( extName)选取具体的扩展点实现。

利用javasist生成设配类的条件

1)接口方法中必须至少有一个方法打上了@Adaptive注解

2)被@Adaptive 注解了的方法参数必须有URL类型参数或者有参数中存在getURL()方法。

Dubbo中SPI扩展机制详解 (源码详解)

http://cxis.me/2017/02/18/Dubbo%E4%B8%ADSPI%E6%89%A9%E5%B1%95%E6%9C%BA%E5%88%B6%E8%AF%A6%E8%A7%A3/

Dubbo的原理解析

https://blog.csdn.net/quhongwei_zhanqiu/article/details/41577235

类的初始化机制方法

类的加载:

1、通过一个类的全限定名来获取其定义的二进制字节流(由类加载器来完成);

这里的字节流并不只是单纯的从class文件获取,它还可以从jar、ear、war包,网络中获取(Applet),或者由其他文件(jsp)生成、运行时计算生成,最典型的是动态代理技术。

2、将class文件中的字节码读入内存,将其放在运行时数据区的方法区内;

3、最终在堆区中创建一个代表这个类的java.lang.Class对象,作为对方法区中对这些数据的访问入口。

一般来说,只有第一次主动调用某个类时才会去进行类加载。如果有一个类有父类,会先去加载其父类,然后再加载其本身。

类加载器:

对于任意一个类,都需要由它的类加载器和这个类的本身一同确定其在虚拟机中的唯一性,也就是说,即便两个类来源于同一个class文件,只要加载它们的类加载器不同,那么这两个类必定不相等。

虚拟机的角度:

1、启动类加载器:C++写的,它属于虚拟机的一部分

作用:负责将存放在<JAVA_HOME>/lib/re.jar目录下的核心类,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机按照文件名识别的类库加载到虚拟机内存中。

启动类加载器无法被java程序直接引用,用户在编写自定义类加载器时,如果需要把加载请求委派给引导类加载器,那就直接使用null代替即可。

JDK中常用的类基本都是由类加载器加载,如java.lang.String,java.util.List等。Main class也是由启动类加载器加载。

2、所有其他的类加载器:这些类加载器都由Java语言实现,独立于虚拟机之外,并且全部继承自抽象类java.lang.ClassLoader,

开发人员的角度:

1、启动类加载器(Bootstrap ClassLoader)

2、扩展类加载器(Extension ClassLoader)

sun.misc.Launcher$ExtClassLoader实现。

负责加载<JAVA_HOME>/lib/ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库。

开发者可以直接使用扩展类加载器

3、应用程序类加载器(Application ClassLoader)

sun.misc.Launcher$AppClassLoader实现。由于这个类加载器时ClassLoader.getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。

应用程序基本都是由以上三种类加载器互相配合进行加载的,如果有必要,我们还可以加入自定义的类加载器。

自定义类加载器(User ClassLoader)

类加载器的层级关系

启动类加载器

扩展类加载器

应用程序加载器

自定义加载器

类的验证

主要是保证类符合java语法规范,确保不会影响JVM的运行,包括但不限于

1、bytecode的完整性。

2、检查final类没有被继承,final方法有咩有被覆盖

3、确保没有不兼容的方法签名

类的准备

在这个阶段,JVM会为类成员变量(不包括实例变量)分配内存空间并且赋予默认初始值,需要注意的这个阶段不会执行任何代码,而只是根据变量类型决定初始值。如果不进行默认初始化,分配的空间的值值是随机的。

双亲委派机制

工作流程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载器请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。

example: 是

java.lang.ClassLoader的loadClass()方法中,先检查是否已经被加载过,若没有加载,则调用父类的加载器加载,若父类的加载器为空,则默认使用启动类加载器作为父类加载器,如果父类加载器失败,则抛出ClassNotFoundException异常,再调用自己的findClass()方法进行加载。

protected synchronized Class<?> loadClass(String name,boolean resolve)throws ClassNotFoundException{
//check the class has been loaded or not
Class c = findLoadedClass(name);
if(c == null){
    try{
        if(parent != null){
            c = parent.loadClass(name,false);
        }else{
            c = findBootstrapClassOrNull(name);
        }
    }catch(ClassNotFoundException e){
        //if throws the exception ,the father can not complete the load
    }
    if(c == null){
        c = findClass(name);
    }
}
if(resolve){
    resolveClass(c);
}
return c;
}

使用双亲委派模型来组织类加载器之间的关系,有一个好处

就是类随着它的类加载器(说白了,就是它所在的目录)一起具备了一种带有优先级的层级关系,这个对于保证JAVA程序的稳定运作很重要。

eg : java.lang.Object,它由启动类加载器加载。双亲委派模型保证任何类加载器收到的java.lang.Object的加载请求,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此,Object类在程序的各种类加载器环境中都是同一个类。

如果没有使用双亲委派模型,由各个类加载器自行去加载的话,会出现同一个类由不同的类加载器去加载,保证不了java的基本行为,容易引起混乱

自定义类加载器的正确姿势:1、继承ClassLoader

2、应当仅覆写ClassLoader #findClass()方法,以支持自定义类的加载方式。不建议覆写ClassLoader #loadClass()(以使用默认的来加载逻辑,即双亲委派模型);如果需要覆写,则不应该破坏双亲委派模型。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342