欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java的內(nèi)存模型

 更新時間:2021年06月01日 10:47:31   作者:糖拌西紅柿  
本文更準確的說法應該是JVM的內(nèi)存模型,但是這里又牽扯了一些其他的前置知識,主要是想從Java入手,從源頭上梳理一遍整個Java底層運行的機制,中間會額外補充一些和題目無關的前置基礎,導致主講內(nèi)存模型的篇幅所占的比例就不是那么絕對。

JVM的內(nèi)存模型

Java “一次運行,到處編譯” 的真面目

說JVM內(nèi)存模型之前,先聊一個老生常談的問題,為什么Java可以 “一次編譯,到處運行”,這個話題最直接的答案就是,因為Java有JVM啊,解釋這個答案之前,我想先回顧一下一個語言被編譯的過程:

一般編程語言的編譯過程大抵就是,編譯——連接——執(zhí)行,這里的編譯就是,把我們寫的源代碼,根據(jù)語義語法進行翻譯,形成目標代碼,即匯編碼。再由匯編程序翻譯成機器語言(可以理解為直接運行于硬件上的01語言);然后進行連接,所謂連接就是將目標代碼與函數(shù)庫相連接,并將源程序所用的庫代碼與目標代碼合并,并形成最終可執(zhí)行的二進制機器代碼(程序)。

編譯運行的整個流程,有一個前提,那就是到匯編的層面,指令編碼就和處理器的架構強關聯(lián)了,說白點就是和硬件關聯(lián)了,可以粗暴的理解為,一類硬件機器只認識一種匯編,一種機器只認一種機器碼。在這個基礎下,很容易就會發(fā)現(xiàn)一個問題,一個編程語言經(jīng)過編譯、連接形成的可運行的機器碼X,可以在硬件環(huán)境1的情況下運行,當機器碼X到硬件環(huán)境2,就未必可以運行了,或者說運行結(jié)果就不是硬件環(huán)境1的結(jié)果了,所以,同一個程序,換臺PC,我們就可能需要重新編譯、打包成可運行在當前硬件環(huán)境的程序。這樣在工程化運用中真的是災難。

現(xiàn)在我們回到開篇問題的答案,之所以Java可以“一次編譯,到處運行”,是因為有JVM,為了便于理解,我們可以這樣認為:JVM就是一個完備的中間環(huán)境,它提供編譯運行Java字節(jié)碼的全套環(huán)境,換句話說,它就像一個小隔離空間,我的Java程序只要編譯一次,只要滿足可以跑在JVM中,那它就可以隨便移植在任何硬件環(huán)境中,所以Java的“一次編譯,到處運行”的本質(zhì)就是,它處處都要依賴JVM,它其實就是一個運行在JVM中的寄生蟲,這也是為什么想要運行環(huán)境,你就必須要裝JDK的原因。

JVM的本質(zhì)和位置

上面的理解只不過是為了更快的入戲,但是上面的理解過于粗暴,下面細膩一下JVM的性質(zhì)以及它所處的位置:

通常工作中所接觸的基本是Java庫和應用以及Java核心類庫,知道如何使用就可以了,但是歸根結(jié)底代碼都是要編譯成class文件由Java虛擬機裝載執(zhí)行,所產(chǎn)生的結(jié)果或者現(xiàn)象都可以通過Java虛擬機的運行機制來解釋。一些相同的代碼會由于虛擬機的實現(xiàn)不同而產(chǎn)生不同結(jié)果。

然后是我們要介紹的JVM,首先我們要明確一個概念,JVM它并不是某一個具體的產(chǎn)品,也不是一個成品的軟件,更準確地說JVM是一種理論規(guī)范,對JVM的具體實現(xiàn)要么是軟件,要么是軟件和硬件的組合,JVM可以由不同的廠商來實現(xiàn)成不同的產(chǎn)品。由于廠商的不同必然導致JVM在實現(xiàn)上的一些不同,像國內(nèi)就有著名的TaobaoVM;

在Java平臺的結(jié)構中,可以看出,Java虛擬機(JVM)處在核心的位置,是程序與底層操作系統(tǒng)和硬件無關的關鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統(tǒng),其中依賴于平臺的部分稱為適配器;JVM通過移植接口在具體的平臺和操作系統(tǒng)上實現(xiàn);在JVM的上方是Java的基本類庫和擴展類庫以及它們的API, 利用Java API編寫的應用程序(application)和小程序(Java applet)可以在任何Java平臺上運行而無需考慮底層平臺,就是因為有Java虛擬機(JVM)實現(xiàn)了程序與操作系統(tǒng)的分離,從而實現(xiàn)了Java的平臺無關性。

JVM在它的生存周期中有一個明確的任務,那就是裝載字節(jié)碼文件,一旦字節(jié)碼進入虛擬機,它就會被解釋器解釋執(zhí)行,或者是被即時代碼發(fā)生器有選擇的轉(zhuǎn)換成機器碼執(zhí)行,即Java程序被執(zhí)行。因此當Java程序啟動的時候,就產(chǎn)生JVM的一個實例;當程序運行結(jié)束的時候,該實例也跟著消失了。

JVM的內(nèi)存模型總覽

總體來講,JVM會將Java進程所管理的內(nèi)存劃分為若干不同的數(shù)據(jù)區(qū)域. 這些區(qū)域有各自的用途、創(chuàng)建/銷毀時間。以上這張圖,就是Java的編譯運行過程,上半部分(運行時區(qū)域)其實就是JVM的內(nèi)存分配,它把從操作系統(tǒng)獲取來的內(nèi)存空間進行了獨立的劃分,分別為方法區(qū)、堆、虛擬機棧、本地方法棧、程序計數(shù)器。下半部分就是連接——運行階段的,JVM將Java語言處理完畢,變成適配與當前機器的機器碼,然后與本地庫進行連接,運行。

線程私有區(qū)域

線程私有數(shù)據(jù)區(qū)域生命周期與線程相同, 依賴用戶線程的啟動/結(jié)束而創(chuàng)建/銷毀(在Hotspot VM內(nèi), 每個線程都與操作系統(tǒng)的本地線程直接映射, 因此這部分內(nèi)存區(qū)域的存/否跟隨本地線程的生/死)。

程序計數(shù)器

一塊較小的內(nèi)存空間, 作用是當前線程所執(zhí)行字節(jié)碼的行號指示器(類似于傳統(tǒng)CPU模型中的PC), PC在每次指令執(zhí)行后自增, 維護下一個將要執(zhí)行指令的地址. 在JVM模型中, 字節(jié)碼解釋器就是通過改變PC值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復等基礎功能都需要依賴PC完成(僅限于Java方法, Native方法該計數(shù)器值為undefined).
不同于OS以進程為單位調(diào)度, JVM中的并發(fā)是通過線程切換并分配時間片執(zhí)行來實現(xiàn)的. 在任何一個時刻, 一個處理器內(nèi)核只會執(zhí)行一條線程中的指令. 因此, 為了線程切換后能恢復到正確的執(zhí)行位置, 每條線程都需要有一個獨立的程序計數(shù)器, 這類內(nèi)存被稱為“線程私有”內(nèi)存。

JAVA代碼編譯后的字節(jié)碼在未經(jīng)過JIT(實時編譯器)編譯前,其執(zhí)行方式是通過“字節(jié)碼解釋器”進行解釋執(zhí)行。簡單的工作原理為解釋器讀取裝載入內(nèi)存的字節(jié)碼,按照順序讀取字節(jié)碼指令。讀取一個指令后,將該指令“翻譯”成固定的操作,并根據(jù)這些操作進行分支、循環(huán)、跳轉(zhuǎn)等流程。

從上面的描述中,可能會產(chǎn)生程序計數(shù)器是否是多余的疑問。因為沿著指令的順序執(zhí)行下去,即使是分支跳轉(zhuǎn)這樣的流程,跳轉(zhuǎn)到指定的指令處按順序繼續(xù)執(zhí)行是完全能夠保證程序的執(zhí)行順序的。假設程序永遠只有一個線程,這個疑問沒有任何問題,也就是說并不需要程序計數(shù)器。但實際上程序是通過多個線程協(xié)同合作執(zhí)行的。

首先我們要搞清楚JVM的多線程實現(xiàn)方式。JVM的多線程是通過CPU時間片輪轉(zhuǎn)(即線程輪流切換并分配處理器執(zhí)行時間)算法來實現(xiàn)的。也就是說,某個線程在執(zhí)行過程中可能會因為時間片耗盡而被掛起,而另一個線程獲取到時間片開始執(zhí)行。當被掛起的線程重新獲取到時間片的時候,它要想從被掛起的地方繼續(xù)執(zhí)行,就必須知道它上次執(zhí)行到哪個位置,在JVM中,通過程序計數(shù)器來記錄某個線程的字節(jié)碼執(zhí)行位置。因此,程序計數(shù)器是具備線程隔離的特性,也就是說,每個線程工作時都有屬于自己的獨立計數(shù)器。

程序計數(shù)器的特點

1.線程隔離性,每個線程工作時都有屬于自己的獨立計數(shù)器。

2.執(zhí)行java方法時,程序計數(shù)器是有值的,且記錄的是正在執(zhí)行的字節(jié)碼指令的地址(參考上一小節(jié)的描述)。

3.執(zhí)行native本地方法時,程序計數(shù)器的值為空(Undefined)。因為native方法是java通過JNI直接調(diào)用本地C/C++庫,可以近似的認為native方法相當于C/C++暴露給java的一個接口,java通過調(diào)用這個接口從而調(diào)用到C/C++方法。由于該方法是通過C/C++而不是java進行實現(xiàn)。那么自然無法產(chǎn)生相應的字節(jié)碼,并且C/C++執(zhí)行時的內(nèi)存分配是由自己語言決定的,而不是由JVM決定的。

4.程序計數(shù)器占用內(nèi)存很小,在進行JVM內(nèi)存計算時,可以忽略不計。

5.程序計數(shù)器,是唯一一個在java虛擬機規(guī)范中沒有規(guī)定任何OutOfMemoryError的區(qū)域。

虛擬機棧

這里的虛擬機棧主要是針對Java的方法執(zhí)行,我們都知道方法在編程中使用的是棧的數(shù)據(jù)結(jié)構;每個方法被執(zhí)行時會創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息. 每個方法被調(diào)用至返回的過程, 就對應著一個棧幀在虛擬機棧中從入棧到出棧的過程(VM提供了-Xss來指定線程的最大??臻g, 該參數(shù)也直接決定了函數(shù)調(diào)用的最大深度)。這里特別說明一下局部變量表,這里的局部變量表,其實就是我們定義的方法內(nèi)部的變量,它基本的范圍包括基本數(shù)據(jù)類型(如boolean、int、double等) 、對象引用(reference : 不等同于對象本身, 可能是一個指向?qū)ο笃鹗嫉刂返闹羔? 也可能指向一個代表對象的句柄或其他與此對象相關的位置),也就是我們私下常說的‘堆棧'中的‘棧'。

Java虛擬機使用局部變量表來完成方法調(diào)用時的參數(shù)傳遞。局部變量表的長度在編譯期已經(jīng)決定了并存儲于類和接口的二進制表示中,一個局部變量可以保存一個類型為boolean、byte、char、short、float、reference和returnAddress的數(shù)據(jù),兩個局部變量可以保存一個類型為long和double的數(shù)據(jù)。

Java虛擬機提供一些字節(jié)碼指令來從局部變量表或者對象實例的字段中復制常量或變量值到操作數(shù)棧中,也提供了一些指令用于從操作數(shù)棧取走數(shù)據(jù)、操作數(shù)據(jù)和把操作結(jié)果重新入棧。在方法調(diào)用的時候,操作數(shù)棧也用來準備調(diào)用方法的參數(shù)以及接收方法返回結(jié)果。

每個棧幀中都包含一個指向運行時常量區(qū)的引用支持當前方法的動態(tài)鏈接。在Class文件中,方法調(diào)用和訪問成員變量都是通過符號引用來表示的,動態(tài)鏈接的作用就是將符號引用轉(zhuǎn)化為實際方法的直接引用或者訪問變量的運行是內(nèi)存位置的正確偏移量。

總的來說,Java虛擬機棧是用來存放局部變量和過程結(jié)果的地方。
Java虛擬機棧可能發(fā)生如下異常情況: 如果Java虛擬機棧被實現(xiàn)為固定大小內(nèi)存,線程請求分配的棧容量超過Java虛擬機棧允許的最大容量時,Java虛擬機將會拋出一個StackOverflowError異常。
如果Java虛擬機棧被實現(xiàn)為動態(tài)擴展內(nèi)存大小,并且擴展的動作已經(jīng)嘗試過,但是目前無法申請到足夠的內(nèi)存去完成擴展,或者在建立新的線程時沒有足夠的內(nèi)存去創(chuàng)建對應的虛擬機棧,那Java虛擬機將會拋出一個OutOfMemoryError異常。

1.符號引用(Symbolic References):

符號引用以一組符號來描述所引用的目標,符號可以是任何形式的字面量,只要使用時能夠無歧義的定位到目標即可。例如,在Class文件中它以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等類型的常量出現(xiàn)。符號引用與虛擬機的內(nèi)存布局無關,引用的目標并不一定加載到內(nèi)存中。在Java中,一個java類將會編譯成一個class文件。在編譯時,java類并不知道所引用的類的實際地址,因此只能使用符號引用來代替。比如org.simple.People類引用了org.simple.Language類,在編譯時People類并不知道Language類的實際內(nèi)存地址,因此只能使用符號org.simple.Language(假設是這個,當然實際中是由類似于CONSTANT_Class_info的常量來表示的)來表示Language類的地址。各種虛擬機實現(xiàn)的內(nèi)存布局可能有所不同,但是它們能接受的符號引用都是一致的,因為符號引用的字面量形式明確定義在Java虛擬機規(guī)范的Class文件格式中。

2.直接引用:

直接引用可以是

(1)直接指向目標的指針(比如,指向“類型”【Class對象】、類變量、類方法的直接引用可能是指向方法區(qū)的指針)

(2)相對偏移量(比如,指向?qū)嵗兞?、實例方法的直接引用都是偏移量?/p>

(3)一個能間接定位到目標的句柄

直接引用是和虛擬機的布局相關的,同一個符號引用在不同的虛擬機實例上翻譯出來的直接引用一般不會相同。如果有了直接引用,那引用的目標必定已經(jīng)被加載入內(nèi)存中了。

本地方法棧

本地方法棧其實作用和虛擬機棧的作用一樣,不同的是,虛擬機棧是為虛擬機解析運行Java方法,而本地方法棧是為虛擬機調(diào)用Native方法服務(Native方法簡單點來說就是一個java調(diào)用非java代碼的接口。一個Native 方法是這樣一個java的方法:該方法的實現(xiàn)由非java語言實現(xiàn))

線程共享區(qū)域

這一區(qū)域的生命周期,同虛擬機一致,也就是虛擬機內(nèi)部的公共內(nèi)存區(qū)域,隨虛擬機的啟動/關閉而創(chuàng)建/銷毀

堆區(qū)

這里的堆,是虛擬機從操作系統(tǒng)那里申請來的的內(nèi)存空間,這塊空間是Java虛擬機所管理的內(nèi)存中最大的一塊,并且是所有線程共享的一塊內(nèi)存區(qū)域,Java堆在虛擬機啟動的時候被創(chuàng)建,主要用來為類實例對象和數(shù)組分配內(nèi)存。這塊區(qū)域可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可,就像我們的磁盤空間一樣,在實現(xiàn)時,既可以實現(xiàn)成固定大小的,也可以是擴展的,如果是可擴展的,則通過(-Xmx和-Xms控制),如果在隊中沒有內(nèi)存完成實例分配,并且堆也無法再擴展時,將會拋出OutOfMemoryError異常。

Java堆是垃圾回收器管理的主要區(qū)域,很多時候也被稱為“GC”堆,在現(xiàn)在的實現(xiàn)上,堆被劃分成兩個不同的區(qū)域:新生代( Young )、老年代( Old );這也就是JVM采用的“分代收集算法”,簡單說,就是針對不同特征的java對象采用不同的 策略實施存放和回收,自然所用分配機制和回收算法就不一樣。新生代( Young ) 又被劃分為三個區(qū)域:Eden、From Survivor、To Survivor。

方法區(qū)

方法區(qū)和Java堆一樣,是各個線程共享的內(nèi)存區(qū)域,用于存儲已被虛擬機加載的類信息,常量、靜態(tài)變量,還包括在類、實例、接口初始化時用到的特殊方法。虛擬機規(guī)范上把方法區(qū)描述為堆的一個邏輯部分,但是它卻有一個別名叫做“非堆”,目的就是與Java的堆區(qū)分開來。

直接內(nèi)存

直接內(nèi)存并不是JVM運行時數(shù)據(jù)區(qū)的一部分, 但也會被頻繁的使用: 在JDK 1.4引入的NIO提供了基于Channel與Buffer的IO方式, 它可以使用Native函數(shù)庫直接分配堆外內(nèi)存, 然后使用DirectByteBuffer對象作為這塊內(nèi)存的引用進行操作(詳見: Java I/O 擴展), 這樣就避免了在Java堆和Native堆中來回復制數(shù)據(jù), 因此在一些場景中可以顯著提高性能。
顯然, 本機直接內(nèi)存的分配不會受到Java堆大小的限制(即不會遵守-Xms、-Xmx等設置), 但既然是內(nèi)存, 則肯定還是會受到本機總內(nèi)存大小及處理器尋址空間的限制, 因此動態(tài)擴展時也會出現(xiàn)OutOfMemoryError異常。

從例子來理解內(nèi)存模型

這里我們引入一個比較簡單的程序樣例,從具體的代碼角度去理解Jvm的內(nèi)存

一個person類

public class Persion {
    private String name;
    public static String aninmal = "dog" 
    
     public Persion(String name){
        this.name = name
    }

    public String getName() {
        return name;
    }
   
    public void setName(String name) {
        this.name = name;
    }

   
}

一個App類

public class App 
{
    public static void main( String[] args )
    {
        Persion persion1 = new Persion("張三"); 
        Persion persion2 = new Persion("李四");
        persoion1.setName("王五");
     } 
}

程序開始運行,系統(tǒng)啟動了一個Java虛擬機進程,Java虛擬機定位到方法區(qū)中App類的main()方法的字節(jié)碼,開始執(zhí)行它的指令。分別去創(chuàng)建Persion1和Persion2(這里我們以persion對象為跟蹤點)

1、程序從main方法開始執(zhí)行,既然提到了方法,根據(jù)上面的知識,我們知道,它首先會在棧區(qū)動工。在JAVA虛擬機進程中,每個線程都會擁有一個方法調(diào)用棧,用來跟蹤線程運行中一系列的方法調(diào)用過程,棧中的每一個元素就被稱為棧幀,每當線程調(diào)用一個方法的時候就會向方法棧壓入一個新幀。這里的幀用來存儲方法的參數(shù)、局部變量和運算過程中的臨時數(shù)據(jù)。這時候執(zhí)行main方法的主線程會在棧區(qū)申請一片區(qū)域。根據(jù)源碼,它會識別出persion1和persion2分別為兩個變量,并且給它們定性是方法內(nèi)局部變量,因此,它被會添加到了執(zhí)行main()方法的主線程的JAVA方法調(diào)用棧中。

2、 接下來就是 “=” 賦值操作了,Java虛擬機接受運行指令,發(fā)現(xiàn)右側(cè)是個對象實例,于是就直奔方法區(qū)而去,試圖找到Persion類的類型信息。首次運行,發(fā)現(xiàn)并沒有找到Persion的信息,這時候Java虛擬機根據(jù)預設的規(guī)則,在無法找到類信息的情況下,自行去加載Persion類,把Persion類的類型信息存放在方法區(qū)里。

3、 現(xiàn)在Persion類的信息已經(jīng)被加載到了方法區(qū),這里Persion類中的靜態(tài)變量animal也會被填充上值“dog”存放于方法區(qū),此時Java虛擬機根據(jù)我們代碼中的兩句new指令,分別去堆中劃出兩塊內(nèi)存區(qū)域,分別用于存放persion實例1和persion實例2,這兩個實例對象分別擁有自己獨立的內(nèi)存空間, 同時這倆實例持有著指向方法區(qū)的Persion類的類型信息的引用。這里所說的引用,實際上指的是Persion類的類型信息在方法區(qū)中的內(nèi)存地址,其實,就是有點類似于C語言里的指針,而這個地址呢,就存放了在persion實例1、persopn實例2的數(shù)據(jù)區(qū)里。我們也能發(fā)現(xiàn)persion實例1和persion實例2共享animal這個變量,也就是說,無論使用哪一個引用(persion1和persion2)去修改這個animal變量,任何一個Persion對象使用這個變量的時候,都會發(fā)生改變。

4、到此為止已經(jīng)將main方法中的兩個成員變量persion1和persion2分別關聯(lián)到了堆中的對象。當Java虛擬機執(zhí)行到persion1.setName()的時候,Java虛擬機根據(jù)main方法棧區(qū)中的persion1變量,定位到堆中的Persion名字為張三的實例(persion實例1),再根據(jù)這個實例所持有的類信息引用(或者說指針),定位到方法區(qū)的Persion類信息,從中獲得setName(String name)方法,然后棧區(qū)再壓入一個新幀,并在其中完成參數(shù)(String name)的復制,然后根據(jù)指令,將堆中的Persion實例1 空間中的Name變成“王五”,然后結(jié)束

以上就是詳解Java的內(nèi)存模型的詳細內(nèi)容,更多關于Java的內(nèi)存模型的資料請關注腳本之家其它相關文章!

相關文章

  • Java調(diào)用外接設備詳解(制卡機)

    Java調(diào)用外接設備詳解(制卡機)

    這篇文章主要為大家詳細介紹了Java調(diào)用外接設備的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • spring @profile注解的使用方法

    spring @profile注解的使用方法

    本篇文章主要介紹了spring @profile注解的使用方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • java swing實現(xiàn)電影購票系統(tǒng)

    java swing實現(xiàn)電影購票系統(tǒng)

    這篇文章主要為大家詳細介紹了java swing實現(xiàn)電影購票系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • request如何獲取完整url(包括域名、端口、參數(shù))

    request如何獲取完整url(包括域名、端口、參數(shù))

    這篇文章主要介紹了request如何獲取完整url(包括域名、端口、參數(shù))問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • spring cloud gateway請求跨域問題解決方案

    spring cloud gateway請求跨域問題解決方案

    這篇文章主要介紹了spring cloud gateway請求跨域問題解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • 如何提高java代碼的重用性

    如何提高java代碼的重用性

    在本篇文章中小編給各位分享了關于如何提高java代碼的重用性的相關知識點內(nèi)容,有需要的朋友們參考下。
    2019-07-07
  • 對象轉(zhuǎn)Json字符串時如何忽略指定屬性

    對象轉(zhuǎn)Json字符串時如何忽略指定屬性

    這篇文章主要介紹了對象轉(zhuǎn)Json字符串時如何忽略指定屬性,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • IDEA快速搭建Java開發(fā)環(huán)境的教程圖解

    IDEA快速搭建Java開發(fā)環(huán)境的教程圖解

    這篇文章主要介紹了IDEA如何快速搭建Java開發(fā)環(huán)境,本文通過圖文并茂的形式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-11-11
  • Spring Security6配置方法(廢棄WebSecurityConfigurerAdapter)

    Spring Security6配置方法(廢棄WebSecurityConfigurerAdapter)

    本文主要介紹了Spring Security6配置方法(廢棄WebSecurityConfigurerAdapter),就像文章標題所說的,SpringSecurity已經(jīng)廢棄了繼承WebSecurityConfigurerAdapter的配置方式,下面就來詳細的介紹一下,感興趣的可以了解一下
    2023-12-12
  • Java常用字節(jié)流和字符流實例匯總

    Java常用字節(jié)流和字符流實例匯總

    這篇文章主要介紹了Java常用字節(jié)流和字符流實例匯總,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07

最新評論