亚洲av色香蕉一区二区三区,十四以下岁毛片带血a级,亚洲 校园 欧美 国产 另类,亚洲av日韩av一区谷露,色欲av无码一区二区三区

  • 相關(guān)軟件
    >避免重啟你的應(yīng)用程序 二 創(chuàng)建者:webmaster 更新時(shí)間:2005-05-16 21:27

    三:如果更新的功能包括應(yīng)用邏輯,也就是class改變了,那就稍微麻煩點(diǎn),你需要了解ClassLoader的原理。使用你定制的ClassLoader重新Load 已經(jīng)編譯好的class,就好比你重啟應(yīng)用一樣。下面將簡(jiǎn)單介紹ClassLoader原理,以及舉出一個(gè)例子來說明如何避免重啟應(yīng)用程序。
        虛擬機(jī)通過Classloader來轉(zhuǎn)載類。bootstrap loader 負(fù)責(zé)load jdk的class(java.*,javax.*), system class loader是bootstrap的子類,負(fù)責(zé)load 所有在chasspath指定的變量。ClassLoader將字節(jié)流轉(zhuǎn)化為Class類,這些字節(jié)流可能來源文件,也可能來源于網(wǎng)絡(luò)或者數(shù)據(jù)庫。轉(zhuǎn)化方法是調(diào)用ClassLoader提供的final defineClass(className, classBytes, 0, classBytes.length)方法來實(shí)現(xiàn)。需要記住的是虛擬機(jī)里一個(gè)類的唯一標(biāo)識(shí)是通過類的包名+類名+裝載此類的ClassLoader。同一個(gè)ClassLoader實(shí)例只能裝載Class一次,重復(fù)裝載將拋出重復(fù)類定義異常。
        如下自定義ClassLoader將從classpath里轉(zhuǎn)載指定的類,來說明如上對(duì)ClassLoader的介紹,同時(shí),我們用此ClassLoader演示如何避免重啟動(dòng)應(yīng)用程序
       
    public class DyLoader extends ClassLoader
    {
      public DyLoader()
      {
        super(DyLoader.class.getClassLoader());
      }

      public Class loadFromCustomRepository(String className) {
      /**取環(huán)境變量*/
      String classPath = System.getProperty("java.class.path");
      List classRepository = new ArrayList();
      /**取得該路徑下的所有文件夾 */
      if ( (classPath != null) && ! (classPath.equals(""))) {
        StringTokenizer tokenizer = new StringTokenizer(classPath,
          File.pathSeparator);
        while (tokenizer.hasMoreTokens()) {
        classRepository.add(tokenizer.nextToken());
        }
      }
      Iterator dirs = classRepository.iterator();
      byte[] classBytes = null;
      /**在類路徑上查找該名稱的類是否存在,如果不存在繼續(xù)查找*/
      while (dirs.hasNext()) {
        String dir = (String) dirs.next();
        //replace '.' in the class name with File.separatorChar & append .class to the name
        String classFileName = className.replace('.', File.separatorChar);
        classFileName += ".class";
        try {
        File file = new File(dir + File.separatorChar + classFileName);
        if (file.exists()) {
          InputStream is = new FileInputStream(file);
          /**把文件讀到字節(jié)文件*/
          classBytes = new byte[is.available()];
          is.read(classBytes);
          break;
        }
        }
        catch (IOException ex) {
        System.out.println("IOException raised while reading class file data");
        ex.printStackTrace();
        return null;
        }
      }
      return this.defineClass(className, classBytes, 0, classBytes.length);//加載類
    }

    }

    如下調(diào)用
    DyLoader loader = new DyLoader();
    Class a = loader.loadFromCustomRepository("com.lijz.SampleDyService");
    Class b = loader.loadFromCustomRepository("com.lijz.SampleDyService");
    第三行代碼將會(huì)拋出
    java.lang.LinkageError: duplicate class definition: com/lijz/SampleDyService



    如果如下調(diào)用,則一切正常,這是因?yàn)槟闶褂眯碌腃lassLoader實(shí)例來裝載com.lijz.SampleDyService"
    DyLoader loader= new DyLoader();
    Class a loader.loadFromCustomRepository("com.lijz.SampleDyService");
    DyLoader newLoader = new DyLoader();
    Class b = newLoader.loadFromCustomRepository("com.lijz.SampleDyService");

    言歸正傳,停止介紹Classloader,回到利用Classloader來避免重新啟動(dòng)你的應(yīng)用程序

    首先定義業(yè)務(wù)邏輯處理模塊接口

    public interface IDyService
    {
      public void start();
      public void close();
      public void doBusiness();
    }

    start方法用于初始化,close用于清除此服務(wù)。doBusiness用來模擬處理業(yè)務(wù)

    一個(gè)實(shí)現(xiàn)的例子如下:
    public class SampleDyService implements IDyService
    {
      public SampleDyService()
      {
      }
      public void doBusiness()
      {
        System.out.println("hello boy");
      }
      public void start()
      {
        System.out.println("Start SampleDyService:");
        System.out.println(SampleDyService.class.getClassLoader());
      }

      public void close()
      {
        System.out.println("close SampleDyService:");
      }


    start方法 close方法僅打印出提示信息。doBuinsess輸出"hello boy"。主程序?qū)⒀h(huán)調(diào)用doBusiness方法

    public class Main()
    {  
      private IDyService service = null;
      public Main()
            throws Exception
      {
        DyLoader loader = new DyLoader();
        service = (IDyService) loader.loadFromCustomRepository(
              "com.gctech.service.test.dyloader.SampleDyService").newInstance();
        service.start();
       
        while (true)
        {

            service.doBusiness();
            Thread.sleep(1000 * 3);
        }
      }
     
      public static void main(String[] args)
            throws Exception
      {
        Main main = new Main();
      }
     
    }  


    假設(shè)業(yè)務(wù)邏輯改變,要求SampleDyService的doBusiness打印出"hello girl"。新編譯好的SampleDyService已經(jīng)覆蓋了原來的類。在不啟動(dòng)應(yīng)用程序前提條件下如何更新新的業(yè)務(wù)邏輯呢?
    分倆部來完成
    第一步,在Main類里添加notifyReLoad方法,用新的classloader重新生成SampleDyService實(shí)例
    public void notifyReLoad()
            throws Exception
      {
        service.close();
        DyLoader loader = new DyLoader();
        service = (IDyService) loader.loadFromCustomRepository(
              "com.gctech.service.test.dyloader.SampleDyService").newInstance();
        service.start();

      }

    第二步:使用某種機(jī)制檢測(cè)來檢測(cè)SampleDyService.class已經(jīng)改變,如可以通過上面的例子啟動(dòng)一個(gè)線程檢測(cè)SampleDyService.class是否被改變,如果改變則調(diào)用Main.notifyReLoad().也可以采用主動(dòng)通知方式,如web應(yīng)用中,提供這樣的界面調(diào)用。在此例子中提供一個(gè)檢測(cè)線程。
    public class DyServciceChecker extends Thread
    {
      Main main = null;
     
      public DyServciceChecker()
      {
      }
      public void setMain(Main main)
      {
        this.main = main;

      }

      public void run()
      {
        while(!interrupted())
        {
            try
            {
              boolean isChanged = check();
              if(isChanged)
              {
                main.notifyReLoad();

                    }
              else
              {
                Thread.sleep(1000*50);


              }
            }
            catch (Exception ex)
            {
              ex.printStackTrace();
            }
        }
      }
       
    }

    修改Main類的構(gòu)造函數(shù)成如下

    public Main()
            throws Exception
      {
        DyLoader loader = new DyLoader();
        service = (IDyService) loader.loadFromCustomRepository(
              "com.gctech.service.test.dyloader.SampleDyService").newInstance();
        service.start();
        //添加檢測(cè)線程
        DyServciceChecker checker = new DyServciceChecker();
        checker.setMain(this);    
        checker.start();    
         
        while (true)
        {

            service.doBusiness();
            Thread.sleep(1000 * 3);
        }
      }
     
    好了,運(yùn)行Main類。并在運(yùn)行過程中用新的SampleDyService.class覆蓋舊的SampleDyService.class??刂婆_(tái)輸出信息如下:


    Start SampleDyService:

    com.gctech.service.test.dyloader.DyLoader@108786b

    hello boy

    hello boy

    hello boy

    ...............
    close SampleDyService:

    Start SampleDyService:

    com.gctech.service.test.dyloader.DyLoader@c1cd1f

    hello girl

    hello girl



    總結(jié):
    如果應(yīng)用程序不可避免的在運(yùn)行中要重啟動(dòng),你首先要做好的工作是采取合理的設(shè)計(jì),保證用戶的請(qǐng)求和對(duì)用戶的相應(yīng)不丟失。否則,只能等到用戶訪問量最少的時(shí)候去啟動(dòng)。還有你在寫你的業(yè)務(wù)邏輯的時(shí)候,即使當(dāng)時(shí)你很肯定你的代碼寫死也沒關(guān)系也不要這么做,盡量采用配置文件的方法,并提供如上的檢測(cè)線程,現(xiàn)在的web container都提供檢測(cè)web.xml文件是否改變來確定是否需要重新部署web。最后Classloader能幫助你動(dòng)態(tài)加載類,從而在不停止應(yīng)用程序的情況下動(dòng)態(tài)更新類
    相關(guān)文章
    本頁查看次數(shù):