偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Java類中熱替換的概念、設(shè)計(jì)與實(shí)現(xiàn)

開發(fā) 后端
在本文中,我們將基于實(shí)例,對構(gòu)建在線升級Java系統(tǒng)的基礎(chǔ)技術(shù)和設(shè)計(jì)原則進(jìn)行了深入的講解,相信讀者能夠根據(jù)文中的技術(shù)構(gòu)建出自己的在線升級系統(tǒng)來。

類的熱替換是Java在線升級系統(tǒng)設(shè)計(jì)中的基礎(chǔ)技術(shù),從文中給出的實(shí)例來看,構(gòu)建在線升級系統(tǒng)不僅僅是一個(gè)技術(shù)問題,還牽扯到很多管理方面的因素,比如:如何管理、部署系統(tǒng)中的可在線升級部分和不可在線升級部分以降低系統(tǒng)的管理、維護(hù)成本等。

對于許多關(guān)鍵性業(yè)務(wù)或者龐大的Java系統(tǒng)來說,如果必須暫停系統(tǒng)服務(wù)才能進(jìn)行系統(tǒng)升級,既會(huì)大大影響到系統(tǒng)的可用性,同時(shí)也增加了系統(tǒng)的管理和維護(hù)成本。因此,如果能夠方便地在不停止系統(tǒng)業(yè)務(wù)的情況下進(jìn)行系統(tǒng)升級,則可以很好地解決上述問題。

JavaClassLoader技術(shù)剖析

要構(gòu)建在線升級系統(tǒng),一個(gè)重要的技術(shù)就是能夠?qū)崿F(xiàn)Java類的熱替換——也就是在不停止正在運(yùn)行的系統(tǒng)的情況下進(jìn)行類(對象)的升級替換。而Java的ClassLoader正是實(shí)現(xiàn)這項(xiàng)技術(shù)的基礎(chǔ)。

在Java中,類的實(shí)例化流程分為兩個(gè)部分:類的加載和類的實(shí)例化。類的加載又分為顯式加載和隱式加載。大家使用new關(guān)鍵字創(chuàng)建類實(shí)例時(shí),其實(shí)就隱式地包含了類的加載過程。對于類的顯式加載來說,比較常用的是Class.forName。其實(shí),它們都是通過調(diào)用ClassLoader類的loadClass方法來完成類的實(shí)際加載工作的。直接調(diào)用ClassLoader的loadClass方法是另外一種不常用的顯式加載類的技術(shù)。

Java類加載器層次結(jié)構(gòu)圖 

圖1.Java類加載器層次結(jié)構(gòu)圖

ClassLoader在加載類時(shí)有一定的層次關(guān)系和規(guī)則。在Java中,有四種類型的類加載器,分別為:BootStrapClassLoader、ExtClassLoader、AppClassLoader以及用戶自定義的ClassLoader。這四種類加載器分別負(fù)責(zé)不同路徑的類的加載,并形成了一個(gè)類加載的層次結(jié)構(gòu)。

BootStrapClassLoader處于類加載器層次結(jié)構(gòu)的最高層,負(fù)責(zé)sun.boot.class.path路徑下類的加載,默認(rèn)為jre/lib目錄下的核心API或-Xbootclasspath選項(xiàng)指定的jar包。ExtClassLoader的加載路徑為java.ext.dirs,默認(rèn)為jre/lib/ext目錄或者-Djava.ext.dirs指定目錄下的jar包加載。AppClassLoader的加載路徑為java.class.path,默認(rèn)為環(huán)境變量CLASSPATH中設(shè)定的值。也可以通過-classpath選型進(jìn)行指定。用戶自定義ClassLoader可以根據(jù)用戶的需要定制自己的類加載過程,在運(yùn)行期進(jìn)行指定類的動(dòng)態(tài)實(shí)時(shí)加載。

這四種類加載器的層次關(guān)系圖如圖1所示。一般來說,這四種類加載器會(huì)形成一種父子關(guān)系,高層為低層的父加載器。在進(jìn)行類加載時(shí),首先會(huì)自底向上挨個(gè)檢查是否已經(jīng)加載了指定類,如果已經(jīng)加載則直接返回該類的引用。如果到最高層也沒有加載過指定類,那么會(huì)自頂向下挨個(gè)嘗試加載,直到用戶自定義類加載器,如果還不能成功,就會(huì)拋出異常。Java類的加載過程如圖2所示。

Java類的加過程 

圖2.Java類的加過程

每個(gè)類加載器有自己的名字空間,對于同一個(gè)類加載器實(shí)例來說,名字相同的類只能存在一個(gè),并且僅加載一次。不管該類有沒有變化,下次再需要加載時(shí),它只是從自己的緩存中直接返回已經(jīng)加載過的類引用。

我們編寫的應(yīng)用類默認(rèn)情況下都是通過AppClassLoader進(jìn)行加載的。當(dāng)我們使用new關(guān)鍵字或者Class.forName來加載類時(shí),所要加載的類都是由調(diào)用new或者Class.forName的類的類加載器(也是AppClassLoader)進(jìn)行加載的。要想實(shí)現(xiàn)Java類的熱替換,首先必須要實(shí)現(xiàn)系統(tǒng)中同名類的不同版本實(shí)例的共存,通過上面的介紹我們知道,要想實(shí)現(xiàn)同一個(gè)類的不同版本的共存,我們必須要通過不同的類加載器來加載該類的不同版本。另外,為了能夠繞過Java類的既定加載過程,我們需要實(shí)現(xiàn)自己的類加載器,并在其中對類的加載過程進(jìn)行完全的控制和管理。 #p#

編寫自定義的ClassLoader

為了能夠完全掌控類的加載過程,我們的定制類加載器需要直接從ClassLoader繼承。首先我們來介紹一下ClassLoader類中和熱替換有關(guān)的的一些重要方法。

◆findLoadedClass:每個(gè)類加載器都維護(hù)有自己的一份已加載類名字空間,其中不能出現(xiàn)兩個(gè)同名的類。凡是通過該類加載器加載的類,無論是直接的還是間接的,都保存在自己的名字空間中,該方法就是在該名字空間中尋找指定的類是否已存在,如果存在就返回給類的引用,否則就返回null。這里的直接是指,存在于該類加載器的加載路徑上并由該加載器完成加載,間接是指,由該類加載器把類的加載工作委托給其他類加載器完成類的實(shí)際加載。

◆getSystemClassLoader:Java2中新增的方法。該方法返回系統(tǒng)使用的ClassLoader??梢栽谧约憾ㄖ频念惣虞d器中通過該方法把一部分工作轉(zhuǎn)交給系統(tǒng)類加載器去處理。

◆defineClass:該方法是ClassLoader中非常重要的一個(gè)方法,它接收以字節(jié)數(shù)組表示的類字節(jié)碼,并把它轉(zhuǎn)換成Class實(shí)例,該方法轉(zhuǎn)換一個(gè)類的同時(shí),會(huì)先要求裝載該類的父類以及實(shí)現(xiàn)的接口類。

◆loadClass:加載類的入口方法,調(diào)用該方法完成類的顯式加載。通過對該方法的重新實(shí)現(xiàn),我們可以完全控制和管理類的加載過程。

◆resolveClass:鏈接一個(gè)指定的類。這是一個(gè)在某些情況下確保類可用的必要方法,詳見Java語言規(guī)范中“執(zhí)行”一章對該方法的描述。

了解了上面的這些方法,下面我們來實(shí)現(xiàn)一個(gè)定制的類加載器來完成這樣的加載流程:我們?yōu)樵擃惣虞d器指定一些必須由該類加載器直接加載的類集合,在該類加載器進(jìn)行類的加載時(shí),如果要加載的類屬于必須由該類加載器加載的集合,那么就由它直接來完成類的加載,否則就把類加載的工作委托給系統(tǒng)的類加載器完成。

在給出示例代碼前,有兩點(diǎn)內(nèi)容需要說明一下:1、要想實(shí)現(xiàn)同一個(gè)類的不同版本的共存,那么這些不同版本必須由不同的類加載器進(jìn)行加載,因此就不能把這些類的加載工作委托給系統(tǒng)加載器來完成,因?yàn)樗鼈冎挥幸环荨?、為了做到這一點(diǎn),就不能采用系統(tǒng)默認(rèn)的類加載器委托規(guī)則,也就是說我們定制的類加載器的父加載器必須設(shè)置為null。該定制的類加載器的實(shí)現(xiàn)代碼如下:

 

  1. class CustomCL extends ClassLoader {   
  2.  
  3.  private String basedir; // 需要該類加載器直接加載的類文件的基目錄  
  4.     private HashSet dynaclazns; // 需要由該類加載器直接加載的類名  
  5.  
  6.     public CustomCL(String basedir, String[] clazns) {   
  7.         super(null); // 指定父類加載器為 null   
  8.         this.basedir = basedir;   
  9.         dynaclazns = new HashSet();   
  10.         loadClassByMe(clazns);   
  11.     }   
  12.  
  13.     private void loadClassByMe(String[] clazns) {   
  14.         for (int i = 0; i < clazns.length; i++) {   
  15.             loadDirectly(clazns[i]);   
  16.             dynaclazns.add(clazns[i]);   
  17.         }   
  18.     }   
  19.  
  20.     private Class loadDirectly(String name) {   
  21.         Class cls = null;   
  22.         StringBuffer sb = new StringBuffer(basedir);   
  23.         String classname = name.replace('.', File.separatorChar) + ".class";  
  24.         sb.append(File.separator + classname);   
  25.         File classF = new File(sb.toString());   
  26.         cls = instantiateClass(name,new FileInputStream(classF),  
  27.             classF.length());   
  28.         return cls;   
  29.     }       
  30.  
  31.     private Class instantiateClass(String name,InputStream fin,long len){   
  32.         byte[] raw = new byte[(int) len];   
  33.         fin.read(raw);   
  34.         fin.close();   
  35.         return defineClass(name,raw,0,raw.length);   
  36.     }   
  37.       
  38.  protected Class loadClass(String name, boolean resolve)   
  39.             throws ClassNotFoundException {   
  40.         Class cls = null;   
  41.         cls = findLoadedClass(name);   
  42.         if(!this.dynaclazns.contains(name) && cls == null)   
  43.             cls = getSystemClassLoader().loadClass(name);   
  44.         if (cls == null)   
  45.             throw new ClassNotFoundException(name);   
  46.         if (resolve)   
  47.             resolveClass(cls);   
  48.         return cls;   
  49.     }   
  50.  
  51. }  

 

在該類加載器的實(shí)現(xiàn)中,所有指定必須由它直接加載的類都在該加載器實(shí)例化時(shí)進(jìn)行了加載,當(dāng)通過loadClass進(jìn)行類的加載時(shí),如果該類沒有加載過,并且不屬于必須由該類加載器加載之列都委托給系統(tǒng)加載器進(jìn)行加載。#p#

實(shí)現(xiàn)Java類的熱替換

現(xiàn)在來介紹一下我們的實(shí)驗(yàn)方法,為了簡單起見,我們的包為默認(rèn)包,沒有層次,并且省去了所有錯(cuò)誤處理。要替換的類為Foo,實(shí)現(xiàn)很簡單,僅包含一個(gè)方法sayHello:

  1. public class Foo{   
  2.     public void sayHello() {   
  3.         System.out.println("hello world! (version one)");   
  4.     }   
  5. }  

在當(dāng)前工作目錄下建立一個(gè)新的目錄swap,把編譯好的Foo.class文件放在該目錄中。接下來要使用我們前面編寫的HotswapCL來實(shí)現(xiàn)該類的熱替換。具體的做法為:我們編寫一個(gè)定時(shí)器任務(wù),每隔2秒鐘執(zhí)行一次。其中,我們會(huì)創(chuàng)建新的類加載器實(shí)例加載Foo類,生成實(shí)例,并調(diào)用sayHello方法。接下來,我們會(huì)修改Foo類中sayHello方法的打印內(nèi)容,重新編譯,并在系統(tǒng)運(yùn)行的情況下替換掉原來的Foo.class,我們會(huì)看到系統(tǒng)會(huì)打印出更改后的內(nèi)容。定時(shí)任務(wù)的實(shí)現(xiàn)如下(其它代碼省略,請讀者自行補(bǔ)齊):

  1. public void run(){   
  2.     try {   
  3.         // 每次都創(chuàng)建出一個(gè)新的類加載器  
  4.         HowswapCL cl = new HowswapCL("../swap", new String[]{"Foo"});   
  5.         Class clcls = cl.loadClass("Foo");   
  6.         Object foo = cls.newInstance();   
  7.  
  8.         Method m = foo.getClass().getMethod("sayHello", new Class[]{});   
  9.         m.invoke(foo, new Object[]{});   
  10.       
  11.     }  catch(Exception ex) {   
  12.         ex.printStackTrace();   
  13.     }   
  14. }  

編譯、運(yùn)行我們的系統(tǒng),會(huì)出現(xiàn)如下的打?。?/p>

熱替換前的運(yùn)行結(jié)果 

圖3.熱替換前的運(yùn)行結(jié)果

好,現(xiàn)在我們把Foo類的sayHello方法更改為:

  1. public void sayHello() {   
  2.     System.out.println("hello world! (version two)");   
  3. }  

在系統(tǒng)仍在運(yùn)行的情況下,編譯,并替換掉swap目錄下原來的Foo.class文件,我們再看看屏幕的打印,奇妙的事情發(fā)生了,新更改的類在線即時(shí)生效了,我們已經(jīng)實(shí)現(xiàn)了Foo類的熱替換。屏幕打印如下:

熱替換后的運(yùn)行結(jié)果 

圖4.熱替換后的運(yùn)行結(jié)果

敏銳的讀者可能會(huì)問,為何不用把foo轉(zhuǎn)型為Foo,直接調(diào)用其sayHello方法呢?這樣不是更清晰明了嗎?下面我們來解釋一下原因,并給出一種更好的方法。如果我們采用轉(zhuǎn)型的方法,代碼會(huì)變成這樣:Foofoo=(Foo)cls.newInstance();讀者如果跟隨本文進(jìn)行試驗(yàn)的話,會(huì)發(fā)現(xiàn)這句話會(huì)拋出ClassCastException異常,為什么嗎?因?yàn)樵贘ava中,即使是同一個(gè)類文件,如果是由不同的類加載器實(shí)例加載的,那么它們的類型是不相同的。在上面的例子中cls是由HowswapCL加載的,而foo變量類型聲名和轉(zhuǎn)型里的Foo類卻是由run方法所屬的類的加載器(默認(rèn)為AppClassLoader)加載的,因此是完全不同的類型,所以會(huì)拋出轉(zhuǎn)型異常。

那么通過接口調(diào)用是不是就行了呢?我們可以定義一個(gè)IFoo接口,其中聲名sayHello方法,F(xiàn)oo實(shí)現(xiàn)該接口。也就是這樣:IFoofoo=(IFoo)cls.newInstance();本來該方法也會(huì)有同樣的問題的,因?yàn)橥獠柯暶娃D(zhuǎn)型部分的IFoo是由run方法所屬的類加載器加載的,而Foo類定義中implementsIFoo中的IFoo是由HotswapCL加載的,因此屬于不同的類型轉(zhuǎn)型還是會(huì)拋出異常的,但是由于我們在實(shí)例化HotswapCL時(shí)是這樣的:

  1. HowswapCLcl=newHowswapCL("../swap",newString[]{"Foo"}); 

其中僅僅指定Foo類由HotswapCL加載,而其實(shí)現(xiàn)的IFoo接口文件會(huì)委托給系統(tǒng)類加載器加載,因此轉(zhuǎn)型成功,采用接口調(diào)用的代碼如下:

  1. public void run(){   
  2.     try {   
  3.         HowswapCL cl = new HowswapCL("../swap", new String[]{"Foo"});   
  4.         Class clcls = cl.loadClass("Foo");   
  5.         IFoo foo = (IFoo)cls.newInstance();   
  6.         foo.sayHello();   
  7.     } catch(Exception ex) {   
  8.         ex.printStackTrace();   
  9.     }   
  10. }  

確實(shí),簡潔明了了很多,在我們的實(shí)驗(yàn)中,每當(dāng)定時(shí)器調(diào)度到run方法時(shí),我們都會(huì)創(chuàng)建一個(gè)新的HotswapCL實(shí)例,在產(chǎn)品代碼中,無需如此,僅當(dāng)需要升級替換時(shí)才去創(chuàng)建一個(gè)新的類加載器實(shí)例。 #p#

在線升級系統(tǒng)的設(shè)計(jì)原則

在上小節(jié)中,我們給出了一個(gè)Java類熱替換的實(shí)例,掌握了這項(xiàng)技術(shù),就具備了實(shí)現(xiàn)在線升級系統(tǒng)的基礎(chǔ)。但是,對于一個(gè)真正的產(chǎn)品系統(tǒng)來說,升級本省就是一項(xiàng)非常復(fù)雜的工程,如果要在線升級,就會(huì)更加復(fù)雜。其中,實(shí)現(xiàn)類的熱替換只是最后一步操作,在線升級的要求會(huì)對系統(tǒng)的整體設(shè)計(jì)帶來深遠(yuǎn)的影響。下面我們來談?wù)勗诰€升級系統(tǒng)設(shè)計(jì)方面的一些原則:

◆在系統(tǒng)設(shè)計(jì)一開始,就要考慮系統(tǒng)的哪些部分是需要以后在線升級的,哪些部分是穩(wěn)定的

雖然我們可以把系統(tǒng)設(shè)計(jì)成任何一部分都是可以在線升級的,但是其成本是非常高昂的,也沒有必要。因此,明確地界定出系統(tǒng)以后需要在線升級的部分是明智之舉。這些部分常常是系統(tǒng)業(yè)務(wù)邏輯規(guī)則、算法等等。

◆設(shè)計(jì)出規(guī)范一致的系統(tǒng)狀態(tài)轉(zhuǎn)換方法

替換一個(gè)類僅僅是在線升級系統(tǒng)所要做的工作中的一個(gè)步驟,為了使系統(tǒng)能夠在升級后正常運(yùn)行,就必須保持升級前后系統(tǒng)狀態(tài)的一致性。因此,在設(shè)計(jì)時(shí)要考慮需要在線升級的部分所涉及的系統(tǒng)狀態(tài)有哪些,把這些狀態(tài)設(shè)計(jì)成便于獲取、設(shè)置和轉(zhuǎn)換的,并用一致的方式來進(jìn)行。

◆明確出系統(tǒng)的升級控制協(xié)議

這個(gè)原則是關(guān)于系統(tǒng)在線升級的時(shí)機(jī)和流程控制的,不考慮系統(tǒng)的當(dāng)前運(yùn)行狀態(tài)就貿(mào)然進(jìn)行升級是一項(xiàng)非常危險(xiǎn)的活動(dòng)。因此在系統(tǒng)設(shè)計(jì)中,就要考慮并預(yù)留出系統(tǒng)在線升級的控制點(diǎn),并定義清晰、明確的升級協(xié)議來協(xié)調(diào)、控制多個(gè)升級實(shí)體的升級次序,以確保系統(tǒng)在升級的任何時(shí)刻都處在一個(gè)確定的狀態(tài)下。

◆考慮到升級失敗時(shí)的回退機(jī)制

即使我們做了非??b密細(xì)致的設(shè)計(jì),還是難以從根本上保證系統(tǒng)升級一定是成功的,對于大型分布式系統(tǒng)來說尤其如此。因此在系統(tǒng)設(shè)計(jì)時(shí),要考慮升級失敗后的回退機(jī)制。

在線升級系統(tǒng)實(shí)例

首先,我們來簡單介紹一下這個(gè)實(shí)例的結(jié)構(gòu)組成和要完成的工作。在我們的例子中,主要有三個(gè)實(shí)體,一個(gè)是升級控制實(shí)體,兩個(gè)是工作實(shí)體,都基于ActiveObject實(shí)現(xiàn),通過命令消息進(jìn)行通信(關(guān)于ActiveObject的詳細(xì)信息,可以參見作者的另外一篇文章“構(gòu)建Java并發(fā)模型框架”)。

升級控制實(shí)體以RMI的方式對外提供了一個(gè)管理命令接口,用以接收外部的在線升級命令。工作實(shí)體有兩個(gè)消息隊(duì)列,一個(gè)用以接收分配給它的任務(wù)(我們用定時(shí)器定時(shí)給它發(fā)送任務(wù)命令消息),我們稱其為任務(wù)隊(duì)列;另一個(gè)用于和升級控制實(shí)體交互,協(xié)作完成升級過程,我們稱其為控制隊(duì)列。工作實(shí)體中的任務(wù)很簡單,就是使用我們前面介紹的Foo類簡單地打印出一個(gè)字符串,不過這次字符串作為狀態(tài)保存在工作實(shí)體中,動(dòng)態(tài)設(shè)置給Foo類的實(shí)例的。升級的協(xié)議流程如下:

當(dāng)升級控制實(shí)體接收到來自RMI的在線升級命令時(shí),它會(huì)向兩個(gè)工作實(shí)體的任務(wù)隊(duì)列中發(fā)送一條準(zhǔn)備升級消息,然后等待回應(yīng)。當(dāng)工作實(shí)體在任務(wù)隊(duì)列中收到準(zhǔn)備升級消息時(shí),會(huì)立即給升級控制實(shí)體發(fā)送一條準(zhǔn)備就緒消息,然后切換到控制隊(duì)列等待進(jìn)一步的升級指令。升級控制實(shí)體收齊這兩個(gè)工作實(shí)體發(fā)來的準(zhǔn)備就緒消息后,就給這兩個(gè)工作實(shí)體的控制隊(duì)列各發(fā)送一條開始升級消息,然后等待結(jié)果。工作實(shí)體收到開始升級消息后,進(jìn)行實(shí)際的升級工作,也就是我們前面講述的熱替換類。然后,給升級控制實(shí)體發(fā)送升級完畢消息。升級控制實(shí)體收到來自兩個(gè)工作實(shí)體的升級完畢消息后,會(huì)給這兩個(gè)工作實(shí)體的控制隊(duì)列各發(fā)送一條繼續(xù)工作消息,工作實(shí)體收到繼續(xù)工作消息后,切換到任務(wù)隊(duì)列繼續(xù)工作,升級過程結(jié)束。主要的代碼片段如下(略去命令消息的定義和執(zhí)行細(xì)節(jié)):

  1. // 升級控制實(shí)體關(guān)鍵代碼  
  2. class UpgradeController extends ActiveObject{   
  3.     int nready  = 0;   
  4.     int nfinished = 0;   
  5.     Worker[] workers;   
  6.     ......   
  7.     // 收到外部升級命令消息時(shí),會(huì)觸發(fā)該方法被調(diào)用  
  8.     public void askForUpgrade() {   
  9.         for(int i=0; i<workers.length; i++)   
  10.             workers[i].getTaskQueue().enqueue(new PrepareUpgradeCmd(workers[i]));  
  11.     }   
  12.  
  13.     // 收到工作實(shí)體回應(yīng)的準(zhǔn)備就緒命令消息時(shí),會(huì)觸發(fā)該方法被調(diào)用  
  14.     public void readyForUpgrade(String worker_name) {   
  15.         nready++;          
  16.         if(nready == workers.length){   
  17.             for(int i=0; i<workers.length; i++)   
  18.                 workers[i].getControlQueue().enqueue(new   
  19.                     StartUpgradeCmd(workers[i]));   
  20.         }        
  21.     }   
  22.  
  23.     // 收到工作實(shí)體回應(yīng)的升級完畢命令消息時(shí),會(huì)觸發(fā)該方法被調(diào)用  
  24.     public void finishUpgrade(String worker_name) {   
  25.         nfinished++;   
  26.         if(nfinished == workers.length){   
  27.             for(int i=0; i<workers.length; i++)   
  28.                 workers[i].getControlQueue().enqueue(new   
  29.                     ContineWorkCmd(workers[i]));   
  30.  
  31.         }   
  32.     }   
  33.       
  34.     ......   
  35.  
  36. }   
  37.  
  38. // 工作實(shí)體關(guān)鍵代碼  
  39. class Worker extends ActiveObject{   
  40.     UpgradeController ugc;   
  41.     HotswapCL hscl;   
  42.     IFoo foo;   
  43.     String state = "hello world!";   
  44.       
  45.     ......   
  46.      
  47.     // 收到升級控制實(shí)體的準(zhǔn)備升級命令消息時(shí),會(huì)觸發(fā)該方法被調(diào)用  
  48.     public void prepareUpgrade() {   
  49.         switchToControlQueue();   
  50.         ugc.getMsgQueue().enqueue(new ReadyForUpdateCMD(ugc,this));   
  51.     }   
  52.  
  53.     // 收到升級控制實(shí)體的開始升級命令消息時(shí),會(huì)觸發(fā)該方法被調(diào)用  
  54.     public void startUpgrade(String worker_name) {   
  55.         doUpgrade();   
  56.         ugc.getMsgQueue().enqueue(new FinishUpgradeCMD(ugc,this));   
  57.     }   
  58.  
  59.     // 收到升級控制實(shí)體的繼續(xù)工作命令消息時(shí),會(huì)觸發(fā)該方法被調(diào)用  
  60.     public void continueWork(String worker_name) {   
  61.         switchToTaskQueue();   
  62.     }   
  63.  
  64.     // 收到定時(shí)命令消息時(shí),會(huì)觸發(fā)該方法被調(diào)用  
  65.     public void doWork() {   
  66.         foo.sayHello();      
  67.     }   
  68.  
  69.     // 實(shí)際升級動(dòng)作  
  70.     private void doUpgrade() {   
  71.         hscl = new HowswapCL("../swap", new String[]{"Foo"});   
  72.         Class cls = hscl.loadClass("Foo");   
  73.         foo = (IFoo)cls.newInstance();   
  74.         foo.SetState(state);   
  75.     }   
  76. }   
  77.  
  78. //IFoo 接口定義  
  79. interface IFoo {   
  80.     void SetState(String);   
  81.     void sayHello();   
  82. }  

在Foo類第一個(gè)版本的實(shí)現(xiàn)中,只是把設(shè)置進(jìn)來的字符串直接打印出來。在第二個(gè)版本中,會(huì)先把設(shè)置進(jìn)來的字符串變?yōu)榇髮?,然后打印出來。例子很簡單,旨在表達(dá)規(guī)則或者算法方面的升級變化。另外,我們并沒有提及諸如:消息超時(shí)、升級失敗等方面的異常情況,這在實(shí)際產(chǎn)品開發(fā)中是必須要考慮的。

 

【編輯推薦】

  1. 在Java類中靈活使用Static關(guān)鍵字
  2. Java類中域和方法設(shè)置中的常見錯(cuò)誤
  3. 使用XML通過Java類定義Web服務(wù)
  4. Java教程 Java類中的各種數(shù)據(jù)
  5. Java教程 Java類中的包
責(zé)任編輯:王曉東 來源: IBM
相關(guān)推薦

2022-04-06 08:49:44

SSTKV存儲(chǔ)引擎

2020-07-19 10:26:47

Kubernetes數(shù)據(jù)結(jié)構(gòu)

2025-03-20 09:54:47

2025-05-22 08:15:00

2018-07-19 06:23:37

物聯(lián)網(wǎng)IOT網(wǎng)絡(luò)

2024-12-13 08:28:45

設(shè)計(jì)模式依賴

2023-03-28 09:58:56

Python變量

2024-06-11 00:00:30

C#編程線程

2015-05-20 10:05:10

Ceph分布式文件系統(tǒng)序列化

2023-10-22 23:28:34

2017-01-13 10:51:13

RPC模型解析

2021-12-22 22:44:49

Webpack熱替換模塊

2020-12-28 07:33:21

SkipListJava跳表

2024-12-27 09:32:19

2011-03-23 15:06:45

PBWORD

2024-11-27 15:33:17

軟件架構(gòu)DDD

2009-06-14 22:09:24

Java界面布局DSL

2010-02-26 13:14:39

Java日志系統(tǒng)

2010-06-28 18:21:36

UML類圖設(shè)計(jì)

2021-03-01 08:19:09

Java 包裝類對象
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號