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

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

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

    zyskm用夢想丈量人生,用奔跑丈量激情

    #

    How tomcat works閱讀筆記

    這幾天抽空把How tomcat works看了一遍。

    這本書寫得很好,把tomcat這么一個牛B的大家伙拆成一堆零件,然后告訴你怎么組裝,真是做到了掰開了揉碎了講。
    簡單記一下
    第一章講web服務(wù)器,如何接受和響應(yīng)http請求,還舉了個sokcet的例子。算是入門,從很底層的技術(shù)講起。
    第二章講servlet容器,javax.servlet.Servle接口,接受到http請求后如何查找servlet,執(zhí)行servlet。
    第三章講連接器的概念,前兩章看下來你會覺得把http請求接受響應(yīng)跟容器放在一起太亂了,這章就講如何把http操作提出來作為一個連接器。
    第四章講tomcat默認(rèn)連接器,http協(xié)議操作講得很詳細(xì),不過我沒怎么看哈,用的時候直接把tomcat這段代碼拿過來就是了。
    第五章講容器,在第三章的基礎(chǔ)上對容器進(jìn)行分層分類,事情復(fù)雜了就分成幾部分,“治眾如治寡,分?jǐn)?shù)是也”這個我們都知道。
        tomcat講容器分成這幾個概念:
    Engine:表示整個Catalina的servlet引擎
    Host:表示一個擁有數(shù)個上下文的虛擬主機(jī)
    Context:表示一個Web應(yīng)用,一個context包含一個或多個wrapper
    Wrapper:表示一個獨(dú)立的servlet

    類型復(fù)雜了,要做的事情也復(fù)雜了。
    不僅僅是執(zhí)行service()方法,還要前邊執(zhí)行一堆,后邊再來一堆。引入了流水線任務(wù)Pipelining Tasks的概念,在流水線上可以執(zhí)行多個Valve(有翻譯成閥),類似于攔截器的概念。

    第六章講生命周期,人多了要講究個步調(diào)統(tǒng)一,引入了Lifecycle接口的概念,方法包括啟動之前干什么、啟動之后干什么、啟動后把子容器也啟動了。
    包括引入監(jiān)聽接口,都是些java常見實(shí)現(xiàn)方式,沒什么特殊。

    第七章講日志系統(tǒng),沒看。
    第八章講加載器,可以參考tomcat類加載器及jar包沖突問題分析 http://m.tkk7.com/zyskm/archive/2011/12/06/365653.html 就不重復(fù)了。
    第九章講session管理,沒什么特別的。
    第十章講安全,沒看。
    第十一章講StandardWrapper,在第五章的基礎(chǔ)上重點(diǎn)分析了wrapper的運(yùn)作機(jī)制。
    其余章節(jié)目前工作中用不到,有空再看了。

    作者:zyskm
    http://m.tkk7.com/zyskm

    posted @ 2011-12-06 16:25 zyskm 閱讀(3192) | 評論 (7)編輯 收藏

    tomcat類加載器及jar包沖突問題分析

    開發(fā)過程中遇到過這樣一個情況,在本地tomcat下開發(fā)調(diào)試正常,打包到測試環(huán)境的jboss下所有頁面都變成空白頁。
    項(xiàng)目日志和jboss日志沒有一點(diǎn)異常信息,費(fèi)了半天勁把jboss所有日志全部打出來,發(fā)現(xiàn)是el.jar這個包里有空指針調(diào)用。
    檢查一下,項(xiàng)目WEB-INF\lib里有這個包呀,那應(yīng)該是跟什么地方的jar包版本沖突了猜想,繼續(xù)找,在jboss-4.0.5.GA\server\default\lib下找到了對應(yīng)包,比較了一下版本果然版本不一樣。
    把項(xiàng)目下的el-api.jar,jsp-api.jar,servlet-api.jar刪除,重新啟動,問題解決。
    接著有同事提出,同樣在tomcat下開發(fā)也出現(xiàn)這種情況,經(jīng)檢查是他本地tomcat版本跟大家的不一致。開發(fā)環(huán)境這地方?jīng)]做到很好的統(tǒng)一。

    這樣問題是解決了,但是有一點(diǎn)就想不明白了,按照java的類加載委托機(jī)制,推測應(yīng)該是先從jboss-4.0.5.GA\server\default\lib加載,如果加載不到的話再用當(dāng)前類加載器加載WEB-INF\lib下的jar包,所有如果jboss下有jar包WEB-INF\lib下的應(yīng)該不起作用,也有不會有沖突了。
    難到情況不是這樣的?

    一直想著找tomcat源碼分析一下來著,拖了好久。趕上這兩天不忙,就把a(bǔ)pache-tomcat-6.0.33-src源文件弄了一份,debug看看到底怎樣。
    tomcat的類加載器結(jié)構(gòu)和其他java項(xiàng)目是一致的。見圖一


    圖一
    其類圖見圖二

    圖二
    elipse debug截圖倒過來看跟這個就一樣了。
    Tomcat 通過Lifecycle接口來實(shí)現(xiàn)容器生命周期的統(tǒng)一管理,跟類加載器關(guān)系不大,這里就不討論了。
    通過這樣大容器啟動的時候啟動子容器,逐級加載。其結(jié)構(gòu)關(guān)系跟server.xml描述的基本一致,詳細(xì)可以參考我的上一篇文章

    Tomcat6結(jié)構(gòu)分析
    http://m.tkk7.com/zyskm/archive/2011/10/24/361870.html

    (這個編輯工具不太會用,樣式難看點(diǎn),湊合看了)
    每個容器都有自己的類加載器,在默認(rèn)情況下都是StandardClassLoader的實(shí)例。
    委托機(jī)制也和標(biāo)準(zhǔn)的java實(shí)現(xiàn)沒什么兩樣。

    接著往下看項(xiàng)目對應(yīng)的類加載
    StandardContext.start();調(diào)用WebappLoader.start()開始加載項(xiàng)目,WebappLoader又通過創(chuàng)建一個WebappClassLoader實(shí)例進(jìn)行類加載。
    WebappClassLoader.loadClass()實(shí)現(xiàn)依然波瀾不驚,規(guī)規(guī)矩矩的先從緩存找,找不到調(diào)用findClass()進(jìn)行加載。
    果然這里實(shí)現(xiàn)有點(diǎn)不同,是先自己找,找不到再委托上級查找。和java默認(rèn)的加載方式不同。
    見源代碼,只留下原理部分,日志和調(diào)試信息都去掉了。

    public Class findClass(String name) throws ClassNotFoundException {
            
    // 先自己加載類,找不到則請求parent來加載,注意這點(diǎn)和java默認(rèn)的委托模式不同
            Class clazz = null;
            
    try {
                
    if ((clazz == null)) {
                        clazz 
    = findClassInternal(name);
                }

                
    if ((clazz == null&& hasExternalRepositories && !searchExternalFirst) {
                        clazz 
    = super.findClass(name);
                }

                
    if (clazz == null{
                    
    throw new ClassNotFoundException(name);
                }

            }
     catch (ClassNotFoundException e) {
                
    if (log.isTraceEnabled())
                    log.trace(
    "    --> Passing on ClassNotFoundException");
                
    throw e;
            }

            
    return (clazz);
    }

    據(jù)此可以認(rèn)為,在web項(xiàng)目WEB-INF\lib下的jar包優(yōu)先級高于jboss,tomcat 下的lib.
    兩處版本不一致的話會導(dǎo)致程序異常。
    比較省事的辦法是WEB-INF\lib下不再保留重復(fù)的jar包,實(shí)在閑著沒事的話可以自己寫個類加載器替換tomcat下WebappClassLoader改變加載順序。
    但是還可能有隱患,WebappClassLoader權(quán)限較低,它加載的類只能訪問web應(yīng)用下的資源,如果servlet-api.jar等包用到其他資源時可能出現(xiàn)異常。
    這個沒實(shí)際測過,只是推測。但是catalina要提供對整個容器的支持,servlet-api實(shí)現(xiàn)對http協(xié)議的封裝轉(zhuǎn)換用到外部資源的可能性很大。


    圖三 類加載器結(jié)構(gòu)圖

    總結(jié):
    sevlet-api.jar,jsp-api.jar,el-api.jar這類容器提供的jar包web項(xiàng)目下沒必要再保留一份了,容易出現(xiàn)版本不一致。

    附錄:
    查看tomcat源碼的時候可以看看how tomcat works這本書,很不錯,雖然老了點(diǎn)。

    作者:zyskm
    http://m.tkk7.com/zyskm

    posted @ 2011-12-06 13:43 zyskm 閱讀(10716) | 評論 (3)編輯 收藏

    spring聲明性事務(wù)常見問題分析(續(xù))

    上一篇說明了一種spring事務(wù)配置方式,這次補(bǔ)上另一種。
    見配置文件:
    <!-- 事務(wù)攔截 -->
        
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
            
    <tx:attributes>
                
    <tx:method name="get*" propagation="REQUIRED" read-only="true" />
                
    <tx:method name="find*" propagation="REQUIRED" read-only="true" />
                
    <tx:method name="search*" propagation="REQUIRED" read-only="true" />
                
    <tx:method name="save*" propagation="REQUIRED" />
                
    <tx:method name="modify*" propagation="REQUIRED" />
                
    <tx:method name="send*" propagation="REQUIRED" />
                
    <tx:method name="revoke*" propagation="REQUIRED" />
                
    <tx:method name="del*" propagation="REQUIRED" />
                
    <tx:method name="logging*" propagation="NOT_SUPPORTED" read-only="true" />
                
    <tx:method name="*" propagation="SUPPORTS" read-only="true"  />
            
    </tx:attributes>
        
    </tx:advice>
        
    <aop:config>
            
    <aop:pointcut id="projectServiceOperation" expression="execution(* cn.ceopen.bss..*.service..*(..))" />
            
    <aop:advisor pointcut-ref="projectServiceOperation" advice-ref="txAdvice" />
        
    </aop:config>

    重點(diǎn)說明兩點(diǎn):
    1.<aop:pointcut id="projectServiceOperation" expression="execution(* cn.ceopen.bss..*.service..*(..))" />
    表示你要進(jìn)行事務(wù)控制的類名。詳細(xì)資料可以查下 aspectj語法。
    配置完成一定要實(shí)際測試一下,我配置過 expression="execution(* cn.ceopen.bss..*.service.*(..))" 少了一個點(diǎn),導(dǎo)致事務(wù)不起作用。
    導(dǎo)致項(xiàng)目很長一段時間事務(wù)方面沒經(jīng)過嚴(yán)格測試。
    2.
    Spring的AOP事務(wù)管理默認(rèn)是針對unchecked exception回滾。
    也就是默認(rèn)對RuntimeException()異常極其子類進(jìn)行事務(wù)回滾。
    在項(xiàng)目中定義公共的RuntimeException異常,避免每個開發(fā)人員隨意拋出異常。
    不然的話沒新定義一個異常,就要修改tx:method rollback-for 太麻煩了。

    總結(jié):
    1.對事務(wù)配置進(jìn)行檢查,對復(fù)雜嵌套的事務(wù)邏輯必要的時候debug到spring源碼中確認(rèn)。
    2.定義統(tǒng)一異常類型
    3.同一個類調(diào)用自身方法,子方法的事務(wù)配置不起作用。解決方法見上一篇文章。
    http://m.tkk7.com/zyskm/archive/2011/11/11/363535.html

    作者: zyskm
    本文地址:
    http://m.tkk7.com/zyskm/archive/2011/11/30/365225.html

    posted @ 2011-11-30 17:35 zyskm 閱讀(3279) | 評論 (0)編輯 收藏

    客戶端緩存和服務(wù)器端緩存

    在開發(fā)中緩存是經(jīng)常要用到的,什么東西都一遍遍的找數(shù)據(jù)庫問,數(shù)據(jù)庫表示壓力很大。
    緩存方案常見的有兩種,一種是在客戶端,也就是web開發(fā)中的瀏覽器。一種是在服務(wù)器端,以memcached為代表。

    瀏覽器緩存

    這幾天因?yàn)轫?xiàng)目需了解了下瀏覽器緩存相關(guān)的知識。

    重點(diǎn)說一下HTML5 Storage技術(shù),之前的那些技術(shù)都是浮云,存不了什么東西還賊難用,各瀏覽器不兼容。
    聽名字就知道這是這兩年剛出來的技術(shù),相應(yīng)的也就對瀏覽器版本要求比較高,低版本的瀏覽器不支持。對用公司內(nèi)部用的話這個技術(shù)還是很不錯的。
    最多支持5M的容量,是個xml文件,備注:
    Html5 storage最大支持5M容量
    文件位置,根據(jù)系統(tǒng)用戶位置會有區(qū)別。
    C:\Documents and Settings\Administrator\Local Settings\Application Data\Microsoft\Internet Explorer\DOMStore\KF2G0R0O
    也就是說別人都能看到你的數(shù)據(jù),所以不能存放需要保密的內(nèi)容。
    每次用戶登錄的時候最好檢查一下緩存版本是否跟服務(wù)器一致。

    現(xiàn)在的項(xiàng)目中有個業(yè)務(wù)受理環(huán)節(jié),設(shè)置的過程中需要大量使用一些基礎(chǔ)數(shù)據(jù)。類似分公司、部門、產(chǎn)品列表這類數(shù)據(jù),不經(jīng)常變動,反復(fù)到服務(wù)器請求的話對服務(wù)器來講是不小的壓力。
    業(yè)務(wù)受理的步驟很多,得點(diǎn)好幾個下一步才能把操作完成,半截?cái)?shù)據(jù)放到數(shù)據(jù)庫里維護(hù)起來結(jié)構(gòu)就復(fù)雜了。
    因此考慮采用本地緩存技術(shù),比較來比較去HTML5 Storage是不錯的選擇,反正都是公司同事可以要求都使用IE8以上瀏覽器。

    下邊這段是js中用到的代碼

    //用jquery方式,為加載緩存到本地按鈕綁定方法
        $('#loadBtn').bind('click',function(event){
            
    if(supports_html5_storage()){
                localStorage.clear();
                load();
                alert(
    "數(shù)據(jù)已經(jīng)緩存到本地!");
                initCorpSelect();
                initDptSelect(
    "-1");
            }
    else{
                alert(
    "You're out!");
            }

            
        }
    ) ;
        
    //清空緩存
        $('#clearBtn').bind('click',function(event){
            
    if(supports_html5_storage()){
                localStorage.clear();
                alert(
    "本地緩存已經(jīng)清空!");
                initCorpSelect();
                initDptSelect(
    "-1");
            }
    else{
                alert(
    "You're out!");
            }

        }
    ) ;
    //加載緩存到本地瀏覽器
    function load(){
         
    var params = {
            url:
    "${ctx}/crm/product/product/webstorage!ajaxLoad.do"
            type: 
    "post",
            dataType: 
    "json",
            data: 
    null
            success: 
    function(response){
                
    var corps = response.corps;  
                
    var dpts = response.dpts; 
                
    var stations = response.stations; 

                
    for(var i=0;i<corps.length;i++){
                    
    var corp = corps[i];
                    
    var jsCorp = new Corp(corp.corpCode,corp.corpName);
                    localStorage.setItem(
    "corp."+corp.corpCode, jsCorp.toJSONString()); 
                }


                
    for(var i=0;i<dpts.length;i++){
                    
    var dpt = dpts[i];
                    localStorage.setItem(
    "dpt."+dpt.dptCode, dpt.toJSONString()); 
                }


                
    for(var i=0;i<stations.length;i++){
                    
    var station = stations[i];
                    localStorage.setItem(
    "station."+station.stationCode, station.toJSONString()); 
                }

            }

        }
    ;                
        ajax(params);
    }


     

    服務(wù)器緩存

    緩存解決方案很多了,只說剛剛用到的memcached。
    memcached很好用了
    1.安裝啟動memcached
    2.寫一個memcached客戶端工具類,我用的是com.danga.MemCached.MemCachedClient 比較穩(wěn)定,至于其他性能更高的目前沒有需求沒用到。
    3.加載數(shù)據(jù)到memcached
    4.程序中需要基礎(chǔ)數(shù)據(jù)的時候從memcached獲取。

    /**
     * memcached接口
     * 
    @author ce
     *
     
    */

    public interface Imemcached {
        
    /**
         * 可增加,可覆蓋
         
    */

        
    public abstract boolean set(Object key, Object value);
        
    public abstract boolean set(Object key, Object value,Date expire);
        
    /**
         * 只能增加;如果增加的key存在返回“false”
         
    */

        
    public abstract boolean add(Object key, Object value);
        
    public abstract boolean add(Object key, Object value,Date expire);

        
    public abstract boolean delete(Object key);

        
    /**
         * 只能修改;如果修改不存在的key返回“false”
         
    */

        
    public abstract boolean modify(Object key, Object value);

        
    /**
         * 如果key不存在返回null
         
    */

        
    public abstract Object getKey(Object key);

        
    /**
         * 清除服務(wù)器上所有數(shù)據(jù)
         
    */

        
    public abstract boolean flushAll();

        
    /**
         * 判斷服務(wù)器上是否存在key
         
    */

        
    public abstract boolean keyExists(Object key);

        
    /**
         * 一次獲取多個數(shù)據(jù),減少網(wǎng)絡(luò)傳輸時間
         
    */

        
    public abstract Map<String, Object> getKeys(String[] keys);
        
        
        
    /**
         * 設(shè)置是否使用字符串方式
         
    */

        
    public abstract void setPrimitiveAsString(boolean flag);
    }


    實(shí)際測試結(jié)果
    查詢一張人員表,同時需要根據(jù)分公司編號,部門編號從分公司、部門表獲取名稱。
    使用緩存技術(shù)的時候,不管客戶端還是服務(wù)器端,因?yàn)橹徊樵儐伪恚俣让黠@比多表聯(lián)合查詢要快的多。
    在系統(tǒng)使用高峰的時候這種差別明顯能改善用戶的操作體驗(yàn)。
    實(shí)際測試了以下幾種情況:

    1.查詢:
    直接通過表關(guān)聯(lián)的方式進(jìn)行查詢,速度最慢,開發(fā)最簡便
    查詢結(jié)果列表中的公司名稱、部門名稱直接從數(shù)據(jù)庫查出。
    2.查詢(本地緩存),緩存數(shù)據(jù)到本地,清除本地緩存:
    速度最快,數(shù)據(jù)同步有一定工作量,需要高版本瀏覽器支持
    查詢結(jié)果列表中的公司名稱、部門名稱從本地緩存獲取,增加_IE標(biāo)識以區(qū)別。
    3.查詢(服務(wù)器緩存),緩存數(shù)據(jù)到服務(wù)器,清除服務(wù)器緩存:
    速度也很快,也有數(shù)據(jù)同步問題,緩存數(shù)據(jù)到服務(wù)器比本地慢
    查詢結(jié)果列表中的公司名稱、部門名稱從服務(wù)器緩存獲取,增加_mem標(biāo)識以區(qū)別。





    緩存使用總結(jié)

    1.采用緩存技術(shù)后系統(tǒng)性能有明顯改善,可以從性能測試工具明顯感受到(這不是廢話嘛,呵呵)。
    2.緩存的數(shù)據(jù)同步問題必須解決好
    3.項(xiàng)目中采用緩存技術(shù)需要統(tǒng)一規(guī)劃,各系統(tǒng)不能互相干擾。
    4.性能壓力不明顯的情況下,緩存開發(fā)要顯得復(fù)雜一點(diǎn)。


     
    作者: zyskm

    本文地址:
    http://m.tkk7.com/zyskm/archive/2011/11/30/364722.html

     

    posted @ 2011-11-30 16:25 zyskm 閱讀(6715) | 評論 (0)編輯 收藏

    spring聲明性事務(wù)常見問題分析

    聲明性事務(wù)是spring一個很重要的功能,可以避免開發(fā)陷入繁瑣的事務(wù)控制邏輯中。
    但是可能是用著太方便了很多人對spring事務(wù)原理并不清楚,有必要做一番分析。
    下邊以攔截器配置方式進(jìn)行說明,tx標(biāo)簽配置方式將在接下來另一篇文章做分析。
    一、首先看配置文件:
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        
    <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <bean id="matchAllTxInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        
    <property name="transactionManager">
            
    <ref bean="transactionManager" />
        
    </property>
        
    <property name="transactionAttributes">
            
    <props>
                
    <prop key="get*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
                
    <prop key="find*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
                
    <prop key="search*">PROPAGATION_REQUIRED,readOnly,-Exception </prop>
                
    <prop key="save*">PROPAGATION_REQUIRED,-Exception </prop>
                
    <prop key="modify*">PROPAGATION_REQUIRED,-Exception </prop>
                
    <prop key="send*">PROPAGATION_REQUIRED,-Exception </prop>
                
    <prop key="revoke*">PROPAGATION_REQUIRED,-Exception </prop>
                
    <prop key="del*">PROPAGATION_REQUIRED,-Exception </prop>
                
    <prop key="logging*">PROPAGATION_NOT_SUPPORTED,readOnly,-Exception </prop>
                
    <prop key="*">PROPAGATION_SUPPORTS,-Exception </prop>
            
    </props>
        
    </property>
    </bean>
    <bean id="autoProxyCreator"
        class
    ="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        
    <property name="interceptorNames">
            
    <list><idref local="matchAllTxInterceptor" /></list>
        
    </property>
        
    <property name="proxyTargetClass"><value>true</value></property>
        
    <property name="beanNames">
            
    <list><value>*Service</value></list>
        
    </property>
    </bean>

    配置第一步引入AOP代理autoProxyCreator,使用的是spring默認(rèn)的jdk動態(tài)代理BeanNameAutoProxyCreator。
    有兩個屬性要介紹一下:
    1.攔截范圍beanNames;例子中攔截范圍是*Service,表示IOC容器中以Service結(jié)尾的bean,一般配置在spring.xml,serviceContext.xml之類的spring配置文件。
    要注意這里不是值src下邊的類。
    bean配置信息:
    <bean id="menuService" class="cn.ceopen.bss..service.impl.MenuServiceImpl"/>
    有圖有真相,下邊是BeanNameAutoProxyCreator 調(diào)試信息。




    2.截器interceptorNames
    interceptorNames定義事務(wù)屬性和事務(wù)管理器
    配置第二步就是定義事務(wù)屬性:事務(wù)傳播范圍、事務(wù)隔離級別
    事務(wù)屬性沒什么好說的,使用spring進(jìn)行事務(wù)管理的都了解,不在這里詳細(xì)說了網(wǎng)上有大量資料。

    配置第三步,指定事務(wù)管理器
    這里用的是HibernateTransactionManager,spring提供對常見orm的事務(wù)支持。從spring源碼可以看出HibernateTransactionManager.doGetTransaction()同時支持hibernate和jdbc。
    支持hibernate和jdbc混合事務(wù),不使用jta方式的話有個前提條件:使用同一個數(shù)據(jù)源,
    這里所說的同一個數(shù)據(jù)源,不僅僅指物理上是同一個,在spring配置文件中也要是同一個。
    我在開發(fā)中遇到過這個問題,最早定義了一個數(shù)據(jù)baseDataSource,hibernate和jdbc都使用此數(shù)據(jù)源,后來項(xiàng)目要求使用動態(tài)數(shù)據(jù)源就又配了一個數(shù)據(jù)源dynamicDataSource
    僅在hibernate下做了改動,未改動jdbc對應(yīng)配置,出現(xiàn)了事務(wù)控制問題。
    出錯了事務(wù)配置:
    <bean id="sessionFactory"
            class
    ="com.sitechasia.webx.dao.hibernate3.NamedMoudleHbmLocalSessionFactoryBean">
        
    <property name="dataSource" ref="dynamicDataSource" />
        
    <!--與主題無關(guān),省略部分內(nèi)容-->
    </bean>
    <bean id="dynamicDataSource" class="cn.ceopen.bss.pub.base.dao.RoutingDataSource">      
       
    <property name="targetDataSources">      
          
    <map key-type="java.lang.String">      
             
    <entry key="baseDataSource" value-ref="baseDataSource"/>  
          
    </map>      
       
    </property>      
       
    <property name="defaultTargetDataSource" ref="baseDataSource"/>      
    </bean>
     
    <bean id="baseDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        
    <!--與主題無關(guān),省略部分內(nèi)容-->
    </bean>
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 
        
    <!--dataSource應(yīng)該與sessionFactor一致-->
        
    <property name="dataSource"><ref bean="baseDataSource"/></property> 
    </bean> 
    <bean id="abstractJdbcDao" abstract="true">
        
    <property name="jdbc" ref="jdbcTemplate" />
    </bean>
    dao配置文件:
    <bean id="actDao" class="cn.ceopen.bss.impl.ActDaoImpl" parent="abstractJdbcDao"/>
    dao中同時支持hibernate操作和jdbc操作。

    二、事務(wù)屬性傳播
    先看這樣一個列子:

    1.基于jdk動態(tài)代理的AOP事務(wù)控制,只能針對接口。
    在上邊的配置文件中設(shè)置的事務(wù)屬性對a3()都不起作用,a3()不能單獨(dú)設(shè)計(jì)事務(wù)屬性,只能繼承接口方法的事務(wù)屬性。
    2.類自身事務(wù)嵌套
    第一種情況:
    AbcIService abcService;
    BcdIService bcdService;
    abcService.a1();
    abcService.a2();
    bcdService.b1();
    這三個方法對應(yīng)的事務(wù)屬性都起作用。

    第二種情況:
    方法定義
    public void a1() {
      bcdService.b1();
    }
    調(diào)用:
    abcService.a1();
    結(jié)果:
    abcService.a1();
    bcdService.b1();
    這兩個方法對應(yīng)的事務(wù)屬性都起作用。

    第三種情況:
    方法定義
    public void a1() {
      this.a2();
    }
    調(diào)用:
    abcService.a1();
    結(jié)果:
    abcService.a1();
    abcService.a2();
    a2()對應(yīng)的事務(wù)屬性配置不起作用。
    解決辦法:
    1.把a(bǔ)2()拆到另一個類中去;
        缺點(diǎn):麻煩,會把相關(guān)業(yè)務(wù)邏輯拆分了
    2.調(diào)用是不用this.a2(),用abcService.a2();
    public void a1() {
      abcService.a2();
    }
    缺點(diǎn):要在類中注入自身引用。
    原因分析:
    為什么會出現(xiàn)這種情況呢?
    我們在調(diào)用abcService.a1();時abcService是從IOC容器獲取的,并AbcServiceImpl而是它的動態(tài)代理AbcServiceProxy。
    示意圖如下,spring不一定是這么實(shí)現(xiàn)的但原理一樣.



    AbcServiceProxy.a()方法進(jìn)行了AOP增強(qiáng),根據(jù)配置文件中事務(wù)屬性增加了事務(wù)控制。
    public void a1() {
      this.a2();
    }
    this.a2()這里this指的是AbcIServiceImpl并沒用進(jìn)行AOP增強(qiáng),所以沒用應(yīng)用事務(wù)屬性,只能繼承a1()的事務(wù)屬性。
    public void a1() {
      abcService.a2();
    }
    abcService則實(shí)際是AbcServiceProxy.a2()所以可以應(yīng)用事務(wù)屬性。

    所以在類內(nèi)部進(jìn)行方法嵌套調(diào)用,如果被嵌套的方法a2()需要區(qū)別于嵌套方法a1()的事務(wù)屬性,需要:1.在接口公開;2.通過代理調(diào)用。


    作者:zyskm
    http://m.tkk7.com/zyskm

    posted @ 2011-11-11 16:33 zyskm 閱讀(1761) | 評論 (3)編輯 收藏

    <<七步掌握業(yè)務(wù)分析>>閱讀筆記

          上周在西單圖書城看到本不錯的書<<七步掌握業(yè)務(wù)分析>>,系統(tǒng)的講了些業(yè)務(wù)分析方面的知識,以前看到業(yè)務(wù)分析方面的資料都是站在需求捕獲分析的角度來寫,向這么完整系統(tǒng)介紹業(yè)務(wù)分析概念方法的不多。本著書非借不能讀的精神,我用了兩個周末在西單圖書大廈看完了整本書。記錄一下閱讀感受,同時結(jié)合一些自己的理解。
            目錄結(jié)構(gòu)見下圖,大概是這個意思,名詞記得不是很準(zhǔn)確。


            一個個說一下。
            1.什么是業(yè)務(wù)分析
            一般來講"什么是...?"這種問題都可以細(xì)分為這幾個問題,什么是業(yè)務(wù)分析、業(yè)務(wù)分析做什么(工作范圍)、跟系統(tǒng)分析有什么區(qū)別、什么人能做業(yè)務(wù)分析。
            讓大家明白組織是怎么運(yùn)作的,為了實(shí)現(xiàn)組織的目標(biāo)提供解決方案。
            實(shí)際開發(fā)過程中誰都可以做業(yè)務(wù)分析工作,目前很少看到這門業(yè)務(wù)分析師這一角色,一般是需求和系統(tǒng)分析師主要來做。根據(jù)個人能力的不同介入的程度不同。
            說到范圍,業(yè)務(wù)分析主要從業(yè)務(wù)需求的角度來考慮,區(qū)別于系統(tǒng)分析更多的從系統(tǒng)能否實(shí)現(xiàn)、怎么實(shí)現(xiàn)的角度來考慮。很多時候系統(tǒng)分析師是同時兼這兩個角色的,優(yōu)勢是考慮問題有統(tǒng)一方向,缺點(diǎn)的是容易互相干擾。通用的解決思路是顏色帽子法,做哪塊工作時戴那個帽子只想這部分的事情,先不想別的部分怎么辦,先過今天再說明天。每一部分單獨(dú)考慮后再進(jìn)行綜合考慮,這樣工作才好開展,要不然一次想太多了事情就變得太復(fù)雜。
            2.什么人來做
            有人的地方就有江湖,既然在江湖里混就要了解這個江湖是什么人組成的,每個人的立場、對事情的認(rèn)識程度、角色、權(quán)利、影響。對這些人有了認(rèn)識,才能更好的認(rèn)識人做的事情。
    這一點(diǎn)一般的需求書上只是提了一下,不想這本書就組織架構(gòu)、角色關(guān)系、溝通技巧各方面做了闡述。有個理論認(rèn)識實(shí)際操作起來更容易有方向感。
            3.項(xiàng)目做什么
            很多開發(fā)人員經(jīng)常是領(lǐng)導(dǎo)讓做什么就做什么,作為一個業(yè)務(wù)分析師顯然不能這么干。
            業(yè)務(wù)分析師很多時候起的是一個導(dǎo)游的角色,探險(xiǎn)的時候大家全兩眼一抹黑只能掉溝里了。
            誰發(fā)起的項(xiàng)目,項(xiàng)目要達(dá)成什么目標(biāo),對哪些人有益,對哪些人不利。這些都要了解,在項(xiàng)目的過程中才知道從哪方面去推動,避開可能會引起的麻煩。
            4.了解業(yè)務(wù)
            這個是當(dāng)然了,業(yè)務(wù)分析師嘛,具體方法先不寫了,都是寫常見的,重要的是要經(jīng)常實(shí)際總結(jié)提高。
            5.了解業(yè)務(wù)環(huán)境
            這也是一個江湖,更多的是從事情的角度進(jìn)行分類
            6.了解技術(shù)環(huán)境
            業(yè)務(wù)分析雖然不用寫代碼技術(shù)還是要懂一點(diǎn)的,好的服裝設(shè)計(jì)師都會自己做衣服(這可不是隨便說的,我見過幾個,呵呵)。
            7.提升自身價(jià)值
            洞悉事態(tài),能夠提出完整解決方案,這樣的人當(dāng)然是有價(jià)值的。做得越好越有價(jià)值。
            書中提到了幾種提高技能方法:時間管理和一些分析技術(shù),包括溝通技巧。
    先寫這么多。

    作者:zyskm
    http://m.tkk7.com/zyskm

    posted @ 2011-11-02 17:18 zyskm 閱讀(1848) | 評論 (2)編輯 收藏

    基于spring的動態(tài)數(shù)據(jù)源

    基于spring的動態(tài)數(shù)據(jù)源
    項(xiàng)目過程中遇到這樣一個需求,系統(tǒng)啟動后動態(tài)設(shè)置數(shù)據(jù)源,不同用戶登錄系統(tǒng)后訪問的數(shù)據(jù)庫不同。
    好在所有書庫結(jié)構(gòu)一致。
    用spring 的AbstractRoutingDataSource解決了這個問題。
    原理如圖:

    項(xiàng)目采用的是hibernate,直接在spring.xml設(shè)置sessionFactory的dataSource屬性為動態(tài)數(shù)據(jù)源即可。
    因?yàn)轫?xiàng)目所有數(shù)據(jù)庫結(jié)構(gòu)都一致,為了避免每次設(shè)置數(shù)據(jù)源的時候要改一堆參數(shù),修改了spring AbstractRoutingDataSource類增加了一個getTargetDataSources方法,獲取當(dāng)前數(shù)據(jù)源詳細(xì)信息,在其基礎(chǔ)上修改數(shù)據(jù)庫名稱、用戶名、密碼即可,不用每次設(shè)置一堆參數(shù)。
    Map<String,ComboPooledDataSource> targetDataSources=dynamicDataSource.getTargetDataSources();
                    
    if(targetDataSources==null){
                        targetDataSources
    =new HashMap<String, ComboPooledDataSource>();
                        targetDataSources.put(
    "baseDataSource", baseDataSource);
                    }

                    targetDataSources.put(dataSourceName, subSystemDataSource);
                    dynamicDataSource.setTargetDataSources(targetDataSources);
                    dynamicDataSource.afterPropertiesSet();
    另外,設(shè)置AbstractRoutingDataSource參數(shù)后要調(diào)用afterPropertiesSet()方法,spring容器才會進(jìn)行加載操作。

    在動態(tài)設(shè)置數(shù)據(jù)源方面,可以通過兩種方式實(shí)現(xiàn):
    1.在action(項(xiàng)目使用struts)中進(jìn)行設(shè)置,可以確保在每個servlet線程中數(shù)據(jù)源是一致的。
    2.以aop方式,對service方法進(jìn)行攔截,根據(jù)需求設(shè)置不同數(shù)據(jù)源。

    posted @ 2011-10-24 17:11 zyskm 閱讀(3582) | 評論 (2)編輯 收藏

    開發(fā)過程注意事項(xiàng)(數(shù)據(jù)庫方面)

    在開發(fā)過程中數(shù)據(jù)庫的操作和使用要有一定規(guī)范,不然會引起混亂。
    下邊是我們開發(fā)中具體例子,因?yàn)樯婕肮驹谟庙?xiàng)目詳細(xì)代碼就不列出來了,整個思路可供參考。

    1.初始化腳本
    各子系統(tǒng)建立自己的數(shù)據(jù)庫初始化腳本,格式可參照附件產(chǎn)品管理初始化腳本sql.rar(需要解壓到c:/sql才能在命令行執(zhí)行,見init.sql說明)
    包括兩部分內(nèi)容:1.建表語句(ddl);2.基礎(chǔ)數(shù)據(jù)初始化(data)
    建表語句由數(shù)據(jù)庫設(shè)計(jì)文檔(PowerDesigner)導(dǎo)出,基礎(chǔ)數(shù)據(jù)由excel文件導(dǎo)出(sql.rar提供示例,開發(fā)框架提供工具支持DbUtilTest.testExcel2Sql ())
    作用:
    1.數(shù)據(jù)庫結(jié)構(gòu)和基礎(chǔ)數(shù)據(jù)文檔化
    2.便于快速搭建開發(fā)測試環(huán)境,新建一套環(huán)境時不用拷貝原數(shù)據(jù)庫而是執(zhí)行腳本
    3.便于獨(dú)立開發(fā)測試,有一個干凈的數(shù)據(jù),避免開發(fā)測試依賴歷史數(shù)據(jù)和調(diào)試過程中互相影響
    2.數(shù)據(jù)庫結(jié)構(gòu)比對
    在部署多套數(shù)據(jù)庫時,懷疑表結(jié)構(gòu)不一致,可使用DbUtilTest.testCompareDataBase ()進(jìn)行檢查。
    執(zhí)行后會在子系統(tǒng)根目錄生成dbcompare.html 文件,參加附件。
    說明:紅色表示兩個表結(jié)構(gòu)不一致,綠色表示多出一表,黑色表示一致
     
    3.數(shù)據(jù)庫字符集(UTF-8)
    create database dbname CHARACTER SET utf8 COLLATE utf8_bin
    不單獨(dú)對表和字段設(shè)置字符集,整個庫統(tǒng)一使用utf-8
    4.表名字段名
    建庫腳本中表名和字段名不區(qū)分大小寫
    5.數(shù)據(jù)庫引擎(InnoDb)
    目前主要使用的兩種引擎MyIsam,InnoDb。MyIsam查詢較快,不支持事務(wù)。InnoDb支持事務(wù)。
    在建表sql指明引擎。
    create table ***
    (
       id bigint(11) not null auto_increment,
    .........
       primary key (id)
    )
    type = innodb;
    powerdesiner按如下方式設(shè)置:

    posted @ 2011-10-24 16:24 zyskm 閱讀(213) | 評論 (0)編輯 收藏

    集群環(huán)境下log4j日志文件命名方式

        在項(xiàng)目中,通過log4j可以實(shí)現(xiàn)對不同模塊不同級別日志輸出到不同的日志文件中。
    以xml格式為例:
    <appender name="FILE_INFO" class="org.apache.log4j.RollingFileAppender">
        
    <param name="File" value="/usr/local/logs/xxx_info.log"/>
        
    <layout class="org.apache.log4j.PatternLayout">
            
    <param name="ConversionPattern" value="%d %p [%c] [%M]:%L - %m%n"/>
        
    </layout>
        
    <filter class="org.apache.log4j.varia.LevelRangeFilter">
            
    <param name="levelMin" value="INFO" />
            
    <param name="levelMax" value="INFO" />
            
    <param name="AcceptOnMatch" value="true" />
        
    </filter>
    </appender>
    按這種方式在單機(jī)環(huán)境下可以很方便的查詢?nèi)罩尽?br />但是在集群環(huán)境下,因?yàn)轫?xiàng)目同時部署在多個機(jī)器上,log4j生成的日志文件在每臺機(jī)器上都叫xxx_info.log,在開發(fā)維護(hù)的過程中很難區(qū)分那個文件是哪臺服務(wù)上的,尤其在日志查詢比較頻繁的情況下做區(qū)分有一定的工作量。
        為解決這一問題,可以在生成日志文件時增加機(jī)器標(biāo)識。如100_xxx_info.log,標(biāo)識ip為172.20.80.100這臺機(jī)器上的。
    實(shí)現(xiàn)這一功能需要對log4j的Appender做些改動。
    通過查看log4j源碼可以看出來所有的文件輸出都會繼承FileAppender ,修改setFile(String file)方法即可實(shí)現(xiàn)。
    重寫DailyRollingFileAppender,改繼承重寫后的fileappender。
    /** 從配置文件讀取日志文件名 */
        
    public void setFile(String file) {
            String val 
    = file.trim();
            
    int index = val.lastIndexOf('/'+ 1;
            String path 
    = val.substring(0, index);
            String name 
    = val.substring(index);
            fileName 
    = path + getIpSuffix() + "_" + name;
        }


        
    // 獲取本機(jī)ip最后一位(雙網(wǎng)卡內(nèi)網(wǎng)ip)
        private String getIpSuffix() {
            String ip 
    = null;
            String suffix 
    = "";
            NetworkInterface ni;
            
    try {
                ni 
    = NetworkInterface.getByName("eth1");
                
    if (ni == null)
                    ni 
    = NetworkInterface.getByName("eth0");
                Enumeration
    <InetAddress> ias = ni.getInetAddresses();
                
    for (; ias.hasMoreElements();) {
                    InetAddress ia 
    = ias.nextElement();
                    
    if (ia instanceof InetAddress) {
                        ip 
    = ia.getHostAddress();
                    }

                }

                
    if (ip == null{
                    InetAddress addr 
    = InetAddress.getLocalHost();
                    ip 
    = addr.getHostAddress();
                }

            }
     catch (SocketException e1) {
                e1.printStackTrace();
            }
     catch (UnknownHostException e) {
                e.printStackTrace();
            }

            
    if (ip != null{
                
    int index = ip.lastIndexOf('.'+ 1;
                suffix 
    = ip.substring(index);
            }

            
    return suffix;
        }


    posted @ 2011-10-24 15:33 zyskm 閱讀(3422) | 評論 (6)編輯 收藏

    mysql字符集和校對規(guī)則

    字符集的概念大家都清楚,校對規(guī)則很多人不了解,一般數(shù)據(jù)庫開發(fā)中也用不到這個概念,mysql在這方便貌似很先進(jìn),大概介紹一下。
    簡要說明
    字符集和校對規(guī)則
    字符集是一套符號和編碼。校對規(guī)則是在字符集內(nèi)用于比較字符的一套規(guī)則。
    MySql在collation提供較強(qiáng)的支持,oracel在這方面沒查到相應(yīng)的資料。
    不同字符集有不同的校對規(guī)則,命名約定:以其相關(guān)的字符集名開始,通常包括一個語言名,并且以_ci(大小寫不敏感)、_cs(大小寫敏感)或_bin(二元)結(jié)束
    校對規(guī)則一般分為兩類:
    binary collation,二元法,直接比較字符的編碼,可以認(rèn)為是區(qū)分大小寫的,因?yàn)樽址?A'和'a'的編碼顯然不同。
    字符集_語言名,utf8默認(rèn)校對規(guī)則是utf8_general_ci
    mysql字符集和校對規(guī)則有4個級別的默認(rèn)設(shè)置:服務(wù)器級、數(shù)據(jù)庫級、表級和連接級。
    具體來說,我們系統(tǒng)使用的是utf8字符集,如果使用utf8_bin校對規(guī)則執(zhí)行sql查詢時區(qū)分大小寫,使用utf8_general_ci 不區(qū)分大小寫。不要使用utf8_unicode_ci。
    如create database demo CHARACTER SET utf8; 默認(rèn)校對規(guī)則是utf8_general_ci 。
     
    Unicode與UTF8
    Unicode只是一個符號集,它只規(guī)定了符號的二進(jìn)制代碼,卻沒有規(guī)定這個二進(jìn)制代碼應(yīng)該如何存儲.
    UTF8字符集是存儲Unicode數(shù)據(jù)的一種可選方法。 mysql同時支持另一種實(shí)現(xiàn)ucs2。

    詳細(xì)說明

    字符集(charset):是一套符號和編碼。
    校對規(guī)則(collation):是在字符集內(nèi)用于比較字符的一套規(guī)則,比如定義'A'<'B'這樣的關(guān)系的規(guī)則。不同collation可以實(shí)現(xiàn)不同的比較規(guī)則,如'A'='a'在有的規(guī)則中成立,而有的不成立;進(jìn)而說,就是有的規(guī)則區(qū)分大小寫,而有的無視。
    每個字符集有一個或多個校對規(guī)則,并且每個校對規(guī)則只能屬于一個字符集。

    binary collation,二元法,直接比較字符的編碼,可以認(rèn)為是區(qū)分大小寫的,因?yàn)樽址?A'和'a'的編碼顯然不同。除此以外,還有更加復(fù)雜的比較規(guī)則,這些規(guī)則在簡單的二元法之上增加一些額外的規(guī)定,比較就更加復(fù)雜了。
    mysql5.1在字符集和校對規(guī)則的使用比其它大多數(shù)數(shù)據(jù)庫管理系統(tǒng)超前許多,可以在任何級別進(jìn)行使用和設(shè)置,為了有效地使用這些功能,你需要了解哪些字符集和 校對規(guī)則是可用的,怎樣改變默認(rèn)值,以及它們怎樣影響字符操作符和字符串函數(shù)的行為。

    校對規(guī)則一般有這些特征:

     兩個不同的字符集不能有相同的校對規(guī)則。
     每個字符集有一個默認(rèn)校對規(guī)則。例如,utf8默認(rèn)校對規(guī)則是utf8_general_ci。
     存在校對規(guī)則命名約定:它們以其相關(guān)的字符集名開始,通常包括一個語言名,并且以_ci(大小寫不敏感)、_cs(大小寫敏感)或_bin(二元)結(jié)束


    確定默認(rèn)字符集和校對
     字符集和校對規(guī)則有4個級別的默認(rèn)設(shè)置:服務(wù)器級、數(shù)據(jù)庫級、表級和連接級。
     數(shù)據(jù)庫字符集和校對
     每一個數(shù)據(jù)庫有一個數(shù)據(jù)庫字符集和一個數(shù)據(jù)庫校對規(guī)則,它不能夠?yàn)榭铡REATE DATABASE和ALTER DATABASE語句有一個可選的子句來指定數(shù)據(jù)庫字符集和校對規(guī)則:
     例如:
     CREATE DATABASE db_name    DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
     MySQL這樣選擇數(shù)據(jù)庫字符集和數(shù)據(jù)庫校對規(guī)則:
    ·         如果指定了CHARACTER SET X和COLLATE Y,那么采用字符集X和校對規(guī)則Y。
    ·         如果指定了CHARACTER SET X而沒有指定COLLATE Y,那么采用CHARACTER SET X和CHARACTER SET X的默認(rèn)校對規(guī)則。
    ·         否則,采用服務(wù)器字符集和服務(wù)器校對規(guī)則。
    在SQL語句中使用COLLATE
    •使用COLLATE子句,能夠?yàn)橐粋€比較覆蓋任何默認(rèn)校對規(guī)則。COLLATE可以用于多種SQL語句中。
    使用WHERE:
     select * from pro_product where product_code='ABcdefg' collate utf8_general_ci
    Unicode與UTF8
    Unicode只是一個符號集,它只規(guī)定了符號的二進(jìn)制代碼,卻沒有規(guī)定這個二進(jìn)制代碼應(yīng)該如何存儲.Unicode碼可以采用UCS-2格式直接存儲.mysql支持ucs2字符集。
    UTF-8就是在互聯(lián)網(wǎng)上使用最廣的一種unicode的實(shí)現(xiàn)方式。其他實(shí)現(xiàn)方式還包括UTF-16和UTF-32,不過在互聯(lián)網(wǎng)上基本不用。
    UTF8字符集(轉(zhuǎn)換Unicode表示)是存儲Unicode數(shù)據(jù)的一種可選方法。它根據(jù) RFC 3629執(zhí)行。UTF8字符集的思想是不同Unicode字符采用變長字節(jié)序列編碼:
    ·         基本拉丁字母、數(shù)字和標(biāo)點(diǎn)符號使用一個字節(jié)。
    ·         大多數(shù)的歐洲和中東手寫字母適合兩個字節(jié)序列:擴(kuò)展的拉丁字母(包括發(fā)音符號、長音符號、重音符號、低音符號和其它音符)、西里爾字母、希臘語、亞美尼亞語、希伯來語、阿拉伯語、敘利亞語和其它語言。
    ·         韓語、中文和日本象形文字使用三個字節(jié)序列。

    posted @ 2011-10-24 14:59 zyskm 閱讀(1815) | 評論 (3)編輯 收藏

    僅列出標(biāo)題
    共5頁: 上一頁 1 2 3 4 5 下一頁 
    主站蜘蛛池模板: 色偷偷亚洲男人天堂| 久久久久亚洲AV无码麻豆| 99久久国产热无码精品免费| 自拍偷自拍亚洲精品被多人伦好爽| 亚洲av不卡一区二区三区| 亚洲欧美aⅴ在线资源| 日本zzzzwww大片免费| 亚洲国产成人久久综合野外 | 久久精品国产亚洲香蕉| 亚洲一区二区三区播放在线| 最近中文字幕mv免费高清在线| 日韩精品亚洲人成在线观看| 狼群影院在线观看免费观看直播| 国产精品四虎在线观看免费| 噜噜综合亚洲AV中文无码| 蜜臀AV免费一区二区三区| 亚洲不卡中文字幕| 国产精品黄页在线播放免费| 日韩a毛片免费观看| 免费理论片51人人看电影| 亚洲精品国产精品乱码在线观看| 免费av一区二区三区| 亚洲福利在线播放| 午夜网站在线观看免费完整高清观看| 18gay台湾男同亚洲男同| 成人免费淫片在线费观看| 亚洲自偷精品视频自拍| 成年女人毛片免费播放视频m| 美国毛片亚洲社区在线观看 | 亚洲高清国产拍精品熟女| 成人免费的性色视频| 亚洲av片在线观看| 亚洲成av人在线视| 99久久免费精品国产72精品九九 | MM1313亚洲国产精品| 亚洲色精品aⅴ一区区三区| 国产在线观看免费观看不卡| 美女隐私免费视频看| 久久久久亚洲av无码专区喷水| 四虎成人精品一区二区免费网站| 亚洲国产综合精品|