Live a simple life

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

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

                      標(biāo)題說(shuō)明了一切,我想說(shuō)的就是如果你在做Eclipse插件開(kāi)發(fā),想真正搞清楚Eclipse插件類加載,那么Java基本類加載原理是基礎(chǔ),無(wú)法逾越!!!我會(huì)舉一個(gè)小例子來(lái)簡(jiǎn)單說(shuō)明一下
                      
                  【情景】
                    例如我們?cè)诘讓幽K插件(就叫做Host)中做了一個(gè)解析器實(shí)現(xiàn)(什么解析器就別管了),對(duì)應(yīng)類型為IParser(com.my.host.parser.IParser),簡(jiǎn)單定義如下:
          1 public interface IParser {
          2     public Object parse(Object input) throws CoreException;
          3 }
                   
                  基本的原則告訴我們:如果一個(gè)實(shí)例的創(chuàng)建過(guò)程較為負(fù)責(zé),則因該把這種實(shí)例的創(chuàng)建和實(shí)例的使用解耦合。于是,我們?cè)贖ost插件中提供了一個(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 
                  這里的簡(jiǎn)單工廠中創(chuàng)建方法返回的是IParser接口類型,目的就是為了保證可以創(chuàng)建子類型的靈活性,同時(shí)確保對(duì)外提供的接口是一致的,有助于客戶端基于接口編程(說(shuō)的有點(diǎn)上綱上線了~_~)

                  同時(shí)我們?cè)贖ost插件中,也提供了一個(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)

                  下面我們?cè)贖ost插件的基礎(chǔ)之上建立了上層功能插件(就叫做Extension插件吧,Extension插件依賴于Host插件),提供了解析器實(shí)現(xiàn),對(duì)應(yīng)類型為com.my.extension.parser.MyParserImpl。我們?cè)贓xtension插件中想使用這個(gè)實(shí)現(xiàn),假設(shè)有如下幾種中創(chuàng)建方式:
          第一種:直接創(chuàng)建實(shí)例,偏不用你Host中的工廠。 俗了點(diǎn),但是沒(méi)問(wè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),但也沒(méi)問(wèn)題,為什么沒(méi)問(wèn)題,可能就沒(méi)有想清楚了~_~
           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 }
          疑惑了:第二種使用方式為什么沒(méi)問(wèn)題,第三種怎么就有問(wèn)題了?代碼實(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ī)則,這種加載請(qǐng)求無(wú)法從Host插件類加載器委托到Extension類加載器(說(shuō)明:使用擴(kuò)展點(diǎn)機(jī)制可以,extension registry會(huì)幫你委托這一個(gè)請(qǐng)求,找到對(duì)應(yīng)的BundleHost...)。如果你想讓Extension插件的類加載器去加載Host中定義的切export出來(lái)的類型,Extension插件的類加載器會(huì)把這個(gè)請(qǐng)求合理的委托給Host插件類加載器。


          第四種:用一把工廠,指定類加載器。由于com.my.extension.parser.MyParserImpl本身就和Customer定義在同一插件中,所以公用同一插件類加載器實(shí)例,兩者對(duì)于Extension插件來(lái)說(shuō)都是local class,加載肯定沒(méi)問(wèn)題。
           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è)小例子,僅僅是為了說(shuō)明一個(gè)道理:掌握J(rèn)ava類加載基本原理是掌握Eclipse插件類加載原理的基礎(chǔ),不可逾越!!!如果讓你在一個(gè)插件應(yīng)用中寫(xiě)一個(gè)較為負(fù)責(zé)的自定義類加載器,但靠背一點(diǎn)Eclipse類加載的規(guī)則,那更不夠了...

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


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

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


          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 扬州市| 万山特区| 惠州市| 新丰县| 赤壁市| 大竹县| 涡阳县| 宜兴市| 独山县| 五台县| 蓬莱市| 礼泉县| 彭阳县| 镇赉县| 瑞金市| 古丈县| 永平县| 西充县| 称多县| 黄大仙区| 克什克腾旗| 中山市| 沂源县| 连城县| 军事| 西平县| 津南区| 元氏县| 桂平市| 泗水县| 涞源县| 乌鲁木齐市| 黔南| 西畴县| 阿巴嘎旗| 荔波县| 竹北市| 安陆市| 垫江县| 酒泉市| 元氏县|