亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入解析Java類(lèi)加載的案例與實(shí)戰(zhàn)教程

 更新時(shí)間:2022年05月05日 11:22:56   作者:怪咖軟妹@  
本篇文章主要介紹Tomcat類(lèi)加載器架構(gòu),以及基于類(lèi)加載和字節(jié)碼相關(guān)知識(shí),去分析動(dòng)態(tài)代理的原理,對(duì)Java類(lèi)加載相關(guān)知識(shí)感興趣的朋友一起看看吧

本篇文章主要介紹Tomcat類(lèi)加載器架構(gòu),以及基于類(lèi)加載和字節(jié)碼相關(guān)知識(shí),去分析動(dòng)態(tài)代理的原理。

一、Tomcat類(lèi)加載器架構(gòu)

Tomcat有自己定義的類(lèi)加載器,因?yàn)橐粋€(gè)功能健全的Web服務(wù)器,都要解決 如下的這些問(wèn)題:

  • 部署在同一個(gè)服務(wù)器上的兩個(gè)Web應(yīng)用程序所使用的Java類(lèi)庫(kù)可以實(shí)現(xiàn)相互隔離。這是最基本的 需求。兩個(gè)不同的應(yīng)用程序可能會(huì)依賴(lài)同一個(gè)第三方類(lèi)庫(kù)的不同版本,不能要求每個(gè)類(lèi)庫(kù)在一個(gè)服務(wù) 器中只能有一份。
  • 部署在同一個(gè)服務(wù)器上的兩個(gè)Web應(yīng)用程序所使用的Java類(lèi)庫(kù)可以互相共享。例如用戶(hù)可能有10個(gè)使用Spring組織的應(yīng)用程序部署在同一臺(tái)服務(wù)器 上,如果把10份Spring分別存放在各個(gè)應(yīng)用程序的隔離目錄中,將會(huì)是很大的資源浪費(fèi)——這主要倒 不是浪費(fèi)磁盤(pán)空間的問(wèn)題,而是指類(lèi)庫(kù)在使用時(shí)都要被加載到服務(wù)器內(nèi)存,如果類(lèi)庫(kù)不能共享,虛擬 機(jī)的方法區(qū)就會(huì)很容易出現(xiàn)過(guò)度膨脹的風(fēng)險(xiǎn)。
  • 服務(wù)器需要盡可能地保證自身的安全不受部署的Web應(yīng)用程序影響?;诎?全考慮,服務(wù)器所使用的類(lèi)庫(kù)應(yīng)該與應(yīng)用程序的類(lèi)庫(kù)互相獨(dú)立。
  • 支持JSP應(yīng)用的Web服務(wù)器,十有八九都需要支持HotSwap功能。我們知道JSP文件最終要被編譯 成Java的Class文件才能被虛擬機(jī)執(zhí)行,所謂的hotswap,就是使用新的代碼替換掉已經(jīng)加載的這個(gè)Class中的內(nèi)容。

由于存在上述問(wèn)題,在部署Web應(yīng)用時(shí),單獨(dú)的一個(gè)ClassPath就不能滿(mǎn)足需求了,所以各種Web服 務(wù)器都不約而同地提供了好幾個(gè)有著不同含義的ClassPath路徑供用戶(hù)存放第三方類(lèi)庫(kù),這些路徑一般 會(huì)以“lib”或“classes”命名。被放置到不同路徑中的類(lèi)庫(kù),具備不同的訪(fǎng)問(wèn)范圍和服務(wù)對(duì)象,通常每一 個(gè)目錄都會(huì)有一個(gè)相應(yīng)的自定義類(lèi)加載器去加載放置在里面的Java類(lèi)庫(kù)

在Tomcat目錄結(jié)構(gòu)中,把Java類(lèi)庫(kù)放置在這4組目錄中,每一組都有獨(dú)立的含義,分別是:

  • 放置在/common目錄中。類(lèi)庫(kù)可被Tomcat和所有的Web應(yīng)用程序共同使用。
  • 放置在/server目錄中。類(lèi)庫(kù)可被Tomcat使用,對(duì)所有的Web應(yīng)用程序都不可見(jiàn)。放置在/shared目錄中。類(lèi)庫(kù)可被所有的Web應(yīng)用程序共同使用,但對(duì)Tomcat自己不可見(jiàn)。
  • 放置在/WebApp/WEB-INF目錄中。類(lèi)庫(kù)僅僅可以被該Web應(yīng)用程序使用,對(duì)Tomcat和其他Web應(yīng)用程序都不可見(jiàn)。

為了支持這套目錄結(jié)構(gòu),并對(duì)目錄里面的類(lèi)庫(kù)進(jìn)行加載和隔離,Tomcat自定義了多個(gè)類(lèi)加載器, 這些類(lèi)加載器按照經(jīng)典的雙親委派模型來(lái)實(shí)現(xiàn),關(guān)系如下圖所示。

在這里插入圖片描述

灰色背景的3個(gè)類(lèi)加載器是默認(rèn)提供的類(lèi)加載器,而JDKCommon類(lèi)加載器、Catalina類(lèi)加載器(也稱(chēng)為Server類(lèi) 加載器)、Shared類(lèi)加載器和Webapp類(lèi)加載器則是Tomcat自己定義的類(lèi)加載器。

它們分別加 載/common/、/server/、/shared/*和/WebApp/WEB-INF/*中的Java類(lèi)庫(kù)。
其中WebApp類(lèi)加載器和JSP類(lèi)加載器通常還會(huì)存在多個(gè)實(shí)例,每一個(gè)Web應(yīng)用程序?qū)?yīng)一個(gè)WebApp類(lèi)加載器,每一個(gè)JSP文件對(duì)應(yīng) 一個(gè)JasperLoader類(lèi)加載器

由上圖得知:

  • Common類(lèi)加載器能加載的類(lèi)都可以被Catalina類(lèi)加載器和Shared 類(lèi)加載器使用
  • 而Catalina類(lèi)加載器和Shared類(lèi)加載器自己能加載的類(lèi)則與對(duì)方相互隔離
  • WebApp類(lèi) 加載器可以使用Shared類(lèi)加載器加載到的類(lèi),但各個(gè)WebApp類(lèi)加載器實(shí)例之間相互隔離。
  • JasperLoader的加載范圍僅僅是這個(gè)JSP文件所編譯出來(lái)的那一個(gè)Class文件,它存在的目的就是為了被 丟棄:當(dāng)服務(wù)器檢測(cè)到JSP文件被修改時(shí),會(huì)替換掉目前的JasperLoader的實(shí)例,并通過(guò)再建立一個(gè)新 的JSP類(lèi)加載器來(lái)實(shí)現(xiàn)JSP文件的HotSwap功能。

本例中的類(lèi)加載結(jié)構(gòu)在Tomcat 6以前是它默認(rèn)的類(lèi)加載器結(jié)構(gòu),在Tomcat 6及之后的版本簡(jiǎn)化了默 認(rèn)的目錄結(jié)構(gòu),只有指定了tomcat/conf/catalina.properties配置文件的server.loader和share.loader項(xiàng)后才會(huì) 真正建立Catalina類(lèi)加載器和Shared類(lèi)加載器的實(shí)例,否則會(huì)用到這兩個(gè)類(lèi)加載器的地方都會(huì)用 Common類(lèi)加載器的實(shí)例代替。

Tomcat 6之后也 順理成章地把/common、/server和/shared這3個(gè)目錄默認(rèn)合并到一起變成1個(gè)/lib目錄,這個(gè)目錄里的類(lèi)庫(kù) 相當(dāng)于以前/common目錄中類(lèi)庫(kù)的作用。

那么筆者不妨再提一個(gè)問(wèn)題讓各位讀者思考一下:前 面曾經(jīng)提到過(guò)一個(gè)場(chǎng)景,如果有10個(gè)Web應(yīng)用程序都是用Spring來(lái)進(jìn)行組織和管理的話(huà),可以把Spring 放到Common或Shared目錄下讓這些程序共享。Spring要對(duì)用戶(hù)程序的類(lèi)進(jìn)行管理,自然要能訪(fǎng)問(wèn)到用 戶(hù)程序的類(lèi),而用戶(hù)的程序顯然是放在/WebApp/WEB-INF目錄中的。那么被Common類(lèi)加載器或 Shared類(lèi)加載器加載的Spring如何訪(fǎng)問(wèn)并不在其加載范圍內(nèi)的用戶(hù)程序呢?

答案:如果按主流的雙親委派機(jī)制,顯然無(wú)法做到讓父類(lèi)加載器加載的類(lèi)去訪(fǎng)問(wèn)子類(lèi)加載器加載的類(lèi),但使用線(xiàn)程上下文加載器,可以讓父類(lèi)加載器請(qǐng)求子類(lèi)加載器去完成類(lèi)加載的動(dòng)作。spring加載類(lèi)所用的Classloader是通過(guò)Thread.currentThread().getContextClassLoader()來(lái)獲取的,而當(dāng)線(xiàn)程創(chuàng)建時(shí)會(huì)默認(rèn)setContextClassLoader(AppClassLoader),即線(xiàn)程上下文類(lèi)加載器被設(shè)置為AppClassLoader,spring中始終可以獲取到這個(gè)AppClassLoader(在Tomcat里就是WebAppClassLoader)子類(lèi)加載器來(lái)加載的bean,以后任何一個(gè)線(xiàn)程都可以通過(guò)getContextClassLoader()獲取到WebAppClassLoader來(lái)getbean了。

二、動(dòng)態(tài)代理的原理

“字節(jié)碼生成”并不是什么高深的技術(shù),因?yàn)镴DK里面的Javac命令就是字節(jié)碼生成技術(shù)的“老祖 宗”,并且Javac也是一個(gè)由Java語(yǔ)言寫(xiě)成的程序。

在Java世界里面除了Javac和字 節(jié)碼類(lèi)庫(kù)外,使用到字節(jié)碼生成的例子比比皆是,如Web服務(wù)器中的JSP編譯器,編譯時(shí)織入的AOP框 架,還有很常用的動(dòng)態(tài)代理技術(shù),甚至在使用反射的時(shí)候虛擬機(jī)都有可能會(huì)在運(yùn)行時(shí)生成字節(jié)碼來(lái)提 高執(zhí)行速度。我們選擇其中相對(duì)簡(jiǎn)單的動(dòng)態(tài)代理技術(shù)來(lái)講解字節(jié)碼生成技術(shù)是如何影響程序運(yùn)作的。

什么是動(dòng)態(tài)代理?

動(dòng)態(tài)代理中所說(shuō)的“動(dòng)態(tài)”,是指實(shí) 現(xiàn)了可以在原始類(lèi)和接口還未知的時(shí)候,就確定代理類(lèi)的代理行為,當(dāng)代理類(lèi)與原始類(lèi)脫離直接聯(lián)系 后,就可以很靈活地重用于不同的應(yīng)用場(chǎng)景之中。

下面代碼演示了一個(gè)最簡(jiǎn)單的動(dòng)態(tài)代理的用法,原始的代碼邏輯是打印一句“hello world”,代 理類(lèi)的邏輯是在原始類(lèi)方法執(zhí)行前打印一句“welcome”。我們先看一下代碼,然后再分析JDK是如何做 到的。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyTest {
    interface IHello {
        void sayHello();
    }
    static class Hello implements IHello {
        @Override
        public void sayHello() {
            System.out.println("hello world");
        }
    }
    static class DynamicProxy implements InvocationHandler {
        Object originalObj;
        Object bind(Object originalObj) {
            this.originalObj = originalObj;
            return Proxy.newProxyInstance(originalObj.getClass().getClassLoader(), originalObj.getClass().getInterfaces(), this);
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("welcome");
            return method.invoke(originalObj, args);
        }
    }
    public static void main(String[] args) {
        IHello hello = (IHello) new DynamicProxy().bind(new Hello());
        hello.sayHello();
    }
}

運(yùn)行結(jié)果如下:

在這里插入圖片描述

在上述代碼里,唯一的“黑匣子”就是Proxy::newProxyInstance()方法,除此之外再?zèng)]有任何特殊之 處。這個(gè)方法返回一個(gè)實(shí)現(xiàn)了IHello的接口,并且代理了new Hello()實(shí)例行為的對(duì)象。

newProxyInstance一共傳進(jìn)去三個(gè)參數(shù):

  • loader第一個(gè)參數(shù),代表的是被代理類(lèi)的類(lèi)加載器
  • interfaces代理類(lèi)要實(shí)現(xiàn)的被代理類(lèi)接口
  • InvocationHandler代表的是將方法調(diào)用分派給的調(diào)用處理程序

跟蹤這個(gè)方法的 源碼,可以看到程序進(jìn)行過(guò)驗(yàn)證、優(yōu)化、緩存、同步、生成字節(jié)碼、顯式類(lèi)加載等操作,前面的步驟 并不是我們關(guān)注的重點(diǎn),這里只分析它最后調(diào)用sun.misc.ProxyGenerator::generateProxyClass()方法來(lái)完 成生成字節(jié)碼的動(dòng)作。

在這里插入圖片描述

這個(gè)方法會(huì)在運(yùn)行時(shí)產(chǎn)生一個(gè)描述代理類(lèi)的字節(jié)碼byte[]數(shù)組。如果想看一看這 個(gè)在運(yùn)行時(shí)產(chǎn)生的代理類(lèi)中寫(xiě)了些什么,可以在main()方法中加入下面這句:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

執(zhí)行完 可以用idea在debug狀態(tài)下直接雙擊shift搜索$Proxy即可找到j(luò)ava文件,如下:

import com.gzl.cn.DynamicProxyTest.IHello;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
final class $Proxy0 extends Proxy implements IHello {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
	// 此處由于版面原因,省略equals()、hashCode()、toString()3個(gè)方法的代碼

    public final void sayHello() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.gzl.cn.DynamicProxyTest$IHello").getMethod("sayHello");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

動(dòng)態(tài)代理的原理:

  • 通過(guò)ProxyGenerator::generateProxyClass()生成一個(gè)代理類(lèi)
  • 這個(gè)代理類(lèi)的實(shí)現(xiàn)代碼也很簡(jiǎn)單,它為傳入接口中的每一個(gè)方法,以及從java.lang.Object中繼承來(lái) 的equals()、hashCode()、toString()方法都生成了對(duì)應(yīng)的實(shí)現(xiàn),并且統(tǒng)一調(diào)用了InvocationHandler對(duì)象的 invoke()方法來(lái)實(shí)現(xiàn)這些方法的 內(nèi)容。
  • 代碼中的“super.h”就是父類(lèi)Proxy中保存的InvocationHandler實(shí)例變量,而實(shí)例變量就是剛剛傳入的new Hello()。
  • 所以無(wú)論調(diào)用動(dòng)態(tài)代理的哪一 個(gè)方法,實(shí)際上都是在執(zhí)行InvocationHandler::invoke()中的代理邏輯。

這個(gè)例子中并沒(méi)有講到generateProxyClass()方法具體是如何產(chǎn)生代理類(lèi)“$Proxy0.class”的字節(jié)碼 的,大致的生成過(guò)程其實(shí)就是根據(jù)Class文件的格式規(guī)范去拼裝字節(jié)碼,但是在實(shí)際開(kāi)發(fā)中,以字節(jié)為 單位直接拼裝出字節(jié)碼的應(yīng)用場(chǎng)合很少見(jiàn),這種生成方式也只能產(chǎn)生一些高度模板化的代碼。

對(duì)于用 戶(hù)的程序代碼來(lái)說(shuō),如果有要大量操作字節(jié)碼的需求,還是使用封裝好的字節(jié)碼類(lèi)庫(kù)比較合適。如果 讀者對(duì)動(dòng)態(tài)代理的字節(jié)碼拼裝過(guò)程確實(shí)很感興趣,可以在OpenJDK的 java.base\share\classes\java\lang\reflect目錄下找到sun.misc.ProxyGenerator的源碼。

三、Java語(yǔ)法糖的改變

在Java世界里,每一次JDK大版本的發(fā)布,對(duì)Java程 序編寫(xiě)習(xí)慣改變最大的,肯定是那些對(duì)Java語(yǔ)法做出重大改變的版本。

  • 譬如JDK 5時(shí)加入的自動(dòng)裝箱、 泛型、動(dòng)態(tài)注解、枚舉、變長(zhǎng)參數(shù)、遍歷循環(huán)(foreach循環(huán));譬如JDK 8時(shí)加入的Lambda表達(dá)式、 Stream API、接口默認(rèn)方法等。
  • 事實(shí)上在沒(méi)有這些語(yǔ)法特性的年代,Java程序也照樣能寫(xiě)。 現(xiàn)在問(wèn)題來(lái)了,如何把高版本JDK中編寫(xiě)的代碼放到低版本JDK 環(huán)境中去部署使用?

為了解決這個(gè)問(wèn)題,一種名為“Java逆向移植”的工具(Java Backporting Tools)應(yīng) 運(yùn)而生,Retrotranslator和Retrolambda是這類(lèi)工具中的杰出代表。

Retrotranslator的作用是將JDK 5編譯出來(lái)的Class文件轉(zhuǎn)變?yōu)榭梢栽贘DK 1.4或1.3上部署的版本, 它能很好地支持自動(dòng)裝箱、泛型、動(dòng)態(tài)注解、枚舉、變長(zhǎng)參數(shù)、遍歷循環(huán)、靜態(tài)導(dǎo)入這些語(yǔ)法特性, 甚至還可以支持JDK 5中新增的集合改進(jìn)、并發(fā)包及對(duì)泛型、注解等的反射操作。

Retrolambda的作 用與Retrotranslator是類(lèi)似的,目標(biāo)是將JDK 8的Lambda表達(dá)式和try-resources語(yǔ)法轉(zhuǎn)變?yōu)?code>可以在JDK 5、JDK 6、JDK 7中使用的形式,同時(shí)也對(duì)接口默認(rèn)方法提供了有限度的支持。

什么是語(yǔ)法糖?

在前端編譯器層面做的改進(jìn)。這種改進(jìn)被稱(chēng)作語(yǔ)法糖。也就是這些語(yǔ)法糖主要是幫助我們這些開(kāi)發(fā)人員減少代碼量,但是并沒(méi)有省略掉,只是交給了javac編譯器,來(lái)替我們做了轉(zhuǎn)換。

  • 如自動(dòng)裝箱拆箱,實(shí)際上就是Javac編 譯器在程序中使用到包裝對(duì)象的地方自動(dòng)插入了很多Integer.valueOf()、Float.valueOf()之類(lèi)的代碼
  • 使用enum關(guān)鍵字定義常量,盡管從 Java語(yǔ)法上看起來(lái)與使用class關(guān)鍵字定義類(lèi)、使用interface關(guān)鍵字定義接口是同一層次的,但實(shí)際上這 是由Javac編譯器做出來(lái)的假象,從字節(jié)碼的角度來(lái)看,枚舉僅僅是一個(gè)繼承于java.lang.Enum、自動(dòng)生 成了values()和valueOf()方法的普通Java類(lèi)而已。

到此這篇關(guān)于深入解析Java類(lèi)加載的案例與實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Java類(lèi)加載內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Easypoi 輕松實(shí)現(xiàn)復(fù)雜excel文件導(dǎo)出功能

    Easypoi 輕松實(shí)現(xiàn)復(fù)雜excel文件導(dǎo)出功能

    這篇文章主要介紹了Easypoi 輕松實(shí)現(xiàn)復(fù)雜excel文件導(dǎo)出功能,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • linux重啟java服務(wù)的腳本

    linux重啟java服務(wù)的腳本

    這篇文章主要介紹了linux重啟java服務(wù)的腳本,本文分步驟通過(guò)shell腳本給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • SpringBoot攔截器excludePathPatterns方法不生效的解決方案

    SpringBoot攔截器excludePathPatterns方法不生效的解決方案

    這篇文章主要介紹了SpringBoot攔截器excludePathPatterns方法不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • Kotlin 基礎(chǔ)教程之反射

    Kotlin 基礎(chǔ)教程之反射

    這篇文章主要介紹了Kotlin 基礎(chǔ)教程之反射的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 淺談Spring IoC容器的依賴(lài)注入原理

    淺談Spring IoC容器的依賴(lài)注入原理

    這篇文章主要介紹了淺談Spring IoC容器的依賴(lài)注入原理,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • Java中Comparator升序降序的具體使用

    Java中Comparator升序降序的具體使用

    本文主要介紹了Java中Comparator升序降序的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • IDEA快速生成實(shí)體類(lèi)的示例教程

    IDEA快速生成實(shí)體類(lèi)的示例教程

    這篇文章主要介紹了IDEA快速生成實(shí)體類(lèi)的示例教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • spring security中Authority、Role的區(qū)別及說(shuō)明

    spring security中Authority、Role的區(qū)別及說(shuō)明

    這篇文章主要介紹了spring security中Authority、Role的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • 詳解Spring boot操作文件的多種方式

    詳解Spring boot操作文件的多種方式

    這篇文章主要介紹了Spring boot操作文件的幾種方式,主要給大家介紹操作文件的三種方式,每種方式通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • Java獲取文件的hash值(SHA256)兩種方式

    Java獲取文件的hash值(SHA256)兩種方式

    這篇文章主要給大家介紹了關(guān)于Java獲取文件hash值(SHA256)的兩種方式,SHA256是一種哈希算法,它是不可逆的,也就是說(shuō)無(wú)法解密,需要的朋友可以參考下
    2023-09-09

最新評(píng)論