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

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

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

    stone2083

    #

    關于cookie特殊字符的一點理解

    背景:
    加密的cookie信息中帶有特殊字符(“=”),導致讀cookie的時候,特殊符號丟失,解密失敗

    看了同事“關于cookie特殊字符”的說明郵件,和網上對cookie特殊字符問題的解釋:

    我們在實際使用Cookie過程中要注意一些問題:

      1. Cookie的兼容性問題

      Cookie的格式有2個不同的版本,第一個版本,我們稱為Cookie Version 0,是最初由Netscape公司制定的,也被幾乎所有的瀏覽器支持。而較新的版本,Cookie Version 1,則是根據RFC 2109文檔制定的。為了確保兼容性,JAVA規定,前面所提到的涉及Cookie的操作都是針對舊版本的Cookie進行的。而新版本的Cookie目前還不被Javax.servlet.http.Cookie包所支持。

      2. Cookie的內容

      同樣的Cookie的內容的字符限制針對不同的Cookie版本也有不同。在Cookie Version 0中,某些特殊的字符,例如:空格,方括號,圓括號,等于號(=),逗號,雙引號,斜杠,問號,@符號,冒號,分號都不能作為Cookie的內容。這也就是為什么我們在例子中設定Cookie的內容為“Test_Content”的原因。

      雖然在Cookie Version 1規定中放寬了限制,可以使用這些字符,但是考慮到新版本的Cookie規范目前仍然沒有為所有的瀏覽器所支持,因而為保險起見,我們應該在Cookie的內容中盡量避免使用這些字符。

    摘自:http://swingchen.bokee.com/6200015.html
    類似這樣的解釋,搜索出來的結果,挺多。

    但是,我去看了RFC2109(http://www.faqs.org/rfcs/rfc2109.html),其說明如下:

    value中的token,是有一組非特殊字符,非空白字符。而它是在RFC 2068(http://www.faqs.org/rfcs/rfc2068.html)中制定的 (是對Header的規范),請看:


    也就是說,所謂的Cookie1,同樣有特殊字符的限制。
    同樣,在Cookie2(RFC2965)中,也如此。

    想想也是啊,如果沒有特殊字符的限制,解析Header的時候,還不亂套了?

    看了RFC之后,我們再來看看Tomcat中的實現(6.0.29版本),請看:
    org.apache.tomcat.util.http.Cookies

    1.類注釋:
    A collection of cookies - reusable and tuned for server side performance.
    Based on RFC2965 ( and 2109 )
    是基于RFC2965/RFC2109規范來實現的

    2.特殊字符的定義
    /*
        List of Separator Characters (see isSeparator())
        Excluding the '/' char violates the RFC, but 
        it looks like a lot of people put '/'
        in unquoted values: '/': ; //47 
        '\t':9 ' ':32 '\"':34 '(':40 ')':41 ',':44 ':':58 ';':59 '<':60 
        '=':61 '>':62 '?':63 '@':64 '[':91 '\\':92 ']':93 '{':123 '}':125
        
    */
        
    public static final char SEPARATORS[] = { '\t'' ''\"''('')'','
            
    ':'';''<''=''>''?''@''[''\\'']''{''}' };
    根據規范,定義了特殊字符。除了“/”這個符號。因為大多數人會直接使用“/”。

    3.針對“=”特殊處理
    /**
     * If true, cookie values are allowed to contain an equals character without
     * being quoted.
     
    */
    public static final boolean ALLOW_EQUALS_IN_VALUE;

    static {
        ALLOW_EQUALS_IN_VALUE 
    = Boolean.valueOf(System.getProperty(
                
    "org.apache.tomcat.util.http.ServerCookie.ALLOW_EQUALS_IN_VALUE",
                
    "false")).booleanValue();
    }
    可以在catalina.properties中,添加這個配置項 (或者啟動過程中加上-D參數),使得cookie value中允許存在“=”符號。
    所以本文開頭提到的問題,可以使用這個方法得到解決

    4.解析過程
    /**
     * Parses a cookie header after the initial "Cookie:"
     * [WS][$]token[WS]=[WS](token|QV)[;|,]
     * RFC 2965
     * JVK
     
    */
    public final void processCookieHeader(byte bytes[], int off, int len){
        
    //詳細代碼,省略
    }


    備注:
    RFC沒有仔細看(時間有限,并且看E文挺累的),如理解有誤,請告知。


    posted @ 2010-11-03 13:27 stone2083 閱讀(7200) | 評論 (1)編輯 收藏

    爬取交通違章信息的腳本

         摘要: 會開車了,也慢慢不規矩起來了,于是乎,違章信息也慢慢多起來了,但是無法第一時間通知到自己。 雖說,有個網站:http://www.hzti.com/service/qry/violation_veh.aspx?pgid=&type=1&node=249 可以查詢非現場違章情況, 不過: 1.我是懶人,主動去查詢的時候不太樂意做 2.車輛識別碼,永遠記不住 3.每次輸驗證...  閱讀全文

    posted @ 2010-10-29 18:30 stone2083 閱讀(3127) | 評論 (8)編輯 收藏

    關于java多線程的幾個小貼士

    原文地址:
    http://weblogs.java.net/blog/caroljmcdonald/archive/2009/09/17/some-java-concurrency-tips

    大綱:

    Prefer immutable objects/data
    盡可能使用不變對象/數據

    Threading risks for Web applications
    注意web應用的線程安全問題

    Hold Locks for as short a time as possible
    持有鎖的時間盡可能短

    Prefer executors and tasks to threads
    盡可能使用JDK并發工具包提供的Executor框架,進行多線程操作

    Prefer Concurrency utilities to wait and notify
    盡可能使用JDK并發工具包提供的工具進行同步(等待和通知)

    • Concurrent Collections
      • ConcurrentMap
      • ConcurrentHashMap
      • COncurrentLinkedQueue
      • CopyOnWriteArrayList
    • BlockingQueue Implementations
      • ArrayBlockingQueue
      • LinkedBlockingQueue
      • PriorityBlockingQueue

    Producer Consumer Pattern
    了解生產者消費者模式

    Synchronizers
    同步器

    • Semaphore
    • CountDownLatch
    • CyclicBarrier
    • Exchanger

    Multithreaded Lazy Initialization is tricky
    多線程環境下,lazy init是一件棘手的事情

    Prefer Normal initialization
    盡可能使用正常的初始化(盡可能不要使用lazy init)


    posted @ 2010-09-15 17:37 stone2083 閱讀(1924) | 評論 (2)編輯 收藏

    java反射效率

         摘要: java反射效率到底如何,花了點時間,做了一個簡單的測試.供大家參考. 測試背景: 1. 測試簡單Bean(int,Integer,String)的set方法 2. loop 1億次 3. 測試代碼盡可能避免對象的創建,復發方法的調用,僅僅測試set方法的耗時 測試結果:  場景 &...  閱讀全文

    posted @ 2010-09-15 14:04 stone2083 閱讀(8025) | 評論 (9)編輯 收藏

    IBatis下DAO單元測試另類思路

    在說另類思路之前,先說下傳統的測試方法:
    0.準備一個干凈的測試數據庫環境
      這個是前提
    1.測試數據準備
      使用文本,excel,或者wiki等,準備測試sql以及測試數據
      利用dbfit,dbutil等工具將準備的測試數據導入到數據庫中
    2.執行dao方法
      執行被測試的dao方法
    3.測試結果斷言
      利用dbfit,dbutil等工具,斷言測試結果數據和預計是否一致
    4.所有數據回滾

    其實,對于這個流程來說,目前的dao測試框架,支持的已經比較完美了
    但是此類測試方法,也有明顯的缺點(或者不能叫缺點,叫使用比較麻煩的地方)
    如下:
    1.背上了一個數據庫環境.
      不輕量
      這是一個共享環境,誰也無法確保環境數據是否真正的干凈
    2.測試數據準備是一件麻煩的事情
      新表,10幾個字段毫不為奇;老表,50幾個字段甚至百來個字段,也偶有可見;無論是使用文本,excel,wiki,準備工作量,都是巨大的.
      準備的數據,部分字段內容可以是無意義的,部分字段內容又是需要符合測試意圖(testcase設計目的),部分字段還是其他表的關聯字段.從而導致后續維護人員無法了解準備數據意圖.
      (實踐中,也出現過,一同事在維護他人單元測試時,由于無法了解測試數據準備意圖,寧可重新刪除,自己準備一份)
    3.預計結果數據準備也是一件麻煩的事情
      理由如上

    所以,理論上是完美的測試方案,在實踐過程中,卻是一件麻煩的事情.導致DAO單元測試維護困難.


    分析了現狀,我們再來分析下,IBatis下DAO,程序員主要做了哪些編碼:
    1. 寫了一份sqlmap.xml配置文件
    2. 通過getSqlMapClientTemplate.doSomething($sqlID,$param), 執行語句
    (當然,沒有使用spring的同學,也是使用了類似sqlMapClient.doSomething($sqlID,$param)方法)

    而步驟2其實是框架替我們做了的事情,按照MOCK的思想,其實這部分代碼可以被MOCK的,那么我們是否可以做如下假設:
    只要sqlmap.xml中配置信息(主要包括resultmap和statement)是正確的,那么執行結果也應該是正確的.

    而我所謂的另類思路,就是基于這個假設,得出的:
    IBatis下,DAO單元測試,我們拋棄背負的數據庫環境,只要根據不同的條件,斷言不同的sql即可.

    于是乎,封裝了一個IbatisSqlTester,可以根據sqlmap中的statement和傳入的條件參數,生成sql語句.
    那么,DAO單元測試就簡單了,脫離下數據庫環境:
    public class ScoreDAOTest extends TestCase {
     
        @SpringBeanByName
        
    private IbatisSqlTester ibatisSqlTester;  //通過spring配置,需要注入sqlmapclient對象
     
        @Test
        
    public void testListTpScores() {
            Map
    <String, Object> param = new HashMap<String, Object>(1);
            param.put(
    "memberIds"new String[] { "stone""stone2083" });
            SqlStatement sql 
    = ibatisSqlTester.test("MS-LIST-SCORES", param);
            
    // sql全部匹配
            SqlAssert.isEqual("select * from score where member_id in ('stone','stone2083')", sql.toString());
            
    // sql包含member_id,athena2002,stone關鍵詞
            SqlAssert.keyWith(sql.toString(), "member_id""stone""stone2083");
            
    // sql符合某個 正則
            SqlAssert.regexWith(".* where member_id in .*", sql.toString());
            
            
    //其中,SqlAssert也可以換 成want.string()中的方法.
        }
    }

    優勢:
      脫離了數據庫環境
      脫離了表結構數據準備
      脫離了預計結果數據準備
      讓單元測試變成sql的斷言,編寫相對更簡單
    缺點:
     
    row mapper過程無法被測試


    最后,附上兩個核心的代碼類(還未完成),供大家參考:
    SqlStatement.java
    /**
     * <pre>
     * SqlStatement:Sql語句對象.
     * 包含:
     *  1.sql語句,類似  select * from offer where id = ? and member_id = ?
     *  2.參數值,類似 [1,stone2083]
     *  
     *  toString方法,返回執行的sql語句,如:
     *  select * from offer where id = '1' and member_id = 'stone2083'
     * </pre>
     * 
     * 
    @author Stone.J 2010-8-9 下午02:55:36
     
    */
    public class SqlStatement {

        
    //sql
        private String   sql;
        
    //sql參數
        private Object[] param;

        
    /**
         * <pre>
         * 輸出最終執行的sql內容.
         * 將sql和param進行merge,產生最終執行的sql語句
         * </pre>
         
    */
        @Override
        
    public String toString() {
            
    return merge();
        }

        
    /**
         * <pre>
         * 將sql進行格式化.
         * 
         * 目前只是簡單進行格式化.去除前后空格,已經重復空格
         * TODO:請使用統一格式化標準規,建議使用SqlFormater類,進行處理
         * </pre>
         * 
         * 
    @param sql
         * 
    @return
         
    */
        
    protected String format(String sql) {
            
    if (sql == null) {
                
    return null;
            }
            
    return sql.toLowerCase().trim().replaceAll("\\s{1,}"" ");
        }

        
    /**
         * <pre>
         * 將sql和param進行merge.
         * TODO:請嚴格按照SQL標準,進行merge sql內容
         * </pre>
         
    */
        
    protected String merge() {
            
    if (param == null || param.length == 0) {
                
    return this.sql;
            }
            String ret 
    = sql;
            
    for (Object p : param) {
                ret 
    = ret.replaceFirst("\\?""'" + p.toString() + "'");
            }
            
    return ret;
        }

        
    public String getSql() {
            
    return sql;
        }

        
    public void setSql(String sql) {
            
    this.sql = format(sql);
        }

        
    public Object[] getParam() {
            
    return param;
        }

        
    public void setParam(Object[] param) {
            
    this.param = param;
        }
    }

    IbatisSqlTester.java
    /**
     * <pre>
     * IBtatis SQL 測試
     * 一般IBatis DAO單元測試,主要就是在測試ibatis的配置文件.
     * IbatisSqlTester將根據提供的Sql Map Id 和 對應的參數,返回 {
    @link SqlStatement}對象,提供最終執行的sql語句
     * 通過外部SqlAssert對象,將預計Sql和實際產生的Sql進行對比,判斷是否正確
     * </pre>
     * 
     * 
    @author Stone.J 2010-8-9 下午02:58:46
     
    */
    public class IbatisSqlTester {

        
    // sqlMapClient
        private ExtendedSqlMapClient sqlMapClient;

        
    /**
         * 根據提供的SqlMap ID,得到 {
    @link SqlStatement}對象
         * 
         * 
    @param sqlId: sql map id
         * 
    @return @see {@link SqlStatement}
         
    */
        
    public SqlStatement test(String sqlId) {
            
    //得到MappedStatement對象
            MappedStatement ms = sqlMapClient.getMappedStatement(sqlId);
            
    if (ms == null) {
                
    //TODO:建議封轉自己的異常對象
                throw new RuntimeException("can't find MappedStatement.");
            }

            
    //按照Ibatis代碼,得到Sql和Param信息
            RequestScope request = new RequestScope();
            ms.initRequest(request);
            Sql sql 
    = ms.getSql();
            String sqlValue 
    = sql.getSql(request, null);

            
    //組轉返回對象
            SqlStatement ret = new SqlStatement();
            ret.setSql(sqlValue);
            
    return ret;
        }

        
    /**
         * 根據提供的SqlMap ID和對應的param信息,得到 {
    @link SqlStatement}對象
         * 
         * 
    @param sqlId: sql map id
         * 
    @param param: 參數內容
         * 
    @return @see {@link SqlStatement}
         
    */
        
    public SqlStatement test(String sqlId, Object param) {
            
    //得到MappedStatement對象
            MappedStatement ms = sqlMapClient.getMappedStatement(sqlId);
            
    if (ms == null) {
                
    //TODO:建議封轉自己的異常對象
                throw new RuntimeException("can't find MappedStatement.");
            }

            
    //按照Ibatis代碼,得到Sql和Param信息
            RequestScope request = new RequestScope();
            ms.initRequest(request);
            Sql sql 
    = ms.getSql();
            String sqlValue 
    = sql.getSql(request, param);
            Object[] sqlParam 
    = sql.getParameterMap(request, param).getParameterObjectValues(request, param);

            
    //組轉返回對象
            SqlStatement ret = new SqlStatement();
            ret.setSql(sqlValue);
            ret.setParam(sqlParam);
            
    return ret;
        }

        
    /**
         * 設置SqlMapClient對象
         
    */
        
    public void setSqlMapClient(ExtendedSqlMapClient sqlMapClient) {
            
    this.sqlMapClient = sqlMapClient;
        }

        
    /**
         * <pre>
         * 不推薦使用
         * 推薦使用: {
    @link IbatisSqlTester#setSqlMapClient(ExtendedSqlMapClient)}
         * TODO:請去除這個方法,或者增加初始化的方式
         * </pre>
         * 
         * 
    @param sqlMapConfig sqlMapConfig xml文件
         
    */
        
    public void setSqlMapConfig(String sqlMapConfig) {
            InputStream in 
    = null;
            
    try {
                File file 
    = ResourceUtils.getFile(sqlMapConfig);
                in 
    = new FileInputStream(file);
                
    this.sqlMapClient = (ExtendedSqlMapClient) SqlMapClientBuilder.buildSqlMapClient(in);
            } 
    catch (Exception e) {
                
    throw new RuntimeException("sqlMapConfig init error.", e);
            } 
    finally {
                
    if (in != null) {
                    
    try {
                        in.close();
                    } 
    catch (IOException e) {
                    }
                }
            }
        }

    }


    最后的最后附上所有代碼(通過單元測試代碼,可以看如何使用).歡迎大家的討論.
    sqltester
    builder

    posted @ 2010-08-12 09:03 stone2083 閱讀(3530) | 評論 (9)編輯 收藏

    掃描classpath下類資源

    很早之前,為了簡化配置信息,自己寫了一坨代碼,基于classpath掃描類信息,加載.
    其實,在spring中,已經提供了類似組件(后知后覺了...):

    org.springframework.core.io.support.PathMatchingResourcePatternResolver  資源解析器(基于路徑的正則表達式)
    org.springframework.core.type.classreading.MetadataReader ClassMeta信息解讀器

    于是乎,代碼就非常簡單了:
     1 public class Test {
     2 
     3     /* 資源路徑 */
     4     private static final String                  PATH           = "classpath*:com/alibaba/javalab/t*/**/*.class";
     5     /* 資源解析器 */
     6     private static final ResourcePatternResolver RESOLVER       = new PathMatchingResourcePatternResolver();
     7     /* Meta信息Reader Factory.用于創建MetaReader */
     8     private static final MetadataReaderFactory   READER_FACTORY = new SimpleMetadataReaderFactory();
     9 
    10     public static void main(String[] args) throws Exception {
    11         //根據正則表達式,得到資源列表
    12         Resource[] resources = RESOLVER.getResources(PATH);
    13         for (Resource res : resources) {
    14             //通過 MetadataReader得到ClassMeta信息,打印類名
    15             MetadataReader meta = READER_FACTORY.getMetadataReader(res);
    16             System.out.println(meta.getClassMetadata().getClassName());
    17         }
    18     }
    19 }

    輸出結果:
    com.alibaba.javalab.tool.fetion.protocol.Config
    com.alibaba.javalab.tool.fetion.protocol.Fetion
    com.alibaba.javalab.tool.fetion.protocol.FetionHelper
    com.alibaba.javalab.tool.fetion.protocol.LoginSession
    com.alibaba.javalab.tool.trace.TimeTrace
    ...

    挺好使的一個工具 :)


    posted @ 2010-07-23 14:55 stone2083 閱讀(1189) | 評論 (0)編輯 收藏

    初識InheritableThreadLocal

    一直來只知道ThreadLocal,直到最近看slf4j MDC實現代碼的時候,才認識了InheritableThreadLocal.
    InheritableThreadLocal顧名思義,可繼承的ThreadLocal.
    看類描述:
    This class extends <tt>ThreadLocal</tt> to provide inheritance of values
     * from parent thread to child thread: when a child thread is created, the
     * child receives initial values for all inheritable thread-local variables
     * for which the parent has values.

    測試代碼:
     1 public class Test {
     2 
     3     public static void main(String[] args) {
     4         //使用ThreadLocal,父子線程之間,不共享Value
     5         final ThreadLocal<String> tl = new ThreadLocal<String>();
     6         tl.set("ThreadLocal-VAL");
     7         System.out.println("Main-1:" + tl.get());
     8         new Thread() {
     9             public void run() {
    10                 System.out.println("Child-1:" + tl.get());
    11             };
    12         }.start();
    13 
    14         //使用InheritableThreadLocal,父線程Value可讓子線程共享
    15         final ThreadLocal<String> itl = new InheritableThreadLocal<String>();
    16         itl.set("InheritableThreadLocal-VAL");
    17         System.out.println("Main-2:" + itl.get());
    18         new Thread() {
    19             public void run() {
    20                 System.out.println("Child-2:" + itl.get());
    21             };
    22         }.start();
    23 
    24     }
    25 }

    輸出內容:
    Main-1:ThreadLocal-VAL
    Main-2:InheritableThreadLocal-VAL
    Child-1:null
    Child-2:InheritableThreadLocal-VAL


    ......分隔符號......

    順帶著簡單說下MDC.(Mapped Diagnostic Context). 中文直譯太惡心了,我理解的意思是,和環境相關的上下文信息.
    比如在web應用中,我們可以把用戶的ip,訪問url等放入到這個上下文中,log打印的時候,就能得到這個信息.

    在slf4j BasicMDCAdapter實現中,就是用了InheritableThreadLocal
    1 public class BasicMDCAdapter implements MDCAdapter {
    2 
    3   private InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal();
    4   
    5   //.
    6 
    7 }

    posted @ 2010-07-23 09:17 stone2083 閱讀(2588) | 評論 (0)編輯 收藏

    小談PropertyPlaceholderConfigurer

    背景:讓應用在一個環境下,以多實例的方法運行.
    Log問題,可以通過Log4j占位符實現(見前文:http://www.tkk7.com/stone2083/archive/2010/07/01/324935.html)
    其他Java組件代碼依賴了本地環境資源,怎么解決呢?

    對于使用Spring的組件來說,PropertyPlaceholderConfigurer能幫我們解決這一問題.

    PropertyPlaceholderConfigurer除了支持配置的properties文件外,還支持系統屬性(System.getProperties()).當然,它有三種模式:
     1/** Never check system properties. */
     2public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0;
     3 
     4/**
     5 * Check system properties if not resolvable in the specified properties.
     6 * This is the default.
     7 */
     8public static final int SYSTEM_PROPERTIES_MODE_FALLBACK = 1;
     9 
    10/**
    11 * Check system properties first, before trying the specified properties.
    12 * This allows system properties to override any other property source.
    13 */
    14public static final int SYSTEM_PROPERTIES_MODE_OVERRIDE = 2;

    對于使用本地環境資源的bean來說,只要配置:
     1 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
     2     <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
     3     <property name="locations">
     4         <list>
     5             <value>classpath*:spring/env.properties</value> <!--無需配置node-->
     6         </list>
     7     </property>
     8 </bean>
     9 
    10 <bean id="javaBean" class="com.alibaba.javalab.spring.JavaBean">
    11      <property name="lockFile" value="/home/stone/base/${node}/lock" />
    12 </bean>


    在啟動腳本中,只要加入-Dnode=instanceX即可.

    總結:
    PropertyPlaceholderConfigurer支持properties文件和系統屬性.并且存在三種覆蓋策略.

    posted @ 2010-07-23 08:51 stone2083 閱讀(1277) | 評論 (0)編輯 收藏

    新人破冰問題(挺搞笑,挺惡毒)

    轉自:http://blog.renren.com/blog/226112318/452978694


    1. 初次訪問發生在幾點幾分?
    2. 完全打開首頁花費多少時間?
    3. 是否瀏覽完整個首頁后再去找login入口?
    4. 找login入口花了多少時間?
    5. 是否在服務器提示下找到入口?
    6. 在找到真正login頁面之前,是否誤入后臺login頁面?
    7. 是否使用XX助手找到入口?
    8. 輸錯了幾次密碼后成功登陸?
    9. 在第一次成功登陸的時候,是否使用https(安全連接)?
    10. 登陸之前購買了多少份https證書?
    11. 是否由于服務器帶寬太小導致登入很慢?
    12. 登陸成功后服務器是否發出提示音?
    13. 登陸之后產生了多少PV才最終下單?
    14. 服務器是否在初次下單后給出紅色回執?
    15. 下單之后留在處于登陸狀態幾分鐘才離開?
    16. 整個訪問過程一共產生了幾個session?
    17. 平均session時長是幾分鐘?
    18. 當日訪問的cookie類型是cookie2.2還是3.1?
    19. 當日一共下了多少單?
    20. 在之后的30日內的活躍度類型(5次-18次屬于中度活躍度)


    實踐經驗:
    1. 對于封閉式題目(回答是與否),比較沒勁:問問題的人描述了半天,回答者只回答一個是否者否.對于此類問題,要做改進
    2. 有些問題,都不好意思問出口
    3. 千萬要根據新人的性格,決定是否是否這套模板,切忌切忌

    posted @ 2010-07-23 08:32 stone2083 閱讀(8669) | 評論 (0)編輯 收藏

    Java Exception性能問題

         摘要: 背景: 大學里學java,老師口口聲聲,言之鑿鑿,告誡我們,Java千萬別用異常控制業務流程,只有系統級別的問題,才能使用異常; (當時,我們都不懂為什么不能用異常,只知道老師這么說,我們就這么做,考試才不會錯 :) ) 公司里,有兩派.異常擁護者說,使用業務異常,代碼邏輯更清晰,更OOP;反之者說,使用異常,性能非常糟糕; (當然,我是擁護者) 論壇上,爭論得更多,仁者見仁智者見智,口...  閱讀全文

    posted @ 2010-07-09 14:30 stone2083 閱讀(13746) | 評論 (16)編輯 收藏

    僅列出標題
    共10頁: 上一頁 1 2 3 4 5 6 7 8 9 下一頁 Last 
    主站蜘蛛池模板: 亚洲综合无码AV一区二区| 在线视频免费国产成人| 久久精品国产亚洲麻豆| 国产成人亚洲精品电影| 老司机永久免费网站在线观看| 有色视频在线观看免费高清在线直播 | 亚洲欧洲免费视频| 久久福利青草精品资源站免费| 亚洲偷自拍拍综合网| 337P日本欧洲亚洲大胆精品| 日本不卡在线观看免费v| 亚洲AV成人精品日韩一区| 啦啦啦手机完整免费高清观看| 亚洲综合成人婷婷五月网址| 好爽又高潮了毛片免费下载| 亚洲.国产.欧美一区二区三区| 午夜免费福利在线| 在线精品自拍亚洲第一区| 亚洲AⅤ视频一区二区三区| 国产精品视频全国免费观看 | 欧美三级在线电影免费| 亚洲综合成人婷婷五月网址| 韩国二级毛片免费播放| 男男gay做爽爽免费视频| 91麻豆国产自产在线观看亚洲| 成人黄网站片免费视频| 亚洲视频一区二区三区| 国产一卡二卡3卡四卡免费| 国产精品亚洲专区无码唯爱网| 亚洲国产精品一区二区第四页| 三级黄色在线免费观看| 亚洲福利一区二区精品秒拍| 成年私人影院免费视频网站| 男女交性无遮挡免费视频| 亚洲成AV人片一区二区密柚| 一级女人18毛片免费| 人成电影网在线观看免费| 亚洲高清视频免费| 免费jjzz在在线播放国产| 久久精品视频免费| 亚洲国产精品久久久久秋霞小|