Live a simple life

          沉默(zhu_xing@live.cn)
          隨筆 - 48, 文章 - 0, 評(píng)論 - 132, 引用 - 0
          數(shù)據(jù)加載中……

          【Eclipse插件開發(fā)】Java基本類加載原理 VS 插件類加載原理

                      標(biāo)題說明了一切,我想說的就是如果你在做Eclipse插件開發(fā),想真正搞清楚Eclipse插件類加載,那么Java基本類加載原理是基礎(chǔ),無法逾越!!!我會(huì)舉一個(gè)小例子來簡單說明一下
                      
                  【情景】
                    例如我們在底層模塊插件(就叫做Host)中做了一個(gè)解析器實(shí)現(xiàn)(什么解析器就別管了),對(duì)應(yīng)類型為IParser(com.my.host.parser.IParser),簡單定義如下:
          1 public interface IParser {
          2     public Object parse(Object input) throws CoreException;
          3 }
                   
                  基本的原則告訴我們:如果一個(gè)實(shí)例的創(chuàng)建過程較為負(fù)責(zé),則因該把這種實(shí)例的創(chuàng)建和實(shí)例的使用解耦合。于是,我們在Host插件中提供了一個(gè)如下的工廠類:
           1 public class ParserFactory {
           2     /**
           3      * create IParser instance
           4      * 
           5      * @param clazz  qualified parser type name
           6      * @return
           7      * @throws CoreException
           8      */
           9     public static IParser createParser(String clazz) throws CoreException{
          10         try {
          11             Object object = Class.forName(clazz).newInstance();
          12             if (object instanceof IParser)
          13                 return (IParser)object;
          14             
          15             return null;
          16         } catch (Exception e) {
          17             throw new CoreException(new Status(IStatus.ERROR, "host"101"創(chuàng)建工廠失敗:" + clazz, e));
          18         }
          19     }
          20     
          21     /**
          22      * create IParser instance with corresponding class loader
          23      * 
          24      * @param clazz         qualified parser type name
          25      * @param classLoader   corresponding class loader
          26      * @return
          27      * @throws CoreException
          28      */
          29     public static IParser createParser(String clazz, ClassLoader classLoader) throws CoreException{
          30         try {
          31             Object object = classLoader.loadClass(clazz);
          32             if (object instanceof IParser)
          33                 return (IParser)object;
          34             
          35             return null;
          36         } catch (Exception e) {
          37             throw new CoreException(new Status(IStatus.ERROR, "host"101"創(chuàng)建工廠失敗:" + clazz, e));
          38         }
          39     }
          40 }
          41 
                  這里的簡單工廠中創(chuàng)建方法返回的是IParser接口類型,目的就是為了保證可以創(chuàng)建子類型的靈活性,同時(shí)確保對(duì)外提供的接口是一致的,有助于客戶端基于接口編程(說的有點(diǎn)上綱上線了~_~)

                  同時(shí)我們在Host插件中,也提供了一個(gè)默認(rèn)的IParser實(shí)現(xiàn),就叫做DefaultParser吧。那到這里我們的Host插件共提供了如下類型:
                  com.my.host.parser.IParser                     解析器接口定義
                  com.my.host.parser.ParserFactory          解析器工廠
                  com.my.host.parser.impl.DefaultParser    解析器接口默認(rèn)實(shí)現(xiàn)

                  下面我們在Host插件的基礎(chǔ)之上建立了上層功能插件(就叫做Extension插件吧,Extension插件依賴于Host插件),提供了解析器實(shí)現(xiàn),對(duì)應(yīng)類型為com.my.extension.parser.MyParserImpl。我們在Extension插件中想使用這個(gè)實(shí)現(xiàn),假設(shè)有如下幾種中創(chuàng)建方式:
          第一種:直接創(chuàng)建實(shí)例,偏不用你Host中的工廠。 俗了點(diǎn),但是沒問題。
           1 package com.my.extension.model;
           2 
           3 public class Customer {
           4     public void doOperation(Object input) throws CoreException{
           5         //直接創(chuàng)建實(shí)例的方式
           6         IParser parser = new MyParserImpl();
           7         
           8         Object model = parser.parse(input);
           9         //TODO 拿到模型之后干其他活
          10     }
          11 }

          第二種,直接使用Class.forName(),還是不用你Host中的工廠。也是俗了點(diǎn),但也沒問題,為什么沒問題,可能就沒有想清楚了~_~
           1 package com.my.extension.model;
           2 
           3 public class Customer {
           4     public void doOperation(Object input) throws CoreException{
           5         try {
           6             //使用默認(rèn)的Class.forName()的方式
           7             IParser parser = (IParser)Class.forName("com.my.extension.parser.MyParserImpl").newInstance();
           8             
           9             Object model = parser.parse(input);
          10             //TODO 拿到模型之后干其他活
          11         } catch (Exception e) {
          12             // TODO: handle exception
          13         }
          14         
          15     }
          16 }

          第三種:用一把工廠 ---》》ClassNotFoundException
           1 package com.my.extension.model;
           2 
           3 public class Customer {
           4     public void doOperation(Object input) throws CoreException{
           5         //使用工廠,不指定類加載器
           6         IParser parser = ParserFactory.createParser("com.my.extension.parser.MyParserImpl");
           7         
           8         Object model = parser.parse(input);
           9         //TODO 拿到模型之后干其他活
          10     }
          11 }
          疑惑了:第二種使用方式為什么沒問題,第三種怎么就有問題了?代碼實(shí)現(xiàn)中都是Class.forName("").newInstance();調(diào)用啊???

          大致錯(cuò)誤原因:
                  這個(gè)時(shí)候如果你只基本熟悉Eclipse的插件類加載機(jī)制(會(huì)去找所依賴的插件中的類型...),可能一時(shí)半會(huì)想不清楚。Java的類加載基本原理中有一條:Class.forName()調(diào)用方式加載類型所默認(rèn)使用的類加載器實(shí)例是加載當(dāng)前類型的類加載器。對(duì)于在Extension插件Customer中調(diào)用Class.forName()使用的是加載Customer類型的類加載器,也就是Extension插件的唯一類加載器;對(duì)于在Host插件中的ParserFactory中調(diào)用Class.forName()則使用的加載ParserFactory類型的類加載器實(shí)例,也就是Host插件的唯一類加載器。你想讓Host插件類加載器去加載一個(gè)在Extension插件中定義的類型,注意Extension插件是依賴于Host插件的啊,根據(jù)Eclipse插件類記載規(guī)則,這種加載請求無法從Host插件類加載器委托到Extension類加載器(說明:使用擴(kuò)展點(diǎn)機(jī)制可以,extension registry會(huì)幫你委托這一個(gè)請求,找到對(duì)應(yīng)的BundleHost...)。如果你想讓Extension插件的類加載器去加載Host中定義的切export出來的類型,Extension插件的類加載器會(huì)把這個(gè)請求合理的委托給Host插件類加載器。


          第四種:用一把工廠,指定類加載器。由于com.my.extension.parser.MyParserImpl本身就和Customer定義在同一插件中,所以公用同一插件類加載器實(shí)例,兩者對(duì)于Extension插件來說都是local class,加載肯定沒問題。
           1 package com.my.extension.model;
           2 
           3 public class Customer {
           4     public void doOperation(Object input) throws CoreException{
           5         //使用工廠,指定類加載器
           6         IParser parser = ParserFactory.createParser("com.my.extension.parser.MyParserImpl"this.getClass().getClassLoader());
           7         
           8         Object model = parser.parse(input);
           9         //TODO 拿到模型之后干其他活
          10     }
          11 }

          以上是舉了一個(gè)小例子,僅僅是為了說明一個(gè)道理:掌握J(rèn)ava類加載基本原理是掌握Eclipse插件類加載原理的基礎(chǔ),不可逾越!!!如果讓你在一個(gè)插件應(yīng)用中寫一個(gè)較為負(fù)責(zé)的自定義類加載器,但靠背一點(diǎn)Eclipse類加載的規(guī)則,那更不夠了...

          Java類加載基本原理還有很多,我博客中有隨筆(老早之前寫的,土了點(diǎn),頭一段時(shí)間貼到了博客上了)。


          本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請注明出處,謝謝!

          posted on 2008-08-28 15:32 zhuxing 閱讀(3620) 評(píng)論(0)  編輯  收藏 所屬分類: Eclipse Plug-in & OSGI

          主站蜘蛛池模板: 平度市| 甘德县| 桐乡市| 大冶市| 杂多县| 甘孜县| 油尖旺区| 四川省| 收藏| 桦南县| 烟台市| 苏州市| 岱山县| 扶余县| 龙井市| 铁力市| 尤溪县| 乌拉特中旗| 丰原市| 宝鸡市| 清新县| 静安区| 卓资县| 溆浦县| 大田县| 榆林市| 靖江市| 理塘县| 太湖县| 越西县| 东乡| 沭阳县| 岳阳县| 迭部县| 舞阳县| 越西县| 剑川县| 岳池县| 宽甸| 芷江| 巴楚县|