中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

[SpringBoot]深入淺出剖析SpringBoot的應(yīng)用類型識(shí)別機(jī)制

微信號(hào):GitShare
微信公眾號(hào):愛折騰的稻草
如有問題或建議,請(qǐng)?jiān)诠娞?hào)留言[1]

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、重慶小程序開發(fā)公司、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了漢中免費(fèi)建站歡迎大家使用!

前續(xù)

為幫助廣大SpringBoot用戶達(dá)到“知其然,更需知其所以然”的境界,作者將通過SpringBoot系列文章全方位對(duì)SpringBoot2.0.0.RELEASE版本深入分解剖析,讓您深刻的理解其內(nèi)部工作原理。

  • 1、[SpringBoot]利用SpringBoot快速構(gòu)建并啟動(dòng)項(xiàng)目

  • 2、[SpringBoot]詳解SpringBoot應(yīng)用的啟動(dòng)過程

推斷應(yīng)用的類型

SpringBoot啟動(dòng)時(shí),在創(chuàng)建SpringApplication對(duì)象時(shí),會(huì)自動(dòng)去識(shí)別并設(shè)置當(dāng)前應(yīng)用是普通web應(yīng)用、響應(yīng)式web應(yīng)用還是非web應(yīng)用,其內(nèi)部實(shí)現(xiàn)原理是什么?  
首先看看源代碼

/**
* 推斷應(yīng)用的類型
*/
private WebApplicationType deduceWebApplicationType() {
    if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
            && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : WEB_ENVIRONMENT_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}
  • ClassUtils.isPresent()方法:  
    其作用是判斷所提供的類名的類是否存在,且可以被加載。源代碼如下:

public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
    try {
        forName(className, classLoader);
        return true;
    }
    catch (Throwable ex) {
        // Class or one of its dependencies is not present...
        return false;
    }
}

調(diào)用了forName()方法,如果出現(xiàn)異常,則返回false,也就是提供目標(biāo)類不存在。

  • forName()方法的源碼剖析:

public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
        throws ClassNotFoundException, LinkageError {

    Assert.notNull(name, "Name must not be null");
    //根據(jù)基本類的JVM命名規(guī)則(如果合適的話),將給定的類名name解析為基本類型的包裝類
    Class<?> clazz = resolvePrimitiveClassName(name);
    if (clazz == null) {
        //commonClassCache是包含java.lang包下所有類,將類的類名作為鍵,對(duì)應(yīng)類作為值的一個(gè)Map集合。
        clazz = commonClassCache.get(name); //根據(jù)類名,獲取commonClassCache集合中的值,如果為空,表示目標(biāo)類不是java.lang包的下類,即不是原始類型。
    }
    if (clazz != null) {
        //如果根據(jù)類名,已經(jīng)獲取到了類,則直接返回該類。
        return clazz;
    }

    //判斷clas屬性值是否為數(shù)組對(duì)象。比如:java.lang.String[]
    // "java.lang.String[]" style arrays
    if (name.endsWith(ARRAY_SUFFIX)) { 
        //如果是,則將類名后的“[]”方括號(hào)截去,返回java.lang.String,遞歸查找類名,找到后,將Class類型轉(zhuǎn)換為數(shù)組。
        String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
        Class<?> elementClass = forName(elementClassName, classLoader);
        return Array.newInstance(elementClass, 0).getClass();
    }

    //class屬性值是否為數(shù)組對(duì)象的二進(jìn)制表示。比如:[Ljava.lang.String
    // "[Ljava.lang.String;" style arrays
    if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
        //如果是,則將值的“[L”部分截去,遞歸查找類名,找到后,將對(duì)應(yīng)的Class類型轉(zhuǎn)換為數(shù)組
        String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
        Class<?> elementClass = forName(elementName, classLoader);
        return Array.newInstance(elementClass, 0).getClass();
    }

    //class屬性值是否為二維數(shù)組
    // "[[I" or "[[Ljava.lang.String;" style arrays
    if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
        String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
        Class<?> elementClass = forName(elementName, classLoader);
        return Array.newInstance(elementClass, 0).getClass();
    }

    //獲取classLoader
    ClassLoader clToUse = classLoader;
    if (clToUse == null) {
         //如果classLoader為空,則獲取默認(rèn)的classLoader對(duì)象。
        clToUse = getDefaultClassLoader();
    }
    try {
        //返回加載后的類
        return (clToUse != null ? clToUse.loadClass(name) : Class.forName(name));
    }
    catch (ClassNotFoundException ex) {
        //用于處理內(nèi)部類的情況。
        int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
        if (lastDotIndex != -1) {
            //拼接內(nèi)部類的名字。
            String innerClassName = name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
            try {
                return (clToUse != null ? clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
            }
            catch (ClassNotFoundException ex2) {
                // Swallow - let original exception get through
            }
        }
        throw ex;
    }
}
  • 再來看看使用到的常量值:

    • REACTIVE_WEB_ENVIRONMENT_CLASS:org.springframework.web.reactive.DispatcherHandler

    • MVC_WEB_ENVIRONMENT_CLASS:org.springframework.web.servlet.DispatcherServlet

    • WEB_ENVIRONMENT_CLASSES:{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" }
      也就是說,

  • 1、如果應(yīng)用程序中存在org.springframework.web.reactive.DispatcherHandler這個(gè)類,則表示是一個(gè)響應(yīng)式web應(yīng)用,項(xiàng)目在啟動(dòng)時(shí),需要去
    加載啟動(dòng)內(nèi)嵌的響應(yīng)式web服務(wù)器。

  • 2、如果應(yīng)用程序中既不存在javax.servlet.Servlet類,也不存在org.springframework.web.context.ConfigurableWebApplicationContext這個(gè)類,則
    表示當(dāng)前應(yīng)用不是一個(gè)web應(yīng)用,啟動(dòng)時(shí)無需加載啟動(dòng)內(nèi)嵌的web服務(wù)器。

  • 3、除上述兩種情況外,則表示當(dāng)前應(yīng)用是一個(gè)servlet的web應(yīng)用,啟動(dòng)時(shí)需要加載啟動(dòng)內(nèi)嵌的servlet的web服務(wù)器(比如Tomcat)。

推斷并設(shè)置main方法的定義類(啟動(dòng)類)

SpringBoot啟動(dòng)時(shí),在創(chuàng)建SpringApplication對(duì)象時(shí),最后會(huì)推斷并設(shè)置main方法的定義類(啟動(dòng)類),其實(shí)現(xiàn)原理是什么呢?
先看看源代碼;

private Class<?> deduceMainApplicationClass() {
    try {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}
  • java.lang.StackTraceElement是什么?
    類元素代表一個(gè)堆棧幀。除了一個(gè)在堆棧的頂部所有的棧幀代表一個(gè)方法調(diào)用。在堆棧頂部的幀表示在將其生成的堆棧跟蹤的執(zhí)行點(diǎn)。

    • stackTraceElement.getMethodName() 返回一個(gè)包含由該堆棧跟蹤元素所表示的執(zhí)行點(diǎn)的方法的名稱。

    • stackTraceElement.getClassName() 返回一個(gè)包含由該堆棧跟蹤元素所表示的執(zhí)行點(diǎn)類的完全限定名。

  • java.lang.Class.forName()的作用是什么?
    java.lang.Class.forName(String name, boolean initialize, ClassLoader loader) 方法返回與給定字符串名的類或接口的Class對(duì)象,使用給定的類加載器。

參數(shù)說明
    - name :這是所需類的完全限定名稱。
    - initialize : 這說明這個(gè)類是否必須初始化。
    - loader : 這是必須加載的類的類加載器。
異常說明
    - LinkageError : 如果聯(lián)動(dòng)失敗。
    - ExceptionInInitializerError : 如果這種方法所引發(fā)的初始化失敗。
    - ClassNotFoundException : 如果類不能位于由指定的類加載器。
參數(shù)使用
    - ClassLoader loader:如果該參數(shù)加載器loader 為空,通過引導(dǎo)類加載器加載類。
    - boolean initialize:如果它沒有被初始化,則initialize參數(shù)為true。

通過上面知識(shí)點(diǎn)的講解,deduceMainApplicationClass的作用就非常清晰了,主要是獲取當(dāng)前方法調(diào)用棧,遍歷調(diào)用堆棧信息找到main函數(shù)的類,并返回該類。

總結(jié)
  • 1、SpringBoot是通過調(diào)用ClassUtils類的isPresent方法,檢查classpath中是否存在org.springframework.web.reactive.DispatcherHandler類、
    javax.servlet.Servlet類和org.springframework.web.context.ConfigurableWebApplicationContext類來判斷當(dāng)前應(yīng)用是響應(yīng)式Web應(yīng)用,還是普通的Servlet的Web應(yīng)用,還是非Web應(yīng)用。

  • 2、SpringBoot是通過獲取當(dāng)前方法的調(diào)用棧信息,來判斷當(dāng)前main函數(shù)所在的類。

后記

為幫助廣大SpringBoot用戶達(dá)到“知其然,更需知其所以然”的境界,作者將通過SpringBoot系列文章全方位對(duì)SpringBoot2.0.0.RELEASE版本深入分解剖析,讓您深刻的理解其內(nèi)部工作原理。 

敬請(qǐng)關(guān)注[愛折騰的稻草(GitShare)]公眾號(hào),為您提供更多更優(yōu)質(zhì)的技術(shù)教程。


[SpringBoot]深入淺出剖析SpringBoot的應(yīng)用類型識(shí)別機(jī)制圖注:愛折騰的稻草

分享文章:[SpringBoot]深入淺出剖析SpringBoot的應(yīng)用類型識(shí)別機(jī)制
本文網(wǎng)址:http://www.rwnh.cn/article48/ipcjhp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站網(wǎng)站營(yíng)銷、小程序開發(fā)、自適應(yīng)網(wǎng)站、網(wǎng)站收錄、品牌網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化
台中市| 北票市| 沐川县| 玛纳斯县| 东乡| 门头沟区| 贵溪市| 曲麻莱县| 肇源县| 巴中市| 九江县| 工布江达县| 株洲市| 深州市| 荆州市| 溧水县| 耿马| 左权县| 汶上县| 曲松县| 防城港市| 玉溪市| 两当县| 衡东县| 泸州市| 道孚县| 合川市| 河西区| 三门县| 烟台市| 休宁县| 桃江县| 吐鲁番市| 建平县| 浦东新区| 锡林浩特市| 固原市| 普安县| 澜沧| 辽源市| 仪征市|