1. 程式人生 > >dubbo原始碼分析之動態編譯

dubbo原始碼分析之動態編譯

我們執行的Java程式碼,都是編譯之後的位元組碼,dubbo為了實現了基於spi思想的擴充套件特性,特別是能夠靈活新增額外功能。dubbo作為一個高擴充套件性的框架,使的使用者能夠新增自己的需求,根據配置動態生成自己的設配類程式碼,這樣就需要在執行的時候去編譯載入這個設配類的程式碼。下面我們就是來了解下Dubbo的動態編譯。

這裡寫圖片描述

編譯介面定義

@SPI("javassist")
public interface Compiler {

    /**
     * Compile java source code.
     *
     * @param code        Java source code
     * @param
classLoader classloader * @return Compiled class */
Class<?> compile(String code, ClassLoader classLoader); }

dubbo預設選用javassist編譯原始碼,介面方法compile第一入參是code,代表Java原始碼,第二個入參classLoader,代表載入編譯後的位元組碼的類載入器,根據當前執行緒或呼叫方classLoader載入的

@Adaptive註解在標註@SPI介面的實現類上,擴充套件類就是這個類。

例如這裡的Compiler的SPI擴充套件就是AdaptiveCompiler這個類。AdaptiveCompiler是Compiler的設配類, 它有類註解@Adaptive表示這個Compiler的設配類不是動態編譯生成的。AdaptiveCompiler作用就是策略的選擇,根據條件選擇何種編譯策略來編譯動態生成的原始碼。預設為javassist.

//@Adaptive表示這個Compiler的設配類不是動態編譯生成的
@Adaptive
public class AdaptiveCompiler implements Compiler {

    private static volatile String DEFAULT_COMPILER;

    public static void setDefaultCompiler(String compiler) {
        DEFAULT_COMPILER = compiler;
    }

    @Override
    public Class<?> compile
(String code, ClassLoader classLoader) { Compiler compiler; ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class); String name = DEFAULT_COMPILER; // copy reference if (name != null && name.length() > 0) { compiler = loader.getExtension(name); } else { compiler = loader.getDefaultExtension(); } return compiler.compile(code, classLoader); } }

AbstractCompiler是一個抽象類,它通過正則表示式獲取到物件的包名以及Class名稱。這樣就可以獲取物件的全類名(包名+Class名稱)。通過反射Class.forName()來判斷當前ClassLoader是否有這個類,如果有就返回,如果沒有就通過JdkCompiler或者JavassistCompiler通過傳入的code編譯這個類。

public abstract class AbstractCompiler implements Compiler {
    //通過正則表示式獲取到物件的包名以及Class名稱。
    private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");

    private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");

    @Override
    public Class<?> compile(String code, ClassLoader classLoader) {
        code = code.trim();
        Matcher matcher = PACKAGE_PATTERN.matcher(code);
        String pkg;
        if (matcher.find()) {
            pkg = matcher.group(1);
        } else {
            pkg = "";
        }
        matcher = CLASS_PATTERN.matcher(code);
        String cls;
        if (matcher.find()) {
            cls = matcher.group(1);
        } else {
            throw new IllegalArgumentException("No such class name in " + code);
        }
       // 獲取物件的全類名(包名+Class名稱)
        String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls;
        try {
           //通過反射Class.forName()來判斷當前ClassLoader是否有這個類,如果有就返回
            return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
        } catch (ClassNotFoundException e) {
            if (!code.endsWith("}")) {
                throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
            }
            try {
            //如果沒有就通過JdkCompiler或者JavassistCompiler通過傳入的code編譯這個類。
                return doCompile(className, code);
            } catch (RuntimeException t) {
                throw t;
            } catch (Throwable t) {
                throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
            }
        }
    }

    protected abstract Class<?> doCompile(String name, String source) throws Throwable;

}

相關推薦

dubbo原始碼分析動態編譯

我們執行的Java程式碼,都是編譯之後的位元組碼,dubbo為了實現了基於spi思想的擴充套件特性,特別是能夠靈活新增額外功能。dubbo作為一個高擴充套件性的框架,使的使用者能夠新增自己的需求,根據配置動態生成自己的設配類程式碼,這樣就需要在執行的時候去編譯載

Dubbo原始碼解讀動態代理

前言 或許我們已悉知Java的動態代理的方式:jdk——通過介面中的方法名,在動態生成的代理類中呼叫業務實現類的同名方法;cglib——通過繼承業務類,生成的動態代理類是業務類的子類,通過重寫業務方法進行代理。dubbo在沿用java的jdk方式外,還採取了javassist方式——通過

Dubbo原始碼分析四:服務的呼叫

在呼叫服務之前,先得獲得服務的引用。 ReferenceBean 就是服務的引用。它實現了一個FactoryBean介面,在我們需要一個服務時,FactoryBean介面的getObject() 方法會被呼叫。 public Object getObje

5.dubbo原始碼分析 SPI分析

如果大家看過之前的 dubbo 核心 SPI 實現 – 2.dubbo原始碼分析 之 核心SPI實現, 有可能還是一頭霧水,下面我講一下dubbo的具體應用。最典型的應用就是 Protocol 介面。 Protocol 屬於 dubbo 十層結構 中的遠端呼叫

9、dubbo原始碼分析 服務遠端暴露(中)

在上一篇文章我們講解了一下 dubbo 遠端服務暴露過程中通過 Netty 進行 Socket 服務暴露。使得遠端客戶端可以訪問這個暴露的服務,這個只是解決了訪問之前點到點的服務呼叫。對於分步式環境當中,越來越多的服務我們如何管理並且治理這些服務是一個問題。因此 dubbo

7、dubbo原始碼分析 服務本地暴露

在上一篇文章我們分析了一下 dubbo 在服務暴露發生了哪些事,今天我們就來分析一下整個服務暴露中的本地暴露。(PS:其實我感覺本地暴露蠻雞肋的)。本地暴露需要服務提供方與服務消費方在同一個 JVM。下面我們來寫一個本地暴露使用的例子: 1) DemoS

Dubbo原始碼分析 SPI(一)

一、概述     dubbo SPI 在dubbo的作用是基礎性的,要想分析研究dubbo的實現原理、dubbo原始碼,都繞不過 dubbo SPI,掌握dubbo SPI 是征服dubbo的必經之路。     本篇文章會詳細介紹dubbo SPI相關的內容,

Dubbo原始碼分析SPI(二)

一、概述   本篇文章是dubbo SPI原始碼分析的第二篇,接著第一篇繼續分析dubbo SPI的內容,我們主要介紹 getDefaultExtension() 獲取預設擴充套件點方法。 由於此方法比較簡單,我們略過示例部分,直接分析原始碼。 二、原始碼分析   獲取預設擴充套件方法getDefau

Dubbo原始碼分析SPI(三)

一、概述   本篇介紹自適應擴充套件,方法getAdaptiveExtension()的實現。ExtensionLoader類本身很多功能也使用到了自適應擴充套件。包括ExtensionFactory擴充套件。   通俗的講,自適應擴充套件要實現的邏輯是:呼叫擴充套件點的方法時,自動判斷要呼叫那個擴充套件點實

Dubbo 原始碼分析系列三 —— 架構原理

1 核心功能 首先要了解Dubbo提供的三大核心功能: Remoting:遠端通訊 提供對多種NIO框架抽象封裝,包括“同步轉非同步”和“請求-響應”模式的資訊交換方式。 Cluster: 服務框架 提供基於介面方法的透明遠端過程呼叫,包括多協議支援,以及

Dubbo 原始碼分析 - 叢集容錯 Router

1. 簡介 上一篇文章分析了叢集容錯的第一部分 – 服務目錄 Directory。服務目錄在重新整理 Invoker 列表的過程中,會通過 Router 進行服務路由。上一篇文章關於服務路由相關邏輯沒有細緻分析,一筆帶過了,本篇文章將對此進行詳細的分析。首先,先來介紹一下服務目錄是什麼。服務路由包含一條路由

Dubbo 原始碼分析 - 叢集容錯 LoadBalance

1.簡介 LoadBalance 中文意思為負載均衡,它的職責是將網路請求,或者其他形式的負載“均攤”到不同的機器上。避免叢集中部分伺服器壓力過大,而另一些伺服器比較空閒的情況。通過負載均衡,可以讓每臺伺服器獲取到適合自己處理能力的負載。在為高負載的伺服器分流的同時,還可以避免資源浪費,一舉兩得。負載均衡可

Dubbo原始碼分析(三):Dubbo服務端(Service)

         如上圖所示的Dubbo的暴露服務的過程,不難看出它也和消費者端很像,也需要一個像reference的物件來維護service關聯的所有物件及其屬性,這裡的reference就是provider。由於ServiceBean實現了  Initializ

Dubbo 原始碼分析 - 叢集容錯 Cluster

1.簡介 為了避免單點故障,現在的應用至少會部署在兩臺伺服器上。對於一些負載比較高的服務,會部署更多臺伺服器。這樣,同一環境下的服務提供者數量會大於1。對於服務消費者來說,同一環境下出現了多個服務提供者。這時會出現一個問題,服務消費者需要決定選擇哪個服務提供者進行呼叫。另外服務呼叫失敗時的處理措

Dubbo 原始碼分析 - 叢集容錯Directory

1. 簡介 前面文章分析了服務的匯出與引用過程,從本篇文章開始,我將開始分析 Dubbo 叢集容錯方面的原始碼。這部分原始碼包含四個部分,分別是服務目錄 Directory、服務路由 Router、叢集 Cluster 和負載均衡 LoadBalance。這幾個部分的原始碼邏輯比較獨立,我會分四

qemu原始碼分析四--dyngen動態翻譯技術

    由於剛剛接觸qemu,所以前面幾篇文章僅僅是膚淺的介紹qemu的一些背景知識,今天突然感覺前面說的太沒有條理了,而且大部分是讀別人的文章,一知半解,沒有自己的總結體會,今天感覺稍微有點心得,敬請指教。 1. 明確guest和host     對於qemu而言,被模擬

qemu原始碼分析五-- TCG動態翻譯技術

1. TCG簡單介紹 TCG(Tiny Code Generator)最早被用於C編譯器的後端。在TCG相關的程式碼中,target指的是我們通常說的host,這一點需要注意,並不是我們理解的被模擬的平臺。 2. TCG動態翻譯技術的幾個概念 (1)與dyngen一樣,TCG的“function”與qem

dubbo原始碼分析8 -- DubboProtocol 提供端釋出服務export

在前面提到,在RegistryProtocol釋出服務時,首先會dubbo對外提供介面 根據url的地址,協議是dubbo,呼叫protocol.export(…), 但是根據ExtensionLoader.getExtensionLoader獲取的到的pro

死磕以太坊原始碼分析EVM動態資料型別

> 死磕以太坊原始碼分析之EVM動態資料型別 > > 配合以下程式碼進行閱讀:https://github.com/blockchainGuide/ > > 寫文不易,給個小關注,有什麼問題可以指出,便於大家交流學習。 > ![image-2021011318550029

Spark原始碼分析Spark Shell(上)

https://www.cnblogs.com/xing901022/p/6412619.html 文中分析的spark版本為apache的spark-2.1.0-bin-hadoop2.7。 bin目錄結構: -rwxr-xr-x. 1 bigdata bigdata 1089 Dec