Spring工作原理

Java 學(xué)習(xí)記錄

Spring工作原理

內(nèi)部最核心的就是IOC了,
1、動(dòng)態(tài)注入,讓一個(gè)對(duì)象的創(chuàng)建不用new了,可以自動(dòng)的生產(chǎn),這其實(shí)就是利用java里的反射(反射其實(shí)就是在運(yùn)行時(shí)動(dòng)態(tài)的去創(chuàng)建、調(diào)用對(duì)象,Spring就是在運(yùn)行時(shí),跟xml Spring的配置文件來(lái)動(dòng)態(tài)的創(chuàng)建對(duì)象,和調(diào)用對(duì)象里的方法的 )。
2、Spring還有一個(gè)核心就是AOP這個(gè)就是面向切面編程,可以為某一類對(duì)象 進(jìn)行監(jiān)督和控制(也就是在調(diào)用這類對(duì)象的具體方法的前后去調(diào)用你指定的模塊)從而達(dá)到對(duì)一個(gè)模塊擴(kuò)充的功能。這些都是通過(guò)配置類達(dá)到的。

```  要記?。篠pring是一個(gè)容器,凡是在容器里的對(duì)象才會(huì)有Spring所提供的這些服務(wù)和功能。

Spring里用的最經(jīng)典的一個(gè)設(shè)計(jì)模式就是:模板方法模式。(這里我都不介紹了,是一個(gè)很常用的設(shè)計(jì)模式)Spring里的配置是很多的,很難都記住,但是Spring里的精華也無(wú)非就是以上的兩點(diǎn),把以上兩點(diǎn)跟理解了 也就基本上掌握了Spring.

Spring AOP與IOC

一、 IoC(Inversion of control): 控制反轉(zhuǎn)
1、IoC:
概念:控制權(quán)由對(duì)象本身轉(zhuǎn)向容器;由容器根據(jù)配置文件去創(chuàng)建實(shí)例并創(chuàng)建各個(gè)實(shí)例之間的依賴關(guān)系
核心:bean工廠;在Spring中,bean工廠創(chuàng)建的各個(gè)實(shí)例稱作bean
二、AOP(Aspect-Oriented Programming): 面向方面編程
1、 代理的兩種方式:
靜態(tài)代理:
? 針對(duì)每個(gè)具體類分別編寫(xiě)代理類;
? 針對(duì)一個(gè)接口編寫(xiě)一個(gè)代理類;
動(dòng)態(tài)代理:
針對(duì)一個(gè)方面編寫(xiě)一個(gè)InvocationHandler,然后借用JDK反射包中的Proxy類為各種接口動(dòng)態(tài)生成相應(yīng)的代理類

Spring 優(yōu)缺點(diǎn)

它是一個(gè)開(kāi)源的項(xiàng)目,而且目前非常活躍;它基于IoC(Inversion of Control,反向控制)和AOP的構(gòu)架多層j2ee系統(tǒng)的框架,但它不強(qiáng)迫你必須在每一層 中必須使用Spring,因?yàn)樗K化的很好,允許你根據(jù)自己的需要選擇使用它的某一個(gè)模塊;它實(shí)現(xiàn)了很優(yōu)雅的MVC,對(duì)不同的數(shù)據(jù)訪問(wèn)技術(shù)提供了統(tǒng)一的 接口,采用IoC使得可以很容易的實(shí)現(xiàn)bean的裝配,提供了簡(jiǎn)潔的AOP并據(jù)此實(shí)現(xiàn)Transcation Managment,等等優(yōu)點(diǎn)

  • Spring能有效地組織你的中間層對(duì)象,不管你是否選擇使用了EJB。如果你僅僅使用了Struts或其他為J2EE的 API特制的framework,Spring致力于解決剩下的問(wèn)題。
  • Spring能消除在許多工程中常見(jiàn)的對(duì)Singleton的過(guò)多使用。根據(jù)我的經(jīng)驗(yàn),這是一個(gè)很大的問(wèn)題,它降低了系統(tǒng)的可測(cè)試性和面向?qū)ο蟮某潭取?/li>
  • 通過(guò)一種在不同應(yīng)用程序和項(xiàng)目間一致的方法來(lái)處理配置文件,Spring能消除各種各樣自定義格式的屬性文件的需要。曾經(jīng)對(duì)某個(gè)類要尋找的是哪個(gè)魔法般的屬性項(xiàng)或系統(tǒng)屬性感到不解,為此不得不去讀Javadoc甚至源編碼?有了Spring,你僅僅需要看看類的JavaBean屬性。Inversion of Control的使用(在下面討論)幫助完成了這種簡(jiǎn)化。
  • 通過(guò)把對(duì)接口編程而不是對(duì)類編程的代價(jià)幾乎減少到?jīng)]有,Spring能夠促進(jìn)養(yǎng)成好的編程習(xí)慣。
  • Spring被設(shè)計(jì)為讓使用它創(chuàng)建的應(yīng)用盡可能少的依賴于他的APIs。在Spring應(yīng)用中的大多數(shù)業(yè)務(wù)對(duì)象沒(méi)有依賴于Spring。
  • 使用Spring構(gòu)建的應(yīng)用程序易于單元測(cè)試。
  • Spring能使EJB的使用成為一個(gè)實(shí)現(xiàn)選擇,而不是應(yīng)用架構(gòu)的必然選擇。你能選擇用POJOs或local EJBs來(lái)實(shí)現(xiàn)業(yè)務(wù)接口,卻不會(huì)影響調(diào)用代碼。
  • Spring幫助你解決許多問(wèn)題而無(wú)需使用EJB。Spring能提供一種EJB的替換物,它們適用于許多web應(yīng)用。例如,Spring能使用AOP提供聲明性事務(wù)管理而不通過(guò)EJB容器,如果你僅僅需要與單個(gè)數(shù)據(jù)庫(kù)打交道,甚至不需要一個(gè)JTA實(shí)現(xiàn)。
  • Spring為數(shù)據(jù)存取提供了一個(gè)一致的框架,不論是使用的是JDBC還是O/R mapping產(chǎn)品(如Hibernate)。
    Spring確實(shí)使你能通過(guò)最簡(jiǎn)單可行的解決辦法來(lái)解決你的問(wèn)題。而這是有有很大價(jià)值的。

缺點(diǎn):jsp中要寫(xiě)很多代碼、控制器過(guò)于靈活,缺少一個(gè)公用控制器

Spring MVC 五大組件

1、dispatcherServlet 前端控制器

2、HandleMapping 映射處理器

3、Controller 處理器

4、ModelAndView模型和試圖

5、ViewResolver 試圖解析器

提交到DispatcherServlet 由DispatcherServlet控制器查詢一個(gè)或多個(gè)HandleMapping,找到處理請(qǐng)求的Controller DispatcherServlet 將請(qǐng)求提交到Controller Controller 調(diào)用業(yè)務(wù)邏輯處理后,返回ModelAndView DispatcherServlet查詢一個(gè)或多個(gè)ViewResoler視圖解析器,找到ModelAndView指定的視圖,視圖負(fù)責(zé)將結(jié)果顯示到客戶

Spring 原理

  1. 內(nèi)部最核心的就是IOC了,動(dòng)態(tài)注入,讓一個(gè)對(duì)象的創(chuàng)建不用New了,可以自動(dòng)的生產(chǎn),這其實(shí)就是利用Java里的反射,反射其實(shí)就是在運(yùn)行時(shí)動(dòng)態(tài)的去創(chuàng)建,調(diào)用對(duì)象,Spring 就是在運(yùn)行時(shí),跟xml Spring的配置文件來(lái)動(dòng)態(tài)的創(chuàng)建對(duì)象,和調(diào)用對(duì)象里的方法。
  2. Spring 還有一個(gè)核心就是AOP,這個(gè)就是面向切面編程,可以為某一類對(duì)象進(jìn)行監(jiān)督和控制(也就是在調(diào)用這類對(duì)象的具體方法的前后去調(diào)用你指定的模塊)從而達(dá)到對(duì)一個(gè)模塊擴(kuò)充的功能,這些都是通過(guò)配置類達(dá)到的。
  • Spring 的目的: 就是讓對(duì)象與對(duì)象(模塊與模塊)之間的關(guān)系沒(méi)有通過(guò)代碼關(guān)聯(lián),都是通過(guò)配置類聲明管理的,(Spring根據(jù)這些配置,內(nèi)部通過(guò)反射動(dòng)態(tài)的組裝對(duì)象)
    要記?。篠pring 是一個(gè)容器,凡是在容器里的對(duì)象才有Spring所提供的這些服務(wù)和功能。
    Spring 里用的最經(jīng)典的這個(gè)設(shè)計(jì)模式就是:模塊方法模式。

SpringAop和IOC

一、IOC(inversion of Control)控制反轉(zhuǎn)
概念:控制權(quán)由對(duì)象本身轉(zhuǎn)向容器,有容器根據(jù)配置文件去創(chuàng)建實(shí)例并創(chuàng)建各個(gè)實(shí)例之間的依賴關(guān)系
核心:bean工廠,在Spring中,bean工廠創(chuàng)建的各個(gè)實(shí)例稱作bean

二、AOP(Aspect-Oriented Programming):面向切面編程
1、代理的兩種方式:
靜態(tài)代理:
針對(duì)每個(gè)具體類分別編寫(xiě)代理類;
針對(duì)一個(gè)接口編寫(xiě)一個(gè)代理類;
動(dòng)態(tài)代理:
針對(duì)一個(gè)方面編寫(xiě)一個(gè)InvocationHandler,然后借用JDK反射包中的Proxy類為各種接口動(dòng)態(tài)生成相應(yīng)的的代理類

什么的反射

什么是類的反射
通過(guò)類的聲明可以得到類的父類,實(shí)現(xiàn)的接口,內(nèi)部類,構(gòu)造函數(shù)、方法,屬性并可以根據(jù)構(gòu)造實(shí)例化一個(gè)對(duì)象,喚起一個(gè)方法,取屬性值,改屬性值,

三、 Spring的三種注入方式是什么
Setter、interface、constructor

四、Spring 的核心接口及核類配置文件是什么
FactoryBean:工廠bean主要實(shí)現(xiàn)ioc/di
ApplicationContext ac = new FileXmlApplicationContext(“applicationContext.xml”);

五、Spring框架的7個(gè)模塊
Spring Aop (面對(duì)切面編程),Spring ORM ,Spring Web, Spring DAO, Spring Context,Spring Web MVC, Spring Core

對(duì)jvm的理解,

jvm就是java虛擬機(jī),jvm的內(nèi)部體系結(jié)構(gòu)分為三部分,分別是:類加載器(ClassLoader)子系統(tǒng),運(yùn)行區(qū)、執(zhí)行引擎。
每一個(gè)Java虛擬機(jī)都由一個(gè)類加載器子系統(tǒng),負(fù)責(zé)加載程序中的類型(類和接口),并賦予唯一的名字,每一個(gè)Java虛擬機(jī)都有一個(gè)執(zhí)行引擎,負(fù)責(zé)執(zhí)行被加載類中包含的指令。JVM的兩種類裝載起包括:?jiǎn)?dòng)類裝載和用戶自定義類裝載器啟動(dòng)類裝載器是JVM實(shí)現(xiàn)的一部分,用戶自定義類裝載器則是Java程序的一部分,必須是ClassLoader類的子類。```

運(yùn)行時(shí)數(shù)據(jù)區(qū):主要包括:方法區(qū),堆,Java棧,PC寄存器,本地方法棧
JVM 內(nèi)存模塊劃分

  1. 方法區(qū)

被所有方法線程共享的一塊內(nèi)存區(qū)域。用于存儲(chǔ)已經(jīng)被虛擬機(jī)加載的類信息,常量,靜態(tài)變量等,這個(gè)區(qū)域的內(nèi)存回收目標(biāo)主要針對(duì)常量池的回收和堆類型的卸載。

  1. 虛擬機(jī)棧

java 虛擬棧也是私有的,每個(gè)方法在執(zhí)行的時(shí)候也會(huì)創(chuàng)建一個(gè)棧幀,存儲(chǔ)了局部變量,操作數(shù), 動(dòng)態(tài)鏈接,方法返回地址。每個(gè)方法從調(diào)用到執(zhí)行完畢,對(duì)應(yīng)一個(gè)幀在虛擬機(jī)棧中的入棧和出棧。
所以通常所說(shuō)的的棧,一般是指在虛擬機(jī)棧中的局部變量部分。局部變量所需要的內(nèi)存在編譯期間完成分配,如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,則StackOverFlowError。
如果虛擬機(jī)長(zhǎng)可以動(dòng)態(tài)擴(kuò)展,擴(kuò)展到無(wú)法申請(qǐng)足夠的內(nèi)存,則OutOfMemoryError。

  1. 本地方法棧(線程私有)

和虛擬機(jī)棧類似,主要虛擬機(jī)使用到的Native方法服務(wù)。也會(huì)拋出StackOverFlowError和OutOfMemoryError

被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)的時(shí)候創(chuàng)建,用于存放對(duì)象實(shí)例。對(duì)可以按照可擴(kuò)展來(lái)實(shí)現(xiàn)(通過(guò)-Xmx和Xms來(lái)控制)當(dāng)對(duì)中沒(méi)有內(nèi)存克分配給實(shí)例,也無(wú)法在擴(kuò)展時(shí),則拋出OutOfMemoryError異常。

  1. 程序計(jì)數(shù)器(線程私有)

程序計(jì)數(shù)器是當(dāng)前線程鎖執(zhí)行行字節(jié)碼的行號(hào)治時(shí)期,每條線程都有一個(gè)獨(dú)立的線程計(jì)數(shù)器,這類內(nèi)存也稱為”線程私有“的內(nèi)存。正在執(zhí)行java的話,計(jì)數(shù)器記錄的是虛擬機(jī)字節(jié)碼指令的地址(當(dāng)前指令的地址)。如果是Native方法,則為空。

GC原理,性能調(diào)優(yōu)

通過(guò)IDEA 運(yùn)行JAVA代碼,java代碼執(zhí)行過(guò)程

  1. 編譯源代碼
  2. 編譯java文件生成字節(jié)碼文件
  3. JVM 中的類加載器,加載字節(jié)碼文件
  4. JVM 中的執(zhí)行引擎找到入口方法main(),執(zhí)行其中的方法

JVM 垃圾回收

JVM回收原理,把對(duì)象分為年青代、年老代,持久代,對(duì)不同生命周期的對(duì)象使用不同的算法。(基于對(duì)對(duì)象生命周期分析)
通常我們說(shuō)的JVM內(nèi)存回收總是在指堆內(nèi)存回收,確實(shí)只有堆中的內(nèi)容是動(dòng)態(tài)生氣分配的,所以以上對(duì)象的年青代和年老代都是指的JVM的Heap空間, 而持久代則是之前提到的MethodArea,不屬于Head。

  1. GC 的基本原理:講內(nèi)存中不再被使用的對(duì)象進(jìn)行回收,GC中用于回收的方法稱為收集器,由于GC需要消耗一些資源和時(shí)間,Java在對(duì)對(duì)象的生命周期特征進(jìn)行分析后,按照新生代,舊生代的方式來(lái)對(duì)對(duì)象進(jìn)行收集,以盡可能的縮短GC對(duì)應(yīng)用造成的暫停
    1)對(duì)新生代的對(duì)象的收集稱為minor GC;
    2)對(duì)舊生代的對(duì)象的收集稱為Full GC;
    3)程序中主動(dòng)調(diào)用System.gc()強(qiáng)制執(zhí)行的GC為Full GC
    不同的對(duì)象引用類型,GC會(huì)采用不同的方法進(jìn)行回收,JVM對(duì)象的引用分為了四種類型:
  1. 強(qiáng)引用:默認(rèn)情況下,對(duì)象采用的均為強(qiáng)引用(這個(gè)對(duì)象的實(shí)例沒(méi)有其他對(duì)象引用,GC時(shí)才會(huì)被銷毀回收)
  2. 軟引用:軟引用是Java中提供的一種比較合適與緩存場(chǎng)景的應(yīng)用(只有在內(nèi)存不夠的用的情況下才會(huì)被回收)
  3. 虛引用:由于虛引用只是用來(lái)得知對(duì)象是否被GC

JVM的對(duì)象分配規(guī)則

對(duì)象優(yōu)先分配在Eden區(qū)【使用空間】,如果Eden區(qū)沒(méi)有足夠的空間時(shí),虛擬機(jī)執(zhí)行一次Minor GC【垃圾回收】。
大對(duì)象直接進(jìn)入老年代(大對(duì)象是指需要大量連續(xù)內(nèi)存空間的對(duì)象)。這樣做的目的是避免在Eden區(qū)和兩個(gè)Survivor區(qū)之間發(fā)生大量的內(nèi)存拷貝(新生代采用復(fù)制算法收集內(nèi)存)。
長(zhǎng)期存活的對(duì)象進(jìn)入老年代。虛擬機(jī)為每個(gè)對(duì)象定義了一個(gè)年齡計(jì)數(shù)器,如果對(duì)象經(jīng)過(guò)了1次Minor GC(年輕代收集)那么對(duì)象會(huì)進(jìn)入Survivor區(qū),之后每經(jīng)過(guò)一次Minor GC那么對(duì)象的年齡加1,直到達(dá)到閥值對(duì)象進(jìn)入老年區(qū)。
動(dòng)態(tài)判斷對(duì)象的年齡。如果Survivor區(qū)中相同年齡的所有對(duì)象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對(duì)象可以直接進(jìn)入老年代。
空間分配擔(dān)保。每次進(jìn)行Minor GC時(shí),JVM會(huì)計(jì)算Survivor區(qū)移至老年區(qū)的對(duì)象的平均大小,如果這個(gè)值大于老年區(qū)的剩余值大小則進(jìn)行一次Full GC,如果小于檢查HandlePromotionFailure設(shè)置,如果true則只進(jìn)行Monitor GC,如果false則進(jìn)行Full GC。

簡(jiǎn)要概括如下

  • 對(duì)象先在Eden區(qū),Eden區(qū)空間不夠時(shí)進(jìn)行新生代GC
  • 大對(duì)象和長(zhǎng)期存活的對(duì)象進(jìn)入老年代
  • JVM為每個(gè)對(duì)象設(shè)置了計(jì)數(shù)器,經(jīng)過(guò)1次新生代GC則進(jìn)入幸存者區(qū),達(dá)到年齡閾值則進(jìn)入老年區(qū)
  • 幸存者區(qū)中年齡一致的對(duì)象所占內(nèi)存大小,大于幸存者區(qū)空間一半時(shí),則大于等于此年齡的對(duì)象全部進(jìn)入老年代
  • 老年代GC通常伴隨著一次新生代GC,但不絕對(duì)

YOUNG(年輕代)

年輕代分為三個(gè)區(qū),一個(gè)Eden區(qū),兩個(gè)Survivor區(qū)。大部分對(duì)象在Eden去中生成。當(dāng)Eden區(qū)滿時(shí),還存活的對(duì)象將被復(fù)制到Survivor區(qū),當(dāng)這個(gè)Survivor區(qū)也滿的時(shí)候,從第一個(gè)Survivor的兩個(gè)區(qū)復(fù)制過(guò)來(lái)的并且此時(shí)還存活的對(duì)象,將被復(fù)制到年老區(qū)(Survivor的兩個(gè)區(qū)是對(duì)稱的,沒(méi)有先后關(guān)系,所以同一個(gè)區(qū)可能同時(shí)存在從Eden復(fù)制過(guò)來(lái)的對(duì)象,和從前一個(gè)Survivor復(fù)制過(guò)來(lái)的對(duì)象,而復(fù)制到年老區(qū)的只有從第一個(gè)Survivor去過(guò)去的對(duì)象,并且Survivor區(qū)總有一個(gè)是空的)。

Tenured 年老代

年老代存放從年輕代存活的對(duì)象,一般來(lái)說(shuō)年老代存放的都是生命周期較長(zhǎng)的對(duì)象。

持久代Perm

用于存放靜態(tài)文件,如今Java類,方法等,持久代對(duì)垃圾回收沒(méi)有明顯的影響,但是有些應(yīng)用可能動(dòng)態(tài)生成活調(diào)用一些class,列如Hibernate等,在這種時(shí)候需要設(shè)置一個(gè)比較大的持久代空間來(lái)存放這些運(yùn)行過(guò)程新增的類。持久代大小通過(guò)-XX:MaxPermSize 進(jìn)行設(shè)置。

一、什么是類的加載

類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后在堆區(qū)創(chuàng)建一個(gè)java.lang.Class對(duì)象,用來(lái)封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。類的加載的最終產(chǎn)品是位于堆區(qū)中的Class對(duì)象,Class對(duì)象封裝了類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu),并且向Java程序員提供了訪問(wèn)方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)的接口。

  • 啟動(dòng)類加載器:Bootstrap ClassLoader,負(fù)責(zé)加載存放在JDK\jre\lib(JDK代表JDK的安裝目錄,下同)下,或被-Xbootclasspath參數(shù)指定的路徑中的,并且能被虛擬機(jī)識(shí)別的類庫(kù)
  • 擴(kuò)展類加載器:Extension ClassLoader,該加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),它負(fù)責(zé)加載DK\jre\lib\ext目錄中,或者由java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫(kù)(如javax.*開(kāi)頭的類),開(kāi)發(fā)者可以直接使用擴(kuò)展類加載器。
  • 應(yīng)用程序類加載器:Application ClassLoader,該類加載器由sun.misc.Launcher$AppClassLoader來(lái)實(shí)現(xiàn),它負(fù)責(zé)加載用戶類路徑(ClassPath)所指定的類,開(kāi)發(fā)者可以直接使用該類加載器

三、JVM加載class文件的原理

JVM中類的裝載是由類加載器(ClassLoader)和它的子類來(lái)實(shí)現(xiàn)的,Java中的類加載器是一個(gè)重要的Java運(yùn)行時(shí)系統(tǒng)組件,它負(fù)責(zé)在運(yùn)行時(shí)查找和裝入類文件中的類。

由于Java的跨平臺(tái)性,經(jīng)過(guò)編譯的Java源程序并不是一個(gè)可執(zhí)行程序,而是一個(gè)或多個(gè)類文件。當(dāng)Java程序需要使用某個(gè)類時(shí),JVM會(huì)確保這個(gè)類已經(jīng)被加載、連接(驗(yàn)證、準(zhǔn)備和解析)和初始化。類的加載是指把類的.class文件中的數(shù)據(jù)讀入到內(nèi)存中,通常是創(chuàng)建一個(gè)字節(jié)數(shù)組讀入.class文件,然后產(chǎn)生與所加載類對(duì)應(yīng)的Class對(duì)象。加載完成后,Class對(duì)象還不完整,所以此時(shí)的類還不可用。當(dāng)類被加載后就進(jìn)入連接階段,這一階段包括驗(yàn)證、準(zhǔn)備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認(rèn)的初始值)和解析(將符號(hào)引用替換為直接引用)三個(gè)步驟。最后JVM對(duì)類進(jìn)行初始化,包括:

如果類存在直接的父類并且這個(gè)類還沒(méi)有被初始化,那么就先初始化父類;
如果類中存在初始化語(yǔ)句,就依次執(zhí)行這些初始化語(yǔ)句。
  類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴(kuò)展加載器(Extension)、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。

從Java 2(JDK 1.2)開(kāi)始,類加載過(guò)程采取了父親委托機(jī)制(PDM)。PDM更好的保證了Java平臺(tái)的安全性,在該機(jī)制中,JVM自帶的Bootstrap是根加載器,其他的加載器都有且僅有一個(gè)父類加載器。類的加載首先請(qǐng)求父類加載器加載,父類加載器無(wú)能為力時(shí)才由其子類加載器自行加載。JVM不會(huì)向Java程序提供對(duì)Bootstrap的引用。下面是關(guān)于幾個(gè)類加載器的說(shuō)明:

Bootstrap:一般用本地代碼實(shí)現(xiàn),負(fù)責(zé)加載JVM基礎(chǔ)核心類庫(kù)(rt.jar);
Extension:從java.ext.dirs系統(tǒng)屬性所指定的目錄中加載類庫(kù),它的父加載器是Bootstrap;
System:又叫應(yīng)用類加載器,其父類是Extension。它是應(yīng)用最廣泛的類加載器。它從環(huán)境變量classpath或者系統(tǒng)屬性java.class.path所指定的目錄中記載類,是用戶自定義加載器的默認(rèn)父加載器。

四、Java對(duì)象創(chuàng)建過(guò)程

(1)JVM遇到一條新建對(duì)象的指令時(shí)首先去檢查這個(gè)指令的參數(shù)是否能在常量池中定義到一個(gè)類的符號(hào)引用。然后加載這個(gè)類(類加載過(guò)程在后邊講)
(2)為對(duì)象分配內(nèi)存。一種辦法“指針碰撞”、一種辦法“空閑列表”,最終常用的辦法“本地線程緩沖分配(TLAB)”
(3)將除對(duì)象頭外的對(duì)象內(nèi)存空間初始化為0
(4)對(duì)對(duì)象頭進(jìn)行必要設(shè)置

五、類的生命周期

類的生命周期包括這幾個(gè)部分,加載、連接、初始化、使用和卸載,其中前三部是類的加載的過(guò)程,如下圖:

加載,查找并加載類的二進(jìn)制數(shù)據(jù),在Java堆中也創(chuàng)建一個(gè)java.lang.Class類的對(duì)象
連接,連接又包含三塊內(nèi)容:驗(yàn)證、準(zhǔn)備、初始化。
(1)驗(yàn)證,文件格式、元數(shù)據(jù)、字節(jié)碼、符號(hào)引用驗(yàn)證;
(2)準(zhǔn)備,為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值;
(3)解析,把類中的符號(hào)引用轉(zhuǎn)換為直接引用
初始化,為類的靜態(tài)變量賦予正確的初始值
使用,new出對(duì)象程序中使用
卸載,執(zhí)行垃圾回收

六、Java對(duì)象結(jié)構(gòu)

Java對(duì)象由三個(gè)部分組成:

對(duì)象頭:由兩部分組成,第一部分存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù),第二部分是指針類型,指向?qū)ο蟮念愒獢?shù)據(jù)類型(即對(duì)象代表哪個(gè)類)。
自身的運(yùn)行時(shí)數(shù)據(jù):哈希碼、GC分代年齡、鎖標(biāo)識(shí)狀態(tài)、線程持有的鎖、偏向線程ID(一般占32/64 bit)。
PS:如果是數(shù)組對(duì)象,則對(duì)象頭中還有一部分用來(lái)記錄數(shù)組長(zhǎng)度。
實(shí)例數(shù)據(jù):用來(lái)存儲(chǔ)對(duì)象真正的有效信息(包括父類繼承下來(lái)的和自己定義的)
對(duì)齊填充:JVM要求對(duì)象起始地址必須是8字節(jié)的整數(shù)倍(8字節(jié)對(duì)齊)

ZooKeeper學(xué)習(xí)(一)了解ZooKeeper

一、什么是ZooKeeper
ZooKeeper主要服務(wù)于分布式系統(tǒng),可以用ZooKeeper來(lái)做:統(tǒng)一配置管理、統(tǒng)一命名服務(wù)、分布式鎖、集群管理。
使用分布式系統(tǒng)就無(wú)法避免對(duì)節(jié)點(diǎn)管理的問(wèn)題(需要實(shí)時(shí)感知節(jié)點(diǎn)的狀態(tài)、對(duì)節(jié)點(diǎn)進(jìn)行統(tǒng)一管理等等),而由于這些問(wèn)題處理起來(lái)可能相對(duì)麻煩和提高了系統(tǒng)的復(fù)雜性,ZooKeeper作為一個(gè)能夠通用解決這些問(wèn)題的中間件就應(yīng)運(yùn)而生了。
二、ZooKeeper的數(shù)據(jù)結(jié)構(gòu)
  ZooKeeper和Redis一樣,也是C/S結(jié)構(gòu)(分成客戶端和服務(wù)端)。

ZooKeeper的數(shù)據(jù)結(jié)構(gòu),跟Unix文件系統(tǒng)非常類似,可以看做是一顆樹(shù),每個(gè)節(jié)點(diǎn)叫做ZNode。每一個(gè)節(jié)點(diǎn)可以通過(guò)路徑來(lái)標(biāo)識(shí),結(jié)構(gòu)圖如下:

圖片1

如圖所示,Znode分為兩種類型:

短暫/臨時(shí)(Ephemeral):當(dāng)客戶端和服務(wù)端斷開(kāi)連接后,所創(chuàng)建的Znode(節(jié)點(diǎn))會(huì)自動(dòng)刪除
持久(Persistent):當(dāng)客戶端和服務(wù)端斷開(kāi)連接后,所創(chuàng)建的Znode(節(jié)點(diǎn))不會(huì)刪除
三、ZooKeeper的監(jiān)聽(tīng)器
  前面了解了,我們可以通過(guò)ZooKeeper去通用的實(shí)現(xiàn)很多功能,那么實(shí)現(xiàn)原理是怎么樣的呢?ZooKeeper配合了監(jiān)聽(tīng)器,才能夠做那么多事的。

常見(jiàn)的監(jiān)聽(tīng)場(chǎng)景有以下兩項(xiàng):

監(jiān)聽(tīng)Znode節(jié)點(diǎn)的數(shù)據(jù)變化
監(jiān)聽(tīng)子節(jié)點(diǎn)的增減變化
  通過(guò)監(jiān)聽(tīng)+Znode節(jié)點(diǎn)(持久/短暫[臨時(shí)]),ZooKeeper就可以解決很多分布式系統(tǒng)的問(wèn)題了。

統(tǒng)一配置管理
  比如我們現(xiàn)在有三個(gè)系統(tǒng)A、B、C,他們有三份配置,分別是ASystem.yml、BSystem.yml、CSystem.yml,然后,這三份配置又非常類似,很多的配置項(xiàng)幾乎都一樣。

痛點(diǎn):如果我們要改變其中一份配置項(xiàng)的信息,很可能其他兩份都要改。并且,改變了配置項(xiàng)的信息很可能就要重啟系統(tǒng)
  于是,我們希望把ASystem.yml、BSystem.yml、CSystem.yml相同的配置項(xiàng)抽取出來(lái)成一份公用的配置common.yml,并且即便common.yml改了,也不需要系統(tǒng)A、B、C重啟。

pic2

做法:我們可以將common.yml這份配置放在ZooKeeper的Znode節(jié)點(diǎn)中,系統(tǒng)A、B、C監(jiān)聽(tīng)著這個(gè)Znode節(jié)點(diǎn)有無(wú)變更,如果變更了,及時(shí)響應(yīng)。

代碼參考:基于zookeeper實(shí)現(xiàn)統(tǒng)一配置管理

統(tǒng)一命名服務(wù)
  統(tǒng)一命名服務(wù)的理解其實(shí)跟域名一樣,是我們?yōu)檫@某一部分的資源給它取一個(gè)名字,別人通過(guò)這個(gè)名字就可以拿到對(duì)應(yīng)的資源。

例如一個(gè)域名可能對(duì)應(yīng)多個(gè)IP地址的資源信息,也可能部署多個(gè)服務(wù)器集群,那么別人訪問(wèn)的時(shí)候,不是直接通過(guò)IP去訪問(wèn)對(duì)應(yīng)的主機(jī),而是通過(guò)一個(gè)域名就可以了。

例如:https://www.cnblogs.com/riches/對(duì)應(yīng)了4臺(tái)服務(wù)器:

192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4

pic3

分布式鎖
  我們可以使用ZooKeeper來(lái)實(shí)現(xiàn)分布式鎖,那是怎么做的呢??下面來(lái)看看:系統(tǒng)A、B、C都去訪問(wèn)/locks節(jié)點(diǎn)

pic4

訪問(wèn)的時(shí)候會(huì)創(chuàng)建帶順序號(hào)的臨時(shí)/短暫節(jié)點(diǎn),比如,系統(tǒng)A創(chuàng)建了id_000000節(jié)點(diǎn),系統(tǒng)B創(chuàng)建了id_000002節(jié)點(diǎn),系統(tǒng)C創(chuàng)建了id_000001節(jié)點(diǎn)。

pic5

接著,拿到/locks節(jié)點(diǎn)下的所有子節(jié)點(diǎn)(id_000000,id_000001,id_000002),判斷自己創(chuàng)建的是不是最小的那個(gè)節(jié)點(diǎn)

如果是,則拿到鎖。
釋放鎖:執(zhí)行完操作后,把創(chuàng)建的節(jié)點(diǎn)給刪掉
如果不是,則監(jiān)聽(tīng)比自己要小1的節(jié)點(diǎn)變化
集群管理
  還是以我們?nèi)齻€(gè)系統(tǒng)A、B、C為例,在ZooKeeper中創(chuàng)建臨時(shí)節(jié)點(diǎn)即可:

pic6

只要系統(tǒng)A掛了,那/groupMember/A這個(gè)節(jié)點(diǎn)就會(huì)刪除,通過(guò)監(jiān)聽(tīng)groupMember下的子節(jié)點(diǎn),系統(tǒng)B和C就能夠感知到系統(tǒng)A已經(jīng)掛了。(新增也是同理)

除了能夠感知節(jié)點(diǎn)的上下線變化,ZooKeeper還可以實(shí)現(xiàn)動(dòng)態(tài)選舉Master的功能。(如果集群是主從架構(gòu)模式下)

原理:如果想要實(shí)現(xiàn)動(dòng)態(tài)選舉Master的功能,Znode節(jié)點(diǎn)的類型是帶序號(hào)的臨時(shí)節(jié)點(diǎn)就好了。

Zookeeper會(huì)每次選舉最小編號(hào)的作為Master,如果Master掛了,自然對(duì)應(yīng)的Znode節(jié)點(diǎn)就會(huì)刪除。然后讓新的最小編號(hào)作為Master,這樣就可以實(shí)現(xiàn)動(dòng)態(tài)選舉的功能了。

如何保證redis和MySql 數(shù)據(jù)一致性

  1. 采用延時(shí)雙刪處理
    具體步驟:先刪除緩存,再寫(xiě)數(shù)據(jù)庫(kù),休眠一段時(shí)間(讀數(shù)據(jù)業(yè)務(wù)耗時(shí)+redis和數(shù)據(jù)庫(kù)主從同步耗時(shí)),再次刪除緩存。
    缺點(diǎn):
    1. 休眠時(shí)間的估算準(zhǔn)確性;
    1. 增加了寫(xiě)入請(qǐng)求的耗時(shí);
  1. 異步消息處理
    先讀redis,然后寫(xiě)MySql,然后更新redis集群服務(wù)器數(shù)據(jù)。將更新數(shù)據(jù)發(fā)送到消息隊(duì)列,redis服務(wù)器訂閱更新數(shù)據(jù),然后同步更新。
    缺點(diǎn):需要部署消費(fèi)代碼同步數(shù)據(jù),有一定的開(kāi)發(fā)量。

另一種情況

  1. 在代碼層次執(zhí)行完增刪改后執(zhí)行redis更新?;緵](méi)啥優(yōu)點(diǎn)。代碼侵入性高。在并發(fā)下還有可能數(shù)據(jù)不一致。

  2. 基于消息中間件,增刪改后將增刪改對(duì)應(yīng)表和對(duì)應(yīng)的數(shù)據(jù)唯一標(biāo)識(shí)放入隊(duì)列。然后在通過(guò)隊(duì)列消息內(nèi)容查詢數(shù)據(jù)庫(kù)更新redis。

  3. 監(jiān)聽(tīng)數(shù)據(jù)庫(kù)更改來(lái)實(shí)現(xiàn)redis更新。阿里canal可以做到??梢员O(jiān)聽(tīng)數(shù)據(jù)庫(kù)日志來(lái)實(shí)現(xiàn)。

  4. 以上三種方案基于是數(shù)據(jù)極端事件的數(shù)據(jù)一致性。還有基于定時(shí)調(diào)度任務(wù)定時(shí)對(duì)在周期內(nèi)更新或新增及刪除的消息至redis個(gè)
    優(yōu)點(diǎn):開(kāi)發(fā)過(guò)程中一般會(huì)根據(jù)實(shí)際情況來(lái)選擇,或組合使用

實(shí)現(xiàn)線程的三種方式:1. new Thread 2.Runable 接口 3. 線程池的方式啟動(dòng)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容