<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    慘淡人生,平淡生活

    The Feature Is Stupid

    2008年5月30日 #

    實(shí)現(xiàn)web服務(wù)的三個(gè)誤區(qū) 讀后感

    我的消息吃了我的服務(wù)器!Kyle指出,通常,Web服務(wù)開發(fā)者開始經(jīng)歷“內(nèi)存溢出”的錯(cuò)誤或者奇怪的“性能問(wèn)題”時(shí),總是會(huì)發(fā)現(xiàn)服 務(wù)器擁有極高的處理負(fù)載,CPU使用率接近100%,以及較低的吞吐量和高網(wǎng)絡(luò)延遲。導(dǎo)致這些癥狀的典型原因是非常大的(有時(shí)會(huì)達(dá)到50 MB或者更大)消息。而且,這些大消息往往包含了非常大的、作為XML消息主體的、采用base-64編碼的二進(jìn)制編碼信息。導(dǎo)致其發(fā)生的原因通常是:

    ……開發(fā)者不理解技術(shù)的局限性:XML處理對(duì)解決許多問(wèn)題都有用,但是你必須認(rèn)識(shí)到消息是要被解析的——并且在大多數(shù)……產(chǎn)品中,這就意味著許多或者所有的消息都會(huì)駐留在內(nèi)存中。

    Kyle建議采用如下方法來(lái)改善這種情況:

    • 不要發(fā)送冗余信息。在許多情況下,發(fā)送二進(jìn)制數(shù)據(jù)時(shí),你可能會(huì)發(fā)現(xiàn)消息高度重復(fù)。如果是這樣,你可能就要考慮在HTTP層面使用壓縮技術(shù)來(lái)改善你的網(wǎng)絡(luò)延遲。雖然這不會(huì)幫助你處理負(fù)載,但可能有助于減輕其中一個(gè)問(wèn)題。
    • 在XML消息體中,根本不要嵌入二進(jìn)制信息。這是較好的解決方法,還有幾種不同的途徑可以實(shí)現(xiàn)這一效果。比如,你可以使用帶有附件的SOAP或者消息傳輸優(yōu)化機(jī)制(MTOM)繞過(guò)解析開銷,盡管這無(wú)助于網(wǎng)絡(luò)延遲問(wèn)題。
    • ……還有一個(gè)更好的辦法,使用SOAP根本不發(fā)送大的二進(jìn)制blob。替代方法,通過(guò)受控的文件傳輸系統(tǒng),使用一個(gè)“帶外數(shù)據(jù)”傳輸……或者“聲明標(biāo)簽(claim Check,參見《EIP模式》或這里)”模式,避免在SOAP和HTTP上發(fā)送大的二進(jìn)制文件。




    任何一種技術(shù)都有它使用的環(huán)境,在做架構(gòu)設(shè)計(jì)的時(shí)候一定要避免因?yàn)閭€(gè)人的偏好,無(wú)意識(shí)的舍棄某些選擇。 一種簡(jiǎn)單的方法論是,根據(jù)需要達(dá)到的目的,列出所有可能的實(shí)現(xiàn)方案,最后做出決定。


    不好意思,你的數(shù)據(jù)正在顯示。根據(jù)Kyle所說(shuō),另一個(gè)典型的Web服務(wù)的“性能問(wèn)題” 是,使用Web服務(wù)的層面非常、非常低——通常Web服務(wù)跟一個(gè)SQL語(yǔ)句相關(guān),這是因?yàn)椋?/p>

    誤解了SOA架構(gòu)原則。一個(gè)優(yōu)秀SOA架構(gòu)的關(guān)鍵原則是你的服務(wù)應(yīng)該具有高復(fù)用性。

    根據(jù)Kyle所說(shuō),這些情況通常發(fā)生在:

    ……如果設(shè)計(jì)是根據(jù)現(xiàn)有代碼“自上而下”衍生出服務(wù),這類服務(wù)就會(huì)出現(xiàn);通常,開發(fā)者會(huì)看著他們現(xiàn)有的架構(gòu)圖并且決定將架構(gòu)中的每一層(包括表現(xiàn)層)轉(zhuǎn)變成服務(wù)集。

    相反,在SOA架構(gòu)的正確位置使用粗粒度的Web服務(wù)會(huì)更好。再次強(qiáng)調(diào),檢查一個(gè)架構(gòu)的標(biāo)準(zhǔn)分層模型,通常在架構(gòu)中會(huì)有一個(gè)明確定義的地方已經(jīng)封裝 了系統(tǒng)業(yè)務(wù)邏輯。可以使用“遠(yuǎn)程門面模式(Remote Facade Pattern)”來(lái)包裝這些服務(wù),以便用合適的方式來(lái)暴露基于模型的服務(wù)。



    同樣是可以利用方法論來(lái)避免問(wèn)題,但對(duì)于粒度的把握就是一個(gè)經(jīng)驗(yàn)的問(wèn)題。




    模式(Schema)?我們不需要任何發(fā)臭的模式! Kyle指出,通常開發(fā)者試圖重用現(xiàn)有代碼來(lái)生成和解析作為Web服務(wù)實(shí)現(xiàn)基礎(chǔ)的XML。這些實(shí)現(xiàn)通常使用XML解析器來(lái)編組/解組消息,同時(shí)使用 Java HTTP類來(lái)發(fā)送和接收XML文檔。使用Web服務(wù)時(shí),通用的方法是,創(chuàng)建使用模式元素的WSDL文檔,使XML不受阻地通過(guò),然后在現(xiàn)有代碼中對(duì)它們進(jìn) 行解析。

    這個(gè)問(wèn)題的癥狀是組織沒(méi)有看到SOA承諾的好處,而且維護(hù)他們的解決方案似乎比以前使用Web服務(wù)的時(shí)候更難(而不是更容易)

    簡(jiǎn)單的解決方案是,每當(dāng)寫Web服務(wù)時(shí),不管使用WS-*標(biāo)準(zhǔn)還是使用REST方法,都要確保你創(chuàng)建了代表你文檔結(jié)構(gòu)的完整準(zhǔn)確的XML模式。

    如果你正在構(gòu)建WS-* Web服務(wù),那么這個(gè)XML應(yīng)該被包含在描述你的Web服務(wù)的WSDL之中。即使你在使用REST方法,擁有易于訪問(wèn)的XML模式將鼓勵(lì)你的服務(wù)被重用。






    posted @ 2009-03-16 14:55 季失羽 閱讀(224) | 評(píng)論 (0)編輯 收藏

    如何看懂Java混淆后的反編譯代碼(轉(zhuǎn))

    如何看懂Java混淆后的反編譯代碼

    作者:dozb

    一般情況下Java應(yīng)用的開發(fā)者為了保護(hù)代碼不被別人抄襲,在生成class文件的時(shí)候都java文件進(jìn)行了混淆,這種class文件用反編譯工具得到的結(jié)果很難看懂,并且不能進(jìn)行編譯。本文從研究的角度,淺析如何讀懂這種反編譯過(guò)來(lái)的文件。

    例子一:賦值
    反編譯過(guò)來(lái)的代碼如下:
            Node node;
            Node node1 = _$3.getChildNodes().item(0);
            node1;
            node1;
            JVM INSTR swap ;
            node;
            getChildNodes();
            0;
            item();
            getChildNodes();
            0;
            item();
            getNodeValue();
            String s;
            s;
    原始語(yǔ)句:
            Node node;
            Node node1 = currDocument.getChildNodes().item(0);
     node = node1;
            String s = node.getChildNodes().item(0).getChildNodes().item(0).getNodeValue();
    注解:
            JVM INSTR swap ; //賦值語(yǔ)句
    練習(xí):
            String s1;
            String s8 = node.getChildNodes().item(1).getChildNodes().item(0).getNodeValue();
            s8;
            s8;
            JVM INSTR swap ;
            s1;
            10;
            Integer.parseInt();
            int i;
            i;

       
    例子二:不帶參數(shù)創(chuàng)建對(duì)象
    反編譯過(guò)來(lái)的代碼如下:
            JVM INSTR new #244 <Class CrossTable>;
            JVM INSTR dup ;
            JVM INSTR swap ;
            CrossTable();
            CrossTable crosstable;
            crosstable;

    原始語(yǔ)句:
            CrossTable crosstable = new CrossTable();
    注解:
    練習(xí):
            JVM INSTR new #246 <Class Database>;
            JVM INSTR dup ;
            JVM INSTR swap ;
            Database();
            Object obj;
            obj;

    例子三:帶參數(shù)創(chuàng)建對(duì)象
    反編譯過(guò)來(lái)的代碼如下:
            JVM INSTR new #262 <Class StringBuffer>;
            JVM INSTR dup ;
            JVM INSTR swap ;
            String.valueOf(s2);
            StringBuffer();
            s.substring(j, i);
            append();
            s6;
            append();
            toString();
            s2;
     
    原始語(yǔ)句:
     s2 = (new StringBuffer(String.valueOf(s2))).append(s.substring(j, i)).append(s6).toString();
    注解:
     此語(yǔ)句實(shí)際上是:s2 += s.substring(j, i) + s6;
    練習(xí):

    例子四:for循環(huán)
    反編譯過(guò)來(lái)的代碼如下:
            int k = 0;
              goto _L4
    _L8:
     ...
     k++;
    _L4:
            if(k < as.length) goto _L8; else goto _L7

    原始語(yǔ)句:
     for(int k=0;k < as.length;k++)
     {
         ...
     }
    注解:

    例子五:while循環(huán)
    反編譯過(guò)來(lái)的代碼如下:
            String s1 = "";
              goto _L1
    _L3:
            JVM INSTR new #262 <Class StringBuffer>;
            JVM INSTR dup ;
            JVM INSTR swap ;
            String.valueOf(s1);
            StringBuffer();
            _$2(resultset, s, l);
            append();
            toString();
            s1;
    _L1:
            if(resultset.next()) goto _L3; else goto _L2

    原始語(yǔ)句:
     String s1 = "";
     while(resultset.next())
     {
      s1 = s1 + resultSetToString(resultset, s, l);

     }

    posted @ 2009-03-03 09:59 季失羽 閱讀(1646) | 評(píng)論 (0)編輯 收藏

    [翻譯]走出ClassLoader的迷宮

    [說(shuō)明]幾個(gè)關(guān)鍵字將不翻譯

    1. ClassLoader
    2. System
    3. Context
    4. Thread

    走出ClassLoader的迷宮

                                                                   System、Current和Context ClassLoader?分別在何種情形下使用?


    1、問(wèn)題:在何種情形下使用thread.getcontextclassloader()?

    盡管沒(méi)經(jīng)常遇到這個(gè)問(wèn)題,但是想獲得準(zhǔn)確的答案并不那么容易,特別是在開發(fā)應(yīng)用框架的時(shí)候,你需要?jiǎng)討B(tài)的加載一些類和資源,不可避免的你會(huì)被此困擾。一般來(lái)說(shuō),動(dòng)態(tài)載入資源有三種ClassLoader可以選擇,System ClassLoader(也叫App ClassLoader)、當(dāng)前類的ClassLoader和CurrentThread的Context ClassLoader。那么, 如何選擇使用?

    首先可以簡(jiǎn)單排除的是System ClassLoader,這個(gè)ClassLoader負(fù)責(zé)從參數(shù)-classpath、-cp、和操作系統(tǒng)CLASSPATH中載入資源。并且,任何ClassLoader的getSystemXXX()方法都是有以上幾個(gè)路徑指定的。我們應(yīng)該很少需要編寫直接使用ClassLoader的程序,否則你的代碼將只能在命令行運(yùn)行,發(fā)布你的代碼成為ejb、web應(yīng)用或者java web start應(yīng)用,我肯定他們會(huì)崩潰!

    接下來(lái),我們只剩下兩個(gè)選擇了:當(dāng)前ClassLoader和Thread Context ClassLoader

    Current ClassLoader:當(dāng)前類所屬的ClassLoader,在虛擬機(jī)中類之間引用,默認(rèn)就是使用這個(gè)ClassLoader。另外,當(dāng)你使用Class.forName(), Class.getResource()這幾個(gè)不帶ClassLoader參數(shù)的方法是,默認(rèn)同樣適用當(dāng)前類的ClassLoader。你可以通過(guò)方法XX.class.GetClassLoader()獲取。

    Thread Context ClassLoader,沒(méi)一個(gè)Thread有一個(gè)相關(guān)聯(lián)系的Context ClassLoader(由native方法建立的除外),可以通過(guò)Thread.setContextClassLoader()方法設(shè)置。如果你沒(méi)有主動(dòng)設(shè)置,Thread默認(rèn)集成Parent Thread的 Context ClassLoader(注意,是parent Thread 不是父類)。如果 你整個(gè)應(yīng)用中都沒(méi)有對(duì)此作任何處理,那么 所有的Thread都會(huì)以System ClassLoader作為Context ClassLoader。知道這一點(diǎn)很重要,因?yàn)閺膚eb服務(wù)器,java企業(yè)服務(wù)器使用一些復(fù)雜而且精巧的ClassLoader結(jié)構(gòu)去實(shí)現(xiàn)諸如JNDI、線程池和熱部署等功能以來(lái),這種簡(jiǎn)單的情況越發(fā)的少見了。

    這篇文章中為什么把Thread Context ClassLoader放在首要的位置,別人并沒(méi)有大張旗鼓的介紹它?很多開發(fā)者都對(duì)此不甚了解,因?yàn)閟un沒(méi)有提供很好的說(shuō)明文檔。

    事實(shí)上,Context ClassLoader提供一個(gè)突破委托代理機(jī)制的后門。虛擬機(jī)通過(guò)父子層次關(guān)系組織管理ClassLoader,沒(méi)有個(gè)ClassLoader都有一個(gè)Parent ClassLoader(BootStartp不在此范圍之內(nèi)),當(dāng)要求一個(gè)ClassLoader裝載一個(gè)類是,他首先請(qǐng)求Parent ClassLoader去裝載,只有parent ClassLoader裝載失敗,才會(huì)嘗試自己裝載。

    但是,某些時(shí)候這種順序機(jī)制會(huì)造成困擾,特別是jvm需要?jiǎng)討B(tài)載入有開發(fā)者提供的資源時(shí)。就以JNDI為例,JNDI的類是由bootstarp ClassLoader從rt.jar中間載入的,但是JNDI具體的核心驅(qū)動(dòng)是由正式的實(shí)現(xiàn)提供的,并且通常會(huì)處于-cp參數(shù)之下(注:也就是默認(rèn)的System ClassLoader管理),這就要求bootstartp ClassLoader去載入只有SystemClassLoader可見的類,正常的邏輯就沒(méi)辦法處理。怎么辦呢?parent可以通過(guò)獲得當(dāng)前調(diào)用Thread的方法獲得調(diào)用線程的Context ClassLoder 來(lái)載入類。

    順帶補(bǔ)充一句,JAXP從1.4之后也換成了類似JNDI的ClassLoader實(shí)現(xiàn),嘿嘿,剛剛我說(shuō)什么來(lái)著,SUN文檔缺乏 ^_^

    介紹完這些之后,我們走到的十字路口,任一選擇都不是萬(wàn)能的。一些人認(rèn)為Context ClassLoader將會(huì)是新的標(biāo)準(zhǔn)。但是 一旦你的多線程需要通訊某些共享數(shù)據(jù),你會(huì)發(fā)現(xiàn),你將有一張極其丑陋的ClassLoader分布圖,除非所有的線程使用一樣的Context ClassLoader。并且委派使用當(dāng)前ClassLoder對(duì)一些方法來(lái)說(shuō)是默認(rèn)繼承來(lái)的,比如說(shuō)Class.forName()。盡管你明確的在任何你能控制的地方使用Context ClassLoader,但是畢竟還有很多代碼不歸你管(備注:想起一個(gè)關(guān)于UNIX名字來(lái)源的笑話)。

    某些應(yīng)用服務(wù)器使用不同的ClassLoder作為Context ClassLoader和當(dāng)前ClassLoader,并且這些ClassLoader有著相同的ClassPath,但沒(méi)有父子關(guān)系,這使得情況更復(fù)雜。請(qǐng)列位看官,花幾秒鐘時(shí)間想一想,為什么這樣不好?被載入的類在虛擬機(jī)內(nèi)部有一個(gè)全名稱,不同的ClassLoader載入的相同名稱的類是不一樣的,這就隱藏了類型轉(zhuǎn)換錯(cuò)誤的隱患。(注:奶奶的 俺就遇到過(guò),JBOSSClassLoader機(jī)制蠻挫的)

    這種混亂事實(shí)上在java類中也有,試著去猜測(cè)任何一個(gè)包含動(dòng)態(tài)加載的java規(guī)范的ClassLoader機(jī)制,以下是一個(gè)清單:

    • JNDI uses context classloaders
    • Class.getResource() and Class.forName() use the current classloader
    • JAXP uses context classloaders (as of J2SE 1.4)
    • java.util.ResourceBundle uses the caller's current classloader
    • URL protocol handlers specified via java.protocol.handler.pkgs system property are looked up in the bootstrap and system classloaders only
    • Java Serialization API uses the caller's current classloader by default

    而且關(guān)于這些資源的類加載機(jī)制文檔時(shí)很少。

    java開發(fā)人員應(yīng)該怎么做?

    如果你的實(shí)現(xiàn)是利用特定的框架,那么恭喜你,實(shí)現(xiàn)它遠(yuǎn)比實(shí)現(xiàn)框架要簡(jiǎn)單得多!例如,在web應(yīng)用和EJB應(yīng)用中,你僅僅只要使用 Class.getResource()就足夠了。

    其他的情形下,俺有個(gè)建議(這個(gè)原則是俺工作中發(fā)現(xiàn)的,侵權(quán)必究,抵制盜版。),

    下面這個(gè)類可以在整個(gè)應(yīng)用中的任何地方使用,作為一個(gè)全局的ClassLoader(所有的示例代碼可以從download下載):

     1 public abstract class ClassLoaderResolver {
     2 /**
     3 * This method selects the best classloader instance to be used for
     4 * class/resource loading by whoever calls this method. The decision
     5 * typically involves choosing between the caller's current, thread context,
     6 * system, and other classloaders in the JVM and is made by the
     7 * {@link IClassLoadStrategy} instance established by the last call to
     8 * {@link #setStrategy}.
     9 *
    10 @return classloader to be used by the caller ['null' indicates the
    11 * primordial loader]
    12 */
    13 public static synchronized ClassLoader getClassLoader() {
    14 final Class caller = getCallerClass(0);
    15 final ClassLoadContext ctx = new ClassLoadContext(caller);
    16 
    17 return s_strategy.getClassLoader(ctx);
    18 }
    19 
    20 public static synchronized IClassLoadStrategy getStrategy() {
    21 return s_strategy;
    22 }
    23 
    24 public static synchronized IClassLoadStrategy setStrategy(
    25 final IClassLoadStrategy strategy) {
    26 final IClassLoadStrategy old = s_strategy;
    27 s_strategy = strategy;
    28 
    29 return old;
    30 }
    31 
    32 /**
    33 * A helper class to get the call context. It subclasses SecurityManager to
    34 * make getClassContext() accessible. An instance of CallerResolver only
    35 * needs to be created, not installed as an actual security manager.
    36 */
    37 private static final class CallerResolver extends SecurityManager {
    38 protected Class[] getClassContext() {
    39 return super.getClassContext();
    40 }
    41 
    42 // End of nested class
    43 
    44 /*
    45 * Indexes into the current method call context with a given offset.
    46 */
    47 private static Class getCallerClass(final int callerOffset) {
    48 return CALLER_RESOLVER.getClassContext()[CALL_CONTEXT_OFFSET
    49 + callerOffset];
    50 }
    51 
    52 private static IClassLoadStrategy s_strategy; // initialized in <clinit>
    53 
    54 private static final int CALL_CONTEXT_OFFSET = 3// may need to change if
    55 // this class is
    56 // redesigned
    57 private static final CallerResolver CALLER_RESOLVER; // set in <clinit>
    58 
    59 static {
    60 try {
    61 // This can fail if the current SecurityManager does not allow
    62 // RuntimePermission ("createSecurityManager"):
    63 
    64 CALLER_RESOLVER = new CallerResolver();
    65 catch (SecurityException se) {
    66 throw new RuntimeException(
    67 "ClassLoaderResolver: could not create CallerResolver: "
    68 + se);
    69 }
    70 
    71 s_strategy = new DefaultClassLoadStrategy();
    72 }
    73 // End of class.
    74 
    75 
    76 


    通過(guò)ClassLoaderResolver.getClassLoader()方法獲得一個(gè)ClassLoader的引用,并且利用正常的ClassLoader的api去加載資源,你也可以使用 ResourceLoader API作為備選方案

     1 public abstract class ResourceLoader {
     2 
     3 /**
     4  * @see java.lang.ClassLoader#loadClass(java.lang.String)
     5  */
     6 public static Class loadClass (final String name)throws ClassNotFoundException{
     7 
     8 final ClassLoader loader = ClassLoaderResolver.getClassLoader (1);
     9 
    10 return Class.forName (name, false, loader);
    11 
    12 }
    13 
    14 /**
    15 
    16 @see java.lang.ClassLoader#getResource(java.lang.String)
    17 
    18 */    
    19 
    20 
    21 public static URL getResource (final String name){
    22 
    23 final ClassLoader loader = ClassLoaderResolver.getClassLoader (1);
    24 
    25 if (loader != null)return loader.getResource (name);
    26 else return ClassLoader.getSystemResource (name);
    27 }
    28  more methods 
    29 
    30 // End of class

    而決定使用何種ClassLoader策略是由接口實(shí)現(xiàn)的,這是一種插件機(jī)制,方便變更。

    public interface IClassLoadStrategy{
    ClassLoader getClassLoader (ClassLoadContext ctx);
    // End of interface

    它需要一個(gè)ClassLoader Context 對(duì)象去決定使用何種ClassLoader策略。
     1 public class ClassLoadContext{
     2 
     3 public final Class getCallerClass (){
     4 return m_caller;
     5 }
     6 
     7 ClassLoadContext (final Class caller){
     8 m_caller = caller;
     9 
    10 }
    11 
    12 private final Class m_caller;
    13 
    14 // End of class

    ClassLoadContext.getCallerClass()返回調(diào)用者給ClassLoaderResolver 或者 ResourceLoader,因此能獲得調(diào)用者的ClassLoader。需要注意的是,調(diào)用者是不會(huì)變的 (注:作者使用的final修飾字)。俺的方法不需要對(duì)現(xiàn)有的業(yè)務(wù)方法做擴(kuò)展,而且可以作為靜態(tài)方法是用。而且,你可以根據(jù)自己的業(yè)務(wù)場(chǎng)景實(shí)現(xiàn)獨(dú)特的ClassLoaderContext。

    看出來(lái)沒(méi),這是一種很熟悉的設(shè)計(jì)模式,XD ,把獲得ClassLoader的策略從業(yè)務(wù)中獨(dú)立出來(lái),這個(gè)策略可以是"總是用ContextClassLoader"或者"總是用當(dāng)前ClassLoader"。想預(yù)先知道那種策略是正確的比較困難,那么這種模式可以讓你簡(jiǎn)單的改變策略。

    俺寫了一個(gè)默認(rèn)的實(shí)現(xiàn),基本可以對(duì)付95%的場(chǎng)景(enjoy yourself)

     1 public class DefaultClassLoadStrategy implements IClassLoadStrategy{
     2 
     3 public ClassLoader getClassLoader (final ClassLoadContext ctx){
     4 
     5 final ClassLoader callerLoader = ctx.getCallerClass ().getClassLoader ();
     6 
     7 final ClassLoader contextLoader = Thread.currentThread ().getContextClassLoader ();
     8 
     9 ClassLoader result;
    10 // If 'callerLoader' and 'contextLoader' are in a parent-child
    11 // relationship, always choose the child:
    12 if (isChild (contextLoader, callerLoader))result = callerLoader;
    13 else if (isChild (callerLoader, contextLoader))result = contextLoader;
    14 else{
    15 // This else branch could be merged into the previous one,
    16 // but I show it here to emphasize the ambiguous case:
    17 result = contextLoader;
    18 }
    19 final ClassLoader systemLoader = ClassLoader.getSystemClassLoader ();
    20 
    21 
    22 // Precaution for when deployed as a bootstrap or extension class:
    23 if (isChild (result, systemLoader))result = systemLoader;
    24 return result;
    25 }
    26 
    27 
    28 
    29  more methods 
    30 
    31 // End of class
    32 


    上面的邏輯比較簡(jiǎn)單,如果當(dāng)前ClassLoader和Context ClassLoader是父子關(guān)系,那就總選兒子,根據(jù)委托原則,這個(gè)很容易理解。

    如果兩人平級(jí),選擇正確的ClassLoader很重要,運(yùn)行時(shí)不允許含糊。這種情況下,我的代碼選擇Context ClassLoader(這是俺個(gè)人的經(jīng)驗(yàn)之談),當(dāng)然也不要擔(dān)心不能改變,你能隨便根據(jù)需要改變。一般而言,Context ClassLoader比較適合框架,而Current ClassLoader在業(yè)務(wù)邏輯中用的更多。

    最后,檢查確保選中的ClassLoader不是System ClassLoader的parent,一旦高于System ClassLoader ,請(qǐng)使用System ClassLoader(你的類部署在Ext路徑下面,就會(huì)出現(xiàn)這種情況)。

    請(qǐng)注意,俺故意沒(méi)關(guān)注被載入資源的名稱。Java XML API 成為java 核心api的經(jīng)歷告訴我們,根據(jù)資源名稱過(guò)濾是很不cool的idea。而且 我也沒(méi)有去確認(rèn)到底哪個(gè)ClassLoader被取得了,因?yàn)橹灰宄恚@很容易被推理出來(lái)。(哈哈,俺是強(qiáng)淫)

    盡管討論java 的ClassLoader不是一個(gè)很cool的話題(譯者注,當(dāng)年不cool,但是現(xiàn)在很cool),而且Java EE的ClassLoader策略越發(fā)的依賴各種平臺(tái)的升級(jí)。如果這沒(méi)有一個(gè)更好的設(shè)計(jì)的話,將會(huì)變成一個(gè)大大的問(wèn)題。不敢您是否同意俺的觀點(diǎn),俺尊重你說(shuō)話的權(quán)利,所以請(qǐng)給俺分享您的意見經(jīng)驗(yàn)。

    作者介紹:

    Vladimir Roubtsov,曾經(jīng)使用多種語(yǔ)言有超過(guò)13年的編程經(jīng)歷(恩 現(xiàn)在應(yīng)該超過(guò)15年了 hoho),95年開始接觸java(hoho 俺是99年看的第一本java書)。現(xiàn)在為Trilogy in Austin, Texas開發(fā)企業(yè)軟件。



    翻譯完了,MMD 翻譯還是很麻煩的。 XD ........

    43 Things :

    posted @ 2008-05-30 18:22 季失羽 閱讀(5295) | 評(píng)論 (0)編輯 收藏

    主站蜘蛛池模板: 色屁屁www影院免费观看视频| 波多野结衣一区二区免费视频| 国产福利电影一区二区三区,免费久久久久久久精 | 国产成人精品无码免费看| 国产99久久亚洲综合精品| 亚洲精品韩国美女在线| 丝袜熟女国偷自产中文字幕亚洲| 午夜dj在线观看免费视频| 青青草a免费线观a| 久久亚洲免费视频| 国产真人无码作爱视频免费| 一个人看的hd免费视频| 亚洲熟女www一区二区三区| 亚洲经典在线中文字幕| 亚洲精品福利视频| 亚洲AV永久无码精品成人| 亚洲国产精品国产自在在线| 精品国产一区二区三区免费看| 成人免费午夜无码视频| **真实毛片免费观看| 国产精成人品日日拍夜夜免费| A国产一区二区免费入口| 日韩久久无码免费毛片软件| 国产精品观看在线亚洲人成网| 亚洲日韩AV无码一区二区三区人| 亚洲乱码中文字幕小综合| 亚洲美女视频网站| 久久丫精品国产亚洲av不卡| 亚洲一区二区三区四区在线观看| 亚洲AV无码一区东京热久久| 久久精品视频亚洲| 无码专区—VA亚洲V天堂| 亚洲国产成人久久精品动漫| 亚洲国产高清人在线| 亚洲综合国产精品| 亚洲福利视频一区二区三区| 亚洲熟妇av一区二区三区下载| 91亚洲性爱在线视频| 亚洲综合精品伊人久久| 欧美亚洲国产SUV| 日日狠狠久久偷偷色综合免费|