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

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

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

    Dev Zone
    偏執狂才能生存,人生/事業的路上需要再堅持一下
    但是又怎么說得清堅持的結果,道得盡堅持的含義

    2005年5月16日

         發現一個問題,使用struts進行文件上傳,如果有些參數沒有完全定義在ActionForm中,需要從request.getParameter獲取,在表單提交并且validate失敗返回input頁面時,這部分需要從request.getPrameter獲取的參數數據都丟失了,即使再對request進行multipart解析也不能得到。

         經過分析,發現struts的ActionServlet在接收到multipart請求之后,在RequestProcessor中會對request進行封裝:MultiRequestWrapper,然后在Action執行完之后,又將已經封裝的request重新還原。以下是部分代碼,截直RequestProcessor:

    封裝:
        protected HttpServletRequest processMultipart(HttpServletRequest request) {

            
    if (!"POST".equalsIgnoreCase(request.getMethod())) {
                
    return (request);
            }

            
            String contentType 
    = request.getContentType();
            
    if ((contentType != null&&
                contentType.startsWith(
    "multipart/form-data")) {
                
    return (new MultipartRequestWrapper(request));
            }
     else {
                
    return (request);
            }


        }

    還原:
       在doForward和doInclude中在forward和include之前都執行了下面的代碼:
            if (request instanceof MultipartRequestWrapper) {
                request 
    = ((MultipartRequestWrapper) request).getRequest();
            }


         問題就出現在這兒。在經過測試之后,發現request只能進行一次multipart解析,這或許和解析request的時候調用了request.inputStream有關,第一次調用之后再調用就不能獲取其中的有效內容了。因此發現request在調用CommonsMultipartRequestHandler.handleRequest進行解析后并還原后,調用common-upload對request進行解析已經得不到任何得提交內容了,因此當Form驗證失敗,返回input頁面時,即使再進行multpart解析,也不能通過request.getPrameter取到你想要的數據。而此時,表單中的數據卻不會丟失(定義在ActionForm中的表單域),這是因為struts的html系列tag在redisplay時值都是從ActionForm獲取的。

           在將RequestProcessor.doForward和doInclude中還原request的語句注釋后,問題得到了解決。到目前還不清楚為什么struts要還原request,難道是因為chain的原因?

           webwork中應該不會出現這個問題,因為webwork中無論ServletDispatcher還是FilterDispatcher在對request wrap之后都沒有再還原。
    posted @ 2006-03-15 06:10 dev 閱讀(3934) | 評論 (1)編輯 收藏
     
    tomcat、jdk1.4下出現The output format must have a '{http://xml.apache.org/xalan}content-handler' property!的原因:
        這是因為系統、tomcat或者jdk使用了老版本的xalan.jar。系統如果本身沒有使用,而tomcat/common/lib、tomcat/common/endorsed/lib、tomcat/shared/lib下又沒有xalan.jar的話,那就是jdk使用了老版本的xalan.jar——在jre\lib\rt.jar里面。下載最新的xalan.jar然后放到tomcat/common/endorsed下即可解決這一問題。
    posted @ 2006-03-03 19:46 dev 閱讀(1049) | 評論 (1)編輯 收藏
     
    暫時記下,沒想透徹,思考所得、個人見解以后再加入。

    企業發展的4個階段:
  • 產品階段
  • 資產階段
  • 資本階段
  • 品牌階段

    企業管理的4個階段:
  • 人治,嘴上說
  • 法治,建立制度
  • 企業文化
  • 目標管理,充分發揮員工的積極主動型,自我管理
  •  

    posted @ 2006-02-21 02:13 dev 閱讀(748) | 評論 (0)編輯 收藏
     

          blog很好,blogjava暫時感覺也很好,可是為什么不能寫只允許自己看的日志呢?雖說blog就是為了大家能夠分享彼此的觀點感想,但是總有一些東西是不便公開或者暫時不能公開的。如果允許寫只允許自己看的日志,blog的應用范圍就會更大,價值也會被充分挖掘了。
         也可能是我愚昧,對blog了解還不深吧,上述所說的blog也許已經出現了(自己搞一個得了,笑談)。

    posted @ 2006-02-21 02:02 dev 閱讀(247) | 評論 (0)編輯 收藏
     
  • XP
  • SCRUM
    需要并且應該持續關注、思考。

    一些共同點:
  • 快速迭代
  • 持續改進
  • 注重測試
  • 團隊協作
  • posted @ 2006-02-20 02:10 dev 閱讀(199) | 評論 (0)編輯 收藏
     
           很久沒有來這兒了。其實我很喜歡BLOG,可以記下每天工作中的所思所想。我是一個喜歡思考的人,經常有一些想法,有這么一塊地方,能夠把自己的經驗、想法、創造記錄下來,沉積起來,對自己無疑是一種財富。

          不知道是不是有人會寫項目經理日志,我覺得這是一個很好的事情。以前做項目管理的時候只是弄了一個“項目事件”,記錄項目開發過程中發生的、自己覺得是重要的事情,比如某某人進入項目組、離開項目組了,某某模塊版本發布了,發生了什么大的費用等等。寫項目經理日志,或者開發日志、工作日志也行,把自己在工作中、項目開發過程中、項目管理過程中的零零碎碎的想法記錄下來,會是一件很棒的事情。人不應該懶,再累心情再遭也應該堅持寫這種日志。

          或許小筆記本、那種可以隨身攜帶的那種是一件更好的日志記錄工具,可惜容量不夠,而且不能檢索。掌上電腦?寫起來似乎麻煩了,table-pc,好像又太大了,攜帶不方便,可惜,要是手寫識別技術更智能一點、掌上電腦更薄一點,而且可以展開屏幕就棒了。可惜。

     
    posted @ 2006-02-20 01:19 dev 閱讀(188) | 評論 (0)編輯 收藏
     

      JDK1.5出來很久了,一直沒有研究。這倒不是沒有時間,而是覺得J2EE服務器要支持JDK1.5還需要一段時間,而多數客戶還在使用JDK1.4,因此要基于JDK1.5開發Web應用程序還不現實,因此一直沒有去弄這玩意。

      今天由于研究Desktop的開發,裝了1.5,發現1.5中Java程序已經可以獲得本地系統的外觀,我試著不斷的變換了xp的theme,Java程序始終能夠保持和系統的外觀一致;而且以前使用SkinLF后,在web start程序中JOptionPane的窗體經常出不來的問題也解決了。這可是一個非常好的消息。

      另一個好消息是JDK的下一個版本將對Swing/AWT組件進行增強。

      為Java感到高興!

    posted @ 2005-05-17 22:12 dev 閱讀(539) | 評論 (0)編輯 收藏
     

    這里列出一部分Java Desktop的開發資源。

    1。A java.net community for JavaDeskTop

      這是sun主持的資源很全的社區,有很多關于JavaDeskTop開發的資源。

    2。JDIC(Java Desktop Integration Components)

      Sun主持的致力于java和本地應用程序集成、交互的組件集,非常棒。目前有5大組件。

      Desktop

      FileTypes

      Brower

      System Tray Icon

      Packager

    3。JDNC(Java Desktop Network Component)

    4。JExePack

      一個將Java程序轉化為Exe程序的組件。

    5。JSmooth

      作用同JExePack。

    6。JavaService

      一個將Java程序轉化為NT Service的組件。

    7。SKinLF

      非常棒的Java LookAndFeel實現,采用配置包的形式定義Java的LookAndFeel,可以很方便的定義自己的LookAndFeel。它的網站上提供了大量Skin下載,其中不乏精品。

    8。JGoodies

      JGoodies最出名的是它的FormLayout,它使swing和AWT應用程序的布局變得非常簡單。由于它的影響,已經有專門針對它的DESIGNER出現,Eclipse也有相應的插件支持。FormLayout使Java的幾個默認Layout相形見絀。

      JGoodies還有一組Swing/Awt組件,可以很方便的創建Wizard、對話框、Splash窗體、About窗體等GUI部件。

    9。Rachel(Open Source Resource Loading Toolkit for Java Web Start )

      和WebStart打過交道的人可能知道,要在webstart中讀取解析zip或者jar資源是一件非常困難的事,然而有些資源又必須以zip或者jar的形式存在,比如SKinLF就是這樣。Rachel使你不再為這種事情煩惱。它提供兩種解決方案:采用class://的協議裝載URL資源,內嵌一個小型的多線程http server。

    10。JavaHelper(JavaHelp System)

      Sun提供的制作Java Help制作系統。允許你在GUI應用程序、Applet中提供Online Help功能。

    11。Exe4j

      Java 安裝程序制作工具。

    12。JGraph

      非常出名的Java 圖形編輯框架。

    13。GEF(Graphic Edit Framework)

      非常好的圖形編輯框架,雖然沒有JGraph出名,但是我始終覺得它的結構和API都比JGraph好,擴展性非常好。

    14。yworks

      它的YGuard是一個非常棒的混淆器,免費的,功能很強。除了YGuard它還有幾個非常好的組件。

    15。Create GUI with JFC/Swing

      Sun的JFC/Swing編程初學者指南。

    16。Drag and Drop

      Sun的關于在GUI中實現拖放操作的教學文章。

    17。Joshua Marinacci的Blog

      有很多介紹GUI編程的好文章。

    18。CloseAndMaxTabbedPane An enhanced JTabbedPane

      JavaWorld上一篇關于如何在JTabbedPane的Tab上添加Close按鈕、Maximize 按鈕和PopupMenu的文章,有源代碼下載。還可以。

    19。Creating Wizard Dialogs with Java Swing

      Sun上的介紹用Swing創建類似Elipse Wizard對話框的文章。

    posted @ 2005-05-17 22:11 dev 閱讀(1412) | 評論 (0)編輯 收藏
     

      SkinLF(http://www.l2fprod.com/)是一個非常漂亮的Java LookAndFee組件,它的外觀可以配置,由一組小圖片和一個skinlf-themepack.xml構成。SkinLF的網站上提供了很多Skin下載,這里http://www.l2fprod.com/software/skinlf/jnlp/demo.jnlp可以看到SkinLF和這些外觀的演示。可惜的是除了默認的themepack.zip之外,其他外觀(好像有很少幾個除外)都有中文亂碼的問題。其實這是這些外觀使用的字體導致的。

      打開外觀zip文件中的skinlf-themepack.xml,你會發現其他外觀的配置文件比themepack.zip中的配置文件多了一些地方:

      <font name="Global" value="SansSerif,0,11" />
      <font name="InternalFrame.titleFont" value="Trebuchet MS,1,11" />
      <font name="TabbedPane.font" value="Tahoma,0,11" />
      <font name="MenuBar.font" value="Tahoma,0,11" />
      <font name="MenuItem.font" value="Tahoma,0,11" />
      <font name="PopupMenu.font" value="Tahoma,0,11" />
      <font name="Menu.font" value="Tahoma,0,11" />
     把這些注釋掉,然后把配置文件放回到zip文件中就可以了。當然你還可以嘗試采用其他的字體。
     
     采用JGoodies的LookAndFeel出現亂碼,我曾經以為是UTF-8的問題,現在看來可能也是字體導致的。可惜的是,JGoodies的LookAndFeel不能配置。
    posted @ 2005-05-17 22:11 dev 閱讀(869) | 評論 (0)編輯 收藏
     

      下午,試用了SkinLF(http://www.l2fprod.com),感覺非常好,程序的外觀得到了很大的改善,還可以根據自己的需要隨意調整得到自己想要的外觀,但是要將SkinLF應用到Web Start中還有點問題。這是因為,web start使用到的資源必須包裝成jar文件,以的形式定義到jnlp資源文件中,而SkinLF的外觀配置文件是zip形式的。也許有人會說,把zip轉化成jar文件就可以了。是的,想象中這應當是可以的,可是實際情況不是如此,你會發現使用ClassLoader.getResourceStream("themepack.jar")的時候返回了Null,SkinLookAndFeel.loadLookAndFeel()會異常Stream closed.

      調試之后發現,即使是在客戶端,在Eclipse中運行的時候,如果不把themepack.jar定義到ClassPath中,也是無法加載的。

      我想這是一個普遍的問題,根據我的理解,如果其他資源,比如圖片、xml文件、屬性文件等等能夠被加載,themepack.jar也應該被加載。事實上應該是這樣,但是關鍵在于SkinLF需要采用ZipInputStream解析zip(jar)文件,這時情況就不一樣了。具體的原因目前沒有搞清楚。

      在網上找了半天,終于發現一個Open Source的組件:Rachel,使用它很輕易就可以解決上面提到的問題。

      Rachelhttp://rachel.sourceforge.net)是一個為解決Web start裝載資源困難而開發的組件。它提供了兩種方法解決資源裝載問題。

         方法一,使用class://URL Handler。
          這個方法采用新的URL協議:class://從jar文件中獲取資源。

         Step 1,注冊新的URL Handler,以支持class://協議(protocal)。
         例子:java.net.URL.setURLStreamHandlerFactory( new RachelUrlFactory() );

         Step 2,采用class://協議構造URL,從jar文件中讀取資源。
      語法:class:///
      例子:

    class://test.LookAndFeelTest/themepack.zip
    class://com.l2fprod.gui.plaf.skin.SkinLookAndFeel/themepack.zip


      注意:這里,是Rachel用來定義資源文件所在的jar的,后面的相對于jar中的根目錄而言。上述例子中的jar的結構如下:

          test.jar:

          test
    /LookAndFeelTest.class
          com
    /l2fprod/gui/plaf/skin/SkinLookAndFeel.class
          themepack.zip
          images
    /example.png
          html
    /index.htm

      Step 3,采用java.net.URL獲取資源。
          例子:

        URL url = new URL("class://test.LookAndFeelTest/themepack.zip");
        URL url 
    = new URL("class://test.LookAndFeelTest/html/index.html");
        URL url 
    = new URL("class://test.LookAndFeelTest/images/example.png");

        URL url 
    = new URL("class://com.l2fprod.gui.plaf.skin.SkinLookAndFeel/themepack.zip");
        SkinLookAndFeel.setSkin( SkinLookAndFeel.loadThemePack(url) );

      方法二,在程序中嵌入多線程的,小型的http server。

      Step 1,把你的資源放到jar中。

      Step 2,在每一個jar中增加一個anchor class,幫組server定位資源所在的jar文件,這點類似于方法一class:///的的
      例子:

       public class CrossRefAnchor
       {
         
    public CrossRefAnchor() {}
       }

      CrossRefAnchor沒有任何的實際意義,只是為了幫組定義資源所在的jar。

      Step 3,為每一個包含資源的jar用ClassResourceLoader注冊到WebResourceManager。
      例子:

       WebResourceManager roots = WebResourceManager.getInstance();
       roots.addResourceLoader( 
    new ClassResourceLoader( CrossRefAnchor.class ) );
       roots.addResourceLoader( 
    new ClassResourceLoader( JavaDocAnchor.class ) );

      Step 4,啟動Server。
      例子:

       try
       {
         WebServer http 
    = new WebServer( 7272, roots );
         http.start();
       }
       
    catch( IOException e )
       {
         e.printStackTrace();
       }

      Step 5,采用URL從server獲取資源。
      例子:

       URL crossRefUrl = new URL( "http://localhost:7272/crossref/index.html" );
       URL url 
    = new URL( "http://localhost:7272/test.LookAndFeelTest/themepack.zip" );
       URL url 
    = new URL( "http://localhost:7272/test.LookAndFeelTest/html/index.html" );
       URL url 
    = new URL( "http://localhost:7272/test.LookAndFeelTest/images/example.png" );
    posted @ 2005-05-17 22:11 dev 閱讀(1097) | 評論 (4)編輯 收藏
     

    我使用的是GEF0.10(http://gef.tigris.org),在某一個Fig上點擊鼠標右鍵彈出PopupMenu時,發現有閃爍的現象,經過追查發現,一個鼠標右擊動作會分別觸發Editor.mousePressed(e)、mouseReleased(e)、mouseClicked(e)三個事件,這些事件最終都要流經ModeManager,而ModeManager采取的是廣播的方式分發這些事件,把這些事件依次轉發給mode對列中的所有Mode。ModePopup是默認的一個Mode之一,負責提供Fig的彈出菜單功能。而ModePopup中的這三個事件都作了如下的判斷: 

       public void mouseClicked(MouseEvent me) {
            boolean popUpDisplayed 
    = false;
            
    if(me.isPopupTrigger() || me.getModifiers() == InputEvent.BUTTON3_MASK) {
                popUpDisplayed 
    = showPopup(me);
                
    if (LOG.isDebugEnabled()) {
                    
    if (popUpDisplayed) LOG.debug("MousePressed detected as a popup and popup displayed and event consumed");
                    
    else  LOG.debug("MousePressed detected as a popup but no popup to display");
                }
                
    return;
         }
            LOG.debug(
    "MousePressed is not a popup trigger");
        }

     

    其中加紅的這段不知道為什么要作me.getModifiers() == InputEvent.BUTTON3_MASK的判斷,加上這個判斷后只要是鼠標右擊動作,ModePopup的mousePressed、mouseReleased和mouseClicked事件中showPopup的代碼都要被執行,這樣在一個鼠標右擊動作中實際上彈出了三次PopupMenu,因此造成了閃爍。解決辦法是extend默認的ModePopup,覆蓋這三個方法,將判斷改成if ( me.isPopupTrigger())即可。

    posted @ 2005-05-17 22:10 dev 閱讀(625) | 評論 (0)編輯 收藏
     

    今天做了一個測試,發現Hibernate的dynamic-update只在兩種條件下生效:

    1。同一session內,對已經persisit的對象進行update,這里的“已經persist”是指update之前先進行了create或者load調用。代碼示例:

    Session session = openSession();
    User user 
    = (User)session.load(User.class,new Long(12));
    user.setAddress(
    null);
    session.update(user);
    session.flush();

    將hibernate配置成show_sql=true,可以看到update產生的sql語句。

    2。不同session之間,update傳入的對象是另一個session中的persist對象(對該對象調用了create或者load方法)。代碼示例:

    Session session1 = openSession();
    User user 
    = (User)session1.load(User.class,new Long(12));

    Session session2 
    = openSession();
    user.setAddress(
    null);
    session2.merge(user);
    session2.flush();


    如果將session2.merge(..)改成update,則會更新所有可更新的屬性。

    posted @ 2005-05-17 22:10 dev 閱讀(2214) | 評論 (0)編輯 收藏
     

    今天在csdn上看到了一篇介紹PDCA理論在項目管理中應用的blog,很是感慨,想想才到公司的時候老總也給我們做過相關培訓,一年下來,要是沒有看到這篇blog,鐵定是想不起來了。PDCA(計劃、實施、檢察、優化)是一個很好的理論,現摘錄這篇blog的內容如下,以為珍藏。

    以下內容出自:http://blog.csdn.net/wwwxuhong/archive/2004/12/20/222804.aspx 

    項目管理是個很大的課題
    所有的事物都有其規律

    項目管理的規律是什么?
    前幾天看到一個理論讓我眼睛一亮,陳述如下,希望對大家有點啟發

    PDCA循環是由美國統計學家戴明博士提出來的,它反映了質量管理活動的規律。P(Plan)表示計劃;D(Do)表示執行;C(Check)表示檢查;A(Action)表示處理。PDCA循環是提高產品質量,改善企業經營管理的重要方法,是質量保證體系運轉的基本方式。

    項目管理的PDCA環。
    PDCA是指以下四個階段,這四個階段是環環相扣的,這個周期是周而復始的
    P  Plan  計劃
    D  Do    實施
    C Check 檢查
    A Action 總結、再優化

    不管是多大的項目,還是多小的任務,如果都用PDCA環實施,環環相扣,就可以大大提高管理的質量,最大程度地保障項目的成功實施。

    PDCA分以下八上步驟
    計劃階段
        1、分析現狀
        2、找出問題的原因
        3、分析產生問題的原因
        4、找出其中的主要原因
        5、擬訂措施計劃
    實施階段
        6、執行技術組織措施計劃
    檢查階段
        7、把執行結果與預定目標對比
    總結、再優化階段
        8、鞏固成績,進行標準化

    轉貼一篇相關文章
      在企業中,通過眾多小小的變革可能實現對整個企業的持久改善,從而獲得巨大的成效。這在日語中叫做“改善”(kaizen),每一步都很小,這兒一個小變化,那兒一個小改進,但幾年后就能發展出完全不同的產品、工序或服務。
      PDCA循環是由美國統計學家戴明博士提出來的,它反映了質量管理活動的規律。P(Plan)表示計劃;D(Do)表示執行;C(Check)表示檢查;A(Action)表示處理。PDCA循環是提高產品質量,改善企業經營管理的重要方法,是質量保證體系運轉的基本方式。

      PDCA循環的特點PDCA表明了質量管理活動的四個階段,每個階段又分為若干步驟。

      在計劃階段,要通過市場調查、用戶訪問等,摸清用戶對產品質量的要求,確定質量政策、質量目標和質量計劃等。它包括現狀調查、原因分析、確定要因和制定計劃四個步驟。

      在執行階段,要實施上一階段所規定的內容,如根據質量標準進行產品設計、試制、試驗,其中包括計劃執行前的人員培訓。它只有一個步驟:執行計劃。

      在檢查階段,主要是在計劃執行過程之中或執行之后,檢查執行情況,看是否符合計劃的預期結果。該階段也只有一個步驟:效果檢查。

      在處理階段,主要是根據檢查結果,采取相應的措施。鞏固成績,把成功的經驗盡可能納入標準,進行標準化,遺留問題則轉入下一個PDCA循環去解決。它包括兩個步驟:鞏固措施和下一步的打算。

      PDCA循環四階段各步驟。

      1.PDCA循環一定要按順序進行,它靠組織的力量來推動,像車輪一樣向前滾進,周而復始,不斷循環。

      2.企業每個科室、車間、工段、班組,直至個人的工作,均有一個PDCA循環,這樣一層一層地解決問題,而且大環套小環,一環扣一環,小環保大環,推動大循環。

      這里,大環與小環的關系,主要是通過質量計劃指標連接起來,上一級的管理循環是下一級管理循環的根據,下一級的管理循環又是上一級管理循環的組成部分和具體保證。通過各個小循環的不斷轉動,推動上一級循環,以至整個企業循環不停轉動。通過各方面的循環,把企業各項工作有機地組織起來,納入企業質量保證體系,實現總的預定質量目標。因此,PDCA循環的轉動,不是哪一個人的力量,而是組織的力量、集體的力量,是整個企業全體職工推動的結果。

      3.每通過一次PDCA循環,都要進行總結,提出新目標,再進行第二次PDCA循環,使質量管理的車輪滾滾向前。PDCA每循環一次,質量水平和管理水平均提高一步。

      PDCA循環不僅是質量管理活動規律的科學總結,是開展質量管理活動的科學程序,也是一種科學管理的工作方法。它同樣可以在質量管理活動以外發揮重要效用。

      PDCA管理法在營銷中的運用在運用PDCA循環進行市場營銷管理方面,已經有一些優秀企業走在了前頭。

      海爾集團純熟地采用PDCA管理法來實施銷售任務的計劃、組織和控制。每年年終,集團商流、各產品本部根據本年度的銷售額完成情況,結合各產品的發展趨勢及競爭對手分析等信息,制定下一年度的銷售計劃,然后將這一計劃分解至全國11個銷售事業部。銷售事業部長根據各工貿上年的完成情況、市場狀況分析等信息再將銷售額計劃分解至其下屬各工貿公司。工貿公司總經理將任務分解至各區域經理,由他們將任務下達至區域代表,區域代表將自己的銷售額任務分解至其所管轄的營銷網絡。同時,海爾還從時間緯度上進行分解:年度計劃分解至月度,月度計劃分解至每日。這樣,處于管理層的每位管理者都可以對下屬每日的工作狀況進行監督,并及時實施糾偏,最終控制每一個具體網點。海爾集團在新產品開發、新品上市等所有方面都遵循PDCA管理方法。這種做法可以保證“人人都管事,事事有人管”,避免出現管理的真空。

      PDCA管理法運用于每日的事務管理,就形成了獨具海爾特色的OEC日清體系。每人均處于相應的崗位上,每一崗位均有不同的職責,并分配相應的指標,員工的激勵直接與指標掛鉤。指標又可分為主項指標與輔項指標以及臨時任務指標等。每人在當日晚上分析一天的各項任務完成情況,并找出差距原因及糾偏辦法,以使今后的工作質量得到提高,由此構成了持續不斷的改進過程。員工在做完當日總結后,對明日工作做出計劃,然后將OEC日清表交至主管領導處,由主管領導進行審核控制并對下屬的當日工作進行評價和激勵。

      OEC管理法的主要理念,海爾認為是“堅持兩個原則,最大限度地對待兩種人”,即堅持閉環原則,堅持優化原則,最大限度地關心員工的生活,最大限度地滿足用戶的需求。所謂閉環原則,指凡事要善始善終,都必須遵循PDCA循環,而且是螺旋上升。所謂優化原則,指根據木桶理論,找出薄弱項,及時整改,提高全系統的水平。在一個企業的運營過程中,必然存在著許多環節,只要找出制約企業經濟效益提高的某一關鍵環節,把首要矛盾解決了,其他矛盾就可以迎刃而解。

      張瑞敏說,海爾生產線每天要出大大小小幾萬臺家電產品,我們不能考慮出了問題如何處理,而要追求不出任何問題。OEC管理法把質量互變規律作為基本思想,堅持日事日清,積沙成塔,使員工素養、企業素質與管理水平的提高寓于每日工作之中,通過日積月累的管理進步,使生產力諸要素的組合與運行達到合理優化的狀態,不增加投入就可使現實生產力獲得盡可能大的提高,從而令管理收到事半功倍的效果。

      海爾把PDCA運用到企業內部的營銷隊伍管理上,那么,這種管理方法對外部營銷是否適用呢?

      上海通用汽車公司成功地把此方法應用于自己的經銷體系中,極大地改善了經銷商的服務。在其近100家經銷商中,上海通用奉行的政策是,對一些業務表現不好、不能完成上海通用的要求、不能在市場上進行有效的開拓,或者在售后服務方面不能夠完全按照上海通用的理念和規范去操作的經銷商,會先給他們做一個PDCA改進計劃。完成了這個計劃性的四部曲后,經銷商的整個市場營銷的管理工作應該會隨之步入一個良性循環的軌道。如果還是不行,經銷商就會被淘汰掉。

      由上可知,PDCA管理法的核心在于通過持續不斷的改進,使企業的各項事務在有效控制的狀態下向預定目標發展。

    posted @ 2005-05-17 22:09 dev 閱讀(1838) | 評論 (0)編輯 收藏
     

      先前的項目采用的是TyrexFactory作為事務工廠的實現,但是運行的過程中發現很不穩定,處理大對象時容易出現事務超時的錯誤,即使事務設置的超時時間很長也是這樣,將jotm及其相關jar copy 到lib中之后,換成JotmFactory,發現TransactionFactory.getTransactionFactory竟然報NoSuchElementException。后來發現是carol.jar中的CarolConfiguration需要裝載jndi.properties文件進行初始化,而tyrex.jar自身有一個同名的文件,正是因為CoralConfiguration裝載了這個同名的文件才產生了異常,去掉tyrex.jar就可以了。

    posted @ 2005-05-17 22:08 dev 閱讀(448) | 評論 (0)編輯 收藏
     
    Ofbiz2.1有兩個bug,都涉及到線程安全性,小并發的時候不容易發現,大并發下有時候會出現,并發數越高出現的頻度就比較高,尤其對于實體引擎的那個bug,在系統初始化的時候如果遭遇大并發,會有一定頻度的出現。
     
    1。entity engine的ModelEntity.getField方法存在線程安全隱患,會造成 XXXX is not a field of XXX的異常,以下是原有代碼片斷:

        
    public ModelField getField(String fieldName) {
            
    if (fieldName == nullreturn null;
            if (fieldsMap == null) {
                fieldsMap = new HashMap(fields.size());
                for (int i = 0; i < fields.size(); i++) {
                    ModelField field = (ModelField) fields.get(i);
                    fieldsMap.put(field.name, field);
            }
            return (ModelField) fieldsMap.get(fieldName);
        }

    由于getField方法沒有同步(會造成性能下降),因此紅色標標注的那段代碼存在線程安全問題,必須進行同步。在大并發下如果多個調用這個方法,最先調用的線程沒有執行完循環的情況下,后續的線程通過最后的語句return的時候得到的就是Null(fieldsMap已經被第一個線程賦值了,后續線程不會進入紅色標準的代碼區域)。
    修改后的代碼如下:
       public ModelField getField(String fieldName) {
            
    if (fieldName == nullreturn null;
            
    if (fieldsMap == null) {
                 createFields();
            }
            
    return (ModelField) fieldsMap.get(fieldName);
        }

        
    public synchronized void createFields()
        {
                 fieldsMap 
    = new HashMap(fields.size());
     
                 
    for (int i = 0; i < fields.size(); i++) {
                     ModelField field 
    = (ModelField) fields.get(i);
     
                     fieldsMap.put(field.name, field);
                 }
        }
     
    這個Bug在3.0中已經被修正。
     
    2。UtilCache.get方法同樣存在線程安全隱患,會造成LinkedList.remove或者LinedList.addFirst的空值針異常,不注意還會以為是LinkedList的bug。以下是原代碼片斷:
        public Object get(Object key) {
            
    if (key == null) {
                missCount
    ++;
                
    return null;
            }
            UtilCache.CacheLine line 
    = (UtilCache.CacheLine) cacheLineTable.get(key);
            
    if (hasExpired(line)) {
                
    // note that print.info in debug.properties cannot be checked through UtilProperties here, it would cause infinite recursion
                
    // if (Debug.infoOn()) Debug.logInfo("Element has expired with key " + key);
                remove(key);
                line 
    = null;
            }
            
    if (line == null) {
                
    // if (Debug.infoOn()) Debug.logInfo("Element not found with key " + key);
                missCount++;
                
    return null;
            }
            
    // if (Debug.infoOn()) Debug.logInfo("Element found with key " + key);
            hitCount++;
            if (maxSize > 0) {
                keyLRUList.remove(key);
                keyLRUList.addFirst(key);
            }

            return line.getValue();
        }
    紅色標準的部分是有問題的代碼,修改后的代碼如下:
        public Object get(Object key) {
            
    if (key == null) {
                missCount
    ++;
                
    return null;
            }
            UtilCache.CacheLine line 
    = (UtilCache.CacheLine) cacheLineTable.get(key);
            
    if (hasExpired(line)) {
                
    // note that print.info in debug.properties cannot be checked through UtilProperties here, it would cause infinite recursion
                
    // if (Debug.infoOn()) Debug.logInfo("Element has expired with key " + key);
                remove(key);
                line 
    = null;
            }
            
    if (line == null) {
                
    // if (Debug.infoOn()) Debug.logInfo("Element not found with key " + key);
                missCount++;
                
    return null;
            }
            
    // if (Debug.infoOn()) Debug.logInfo("Element found with key " + key);
            hitCount++;
            
    if (maxSize > 0) {
                synchronized ( 
    this)
                {
                     keyLRUList.remove(key);
                     keyLRUList.addFirst(key);
                }
            }
            
    return line.getValue();
        }

    這個BUG在3.0種也修正了。
    posted @ 2005-05-17 22:07 dev 閱讀(313) | 評論 (0)編輯 收藏
     
    1。XAPool是如何wrap jdbc driver返回的PreparedStatement的。
    以下是StandardConnectionHandler中的checkPreparedCache代碼片斷
    ????synchronized?PreparedStatement?checkPreparedCache(
    ????????String?sql,
    ????????
    int?type,
    ????????
    int?concurrency)
    ????????throws?SQLException?{
    ????????log.debug(
    ????????????
    "StandardConnectionHandle:checkPreparedCache?sql='"?+?sql?+?"'");
    ????????PreparedStatement?ret?
    =?null;?//?the?return?value
    ????????
    //?NOTE?-?We?include?the?Connection?in?the?lookup?key.?This?has?no
    ????????
    //?effect?here?but?is?needed?by?StandardXAConnection?where?the?the?physical
    ????????
    //?Connection?used?can?vary?over?time?depending?on?the?global?transaction.
    ????????String?lookupKey?=?sql?+?type?+?concurrency;
    ????????
    //?used?to?lookup?statements
    ????????if?(preparedStatementCache?!=?null)?{
    ????????????Object?obj?
    =?preparedStatementCache.get(lookupKey);
    ????????????
    //?see?if?there's?a?PreparedStatement?already
    ????????????if?(obj?!=?null)?{?//?if?there?is
    ????????????????ret?=?(PreparedStatement)?obj;?//?use?as?return?value
    ????????????????try?{
    ????????????????????ret.clearParameters();?
    //?make?it?look?like?new
    ????????????????}?catch?(SQLException?e)?{
    ????????????????????
    //?Bad?statement,?so?we?have?to?create?a?new?one
    ????????????????????ret?=?createPreparedStatement(sql,?type,?concurrency);
    ????????????????}

    ????????????????preparedStatementCache.remove(lookupKey);
    ????????????????
    //?make?sure?it?cannot?be?re-used
    ????????????????inUse.put(lookupKey,?ret);
    ????????????????
    //?make?sure?it?gets?reused?by?later?delegates
    ????????????}?else?{?//?no?PreparedStatement?ready
    ????????????????ret?=?createPreparedStatement(sql,?type,?concurrency);
    ????????????????inUse.put(lookupKey,?ret);
    ????????????????
    //?will?get?saved?in?prepared?statement?cache
    ????????????}
    ????????}?
    else?{
    ????????????ret?
    =?createPreparedStatement(sql,?type,?concurrency);
    ????????}
    ????????
    //?We?don't?actually?give?the?application?a?real?PreparedStatement.?Instead
    ????????
    //?they?get?a?StandardPreparedStatement?that?delegates?everything?except
    ????????
    //?PreparedStatement.close();

    ????????ret?
    =?new?StandardPreparedStatement(this,?ret,?lookupKey);
    ????????
    return?ret;
    ????}

    2。StandardPreparedStatement的Close方法代碼片斷
    ????public?void?close()?throws?SQLException?{
    ????????
    //?Note?no?check?for?already?closed?-?some?servers?make?mistakes
    ????????closed?=?true;
    ????????
    if?(con.preparedStmtCacheSize?==?0)?{
    ????????????
    //?no?cache,?so?we?just?close
    ????????????if?(ps?!=?null)?{
    ????????????????ps.close();
    ????????????}
    ????????}?
    else?{
    ????????????con.returnToCache(key);
    ????????????
    //?return?the?underlying?statement?to?the?cache
    ????????}
    ????}

    3。xapool StandardPoolDataSource的getConnection 原理:
    ???? StandardPoolDataSource.getConnection --> GenericPool.checkOut-->StandardPoolDataSource.create -->StandardPoolDataSource.getPooledConnection:返回StandardPooledConnection。
    ?
    ???? StandardPooledConnection通過StandardDataSource.getConnection獲取jdbc driver返回的connection(physical connection),然后通過工廠方法newConnectionHandle采用StandardConnectionHandler對該connection進行包裝。StandardConnectionHandler對PreparedStatement進行重新包裝和Cache,對connection.close進行了控制。
    ?
    4。xapool StandardXAPoolDataSource的getConnection的原理:
    ?? StandardXAPoolDataSource.getConnection -->StandardPoolDataSource.getConnection-->StandardXAPoolDataSource.create -->XADataSource.getXAConnection -->StandardXADatasource.getXAConnection:返回StandardXAConnection。
    ??? StandardXAConnection通過StandardDataSource.getConnection獲取jdbc driver返回的connection(physical connection),然后通過工廠方法newConnectionHandle采用StandardXAConnectionHandle對該connection進行包裝。StandardXAConnectionHandler繼承自StandardConnectionHandler。
    ?
    5。xapool從StandardPoolDataSource獲取的 Connection的關閉原理。
    ?? StandardPooledConnection.close-->StandardConnectionHandler.close(設置closed=true,回收PreparedStatement)-->StandardPooledConnection.closeEvent-->StandardPoolDataSource.connectionClosed-->GenericPool.checkIn(返回連接池)
    ?
    6.xapool中對連接池進行管理的類是GenericPool,該類的checkOut和checkIn方法分別完成連接獲取和連接回收功能。checkOut從unlocked池中獲取可用的連接,如果需要進行檢查或者測試,然后返回;如果發現unlocked池中沒有連接,在連接數小于maxSize的時候調用PoolHelper的實現類創建連接,如果連接數已經達到或者超過maxSize,調用wait使當前進程進入等待狀態(等待期限和等待間隔可以設置),如果等待過程中其他線程釋放了connection返回可用的connection,否則異常:GenericPool:checkOut ERROR? impossible to obtain a new object from the pool
    posted @ 2005-05-17 22:07 dev 閱讀(1814) | 評論 (0)編輯 收藏
     
    1. sleepTime:PoolKeeper檢測時間間隔
    2. lifeTime:連接生命周期(上次訪問時間-當前時間)
    3. deadLockMaxWait(:超過最大連接之后的調用getConnection的等待時間
    4. deadLockRetryWait:超過最大連接之后的調用getConnection等待,在等待中重試的時間間隔
    5. maxSize:連接池的容量

    deald-lock-max-wait和dead-lock-retry-wait的設置要小心,這兩個參數的意義見我的另一個日志:XAPool原理簡要分析。dead-lock-retry-wait最好設置得比較短,這樣不至于線程等待很長時間,dead-lock-max-wait的設置不要太長,一般是設置成比最高并發數下應用處理時間稍長一點,設置過短在大并發下會造成提交實效導致應用數據的丟失,因為超過xapool在超過等待dead-lock-max-wait之后會異常:沒有可用連接分配。

     

    sleepTime是對Connection idle檢測線程PoolKeeper的檢測時間間隔設置。PoolKeeper會定時監測是否存在超過lifeTime的connection然后釋放掉這些connection。不過PoolKeeper在運行的時候會檢查running屬性,以下是它的run方法中的代碼片斷:

      while (! running && !Thread.interrupted()) {
          System.err.println(
    "!!!!"+System.currentTimeMillis());
       
    try {
        synchronized (
    this) {
         wait(
    this.sleepTime); // wait for timeout ms before attack
        }
       } 
    catch (InterruptedException e) {
                                    
    break;
       }
       
    this.pool.cleanUp(); // clean up the Pool and reallocate objects
      }
      
    // release the pool.
      this.pool = null;

    之所以把這段代碼粘出來,是因為running屬性默認是true,而GenericPool在啟動PookKeeper的時候并沒有改變這個值,因此PookKeeper永遠不會運行起來。也許這是xapool的另一個bug:)

    連接池的容量設置是有講究的,一般至少等于AppServer(或者叫WEB 容器)的最大并發數。因為xapool在達到maxSize的時候,如果還有線程需要連接,會進入等待狀態(通過deadLockMaxWait設置最大等待時間,deadLockRetryWait設置等待間隔),在大并發下會造成App Server容器線程池滿,Server在一段時間內(deadLockMaxWait)停止響應的現象。將連接池的容量設置成大于App Server的最大并發數,可以盡可能的避免這種情況。App Server的最大并發數=App Server的線程池線程數,Tomcat默認是75,Websphere默認是50。集群環境下,集群的最大并發數=每臺集群服務器的最大并發數之和

    posted @ 2005-05-17 22:06 dev 閱讀(2397) | 評論 (1)編輯 收藏
     
    現狀:我們的項目中使用了ofbiz2.1,并采用JotmFactory作為TransactionFactory,使用Oracle9i數據庫,在大并發測試的時候發現數據庫游標暴漲并且不釋放,最終導致游標溢出。
     
    原因分析:ofbiz  entityengine的很多操作都是使用PreparedStatement完成的,這無可厚非,問題是JotmFactory采用的是XAPool作為連接池,而XAPool對PreparedStatement進行了Cache,同時Oracle有一個出名的內存漏洞,PreparedStatement使用之后必須關閉,如果不關閉連續進行SQL查詢會造成前面SQL的游標不能釋放;此外JotmConnectionFactory沒有允許對XAPool做更多的配置,按照它使用XAPool的方式,XAPool會對PreparedStatement進行Cache。Oracle漏洞+ofbiz的不周全的使用方式+xapool的機制造成了游標不釋放最終溢出的異常。
     
     
    解決辦法:修改JotmConnectionFactory,調用StandardXAPoolDataSource的setPreparedStmtCacheSize(int)的方法,將preparedStmtCacheSize設置為0。需要注意的是xapool在目前的版本(1.4)當preparedStmtCacheSize=0的時候存在一個bug,close PreparedStatement的時候會報NullPointerException,請參考我的另一個日志XAPool1.4的bug
     
    posted @ 2005-05-17 22:06 dev 閱讀(561) | 評論 (0)編輯 收藏
     
    現狀:XAPool1.4有一個bug,當設置preparedStmtCacheSize=0的時候,關閉連接會拋出NullPointerException
     
    原因:StandardConnectionHandle在Close的時候調用了preparedStatementCache.cleanupAll(),沒有進行判斷;而當preparedStmtCacheSize設置為0的時候,StandardConnectionHandle在setupPreparedStatementCache中把preparedStatementCache設置為null,以下setupPreparedStatementCache是方法中的源代碼片斷:
     
     protected void setupPreparedStatementCache() {
      log.debug(
    "StandardConnectionHandle:setupPreparedStatementCache start");
      
    if (preparedStmtCacheSize == 0) {
       log.debug(
        
    "StandardConnectionHandle:setupPreparedStatementCache return with 0");
       preparedStatementCache 
    = null;
       
    return;
      }
     
    解決辦法:修改setupPreparedStatementCache,如下:
      if (preparedStmtCacheSize == 0) {
       log.debug(
        
    "StandardConnectionHandle:setupPreparedStatementCache return with 0");
    //   preparedStatementCache = null;
       preparedStatementCache = new PreparedStatementCache(0);
       
    return;
      }
    posted @ 2005-05-17 22:05 dev 閱讀(249) | 評論 (0)編輯 收藏
     
    現狀:在我們的項目中使用了Ofbiz2.1,TransactionFactory配置為JotmFactory,數據庫是Oracle9i,lifeTime設置為120000(2分鐘)在大并發測試的時候發現經常Closed Connection的異常。
     
    原因:Oracle數據庫會檢查physical connection的idle時間和使用次數并關閉長時間idle的physical connection,如果應用對從連接池中
    獲取的connection不進行檢查,或者連接池仔返回可用連接之前不進行檢查,在使用過程中就會Closed Connection的異常。大多數數據庫都會檢查physical connection的idle時間。
     
    解決辦法:調用StandardPoolDataSource或者StandardXAPoolDataSource的setCheckLevelObject(int)方法設置連接檢查級別,參數取值如下:
    1. 0:不檢查
    2. 1:對unlocked池中獲取的連接進行Closed檢查
    3. 2:對unlocked池中獲取的連接進行sql測試,需要設置setJdbcTestStmt(Test SQL)
    4. 3:對所有unlocked池中的連接進行Closed檢查
    5. 4:對所有unloked池中的連接進行測試,需要設置setJdbcTestStmt(Test SQL)
     
     
    posted @ 2005-05-17 22:04 dev 閱讀(1134) | 評論 (0)編輯 收藏
     

    打算將我在http://jdev.blogdriver.com 的blog搬過來。

    posted @ 2005-05-16 23:56 dev 閱讀(142) | 評論 (0)編輯 收藏
     
    主站蜘蛛池模板: 日日摸夜夜添夜夜免费视频 | 曰批全过程免费视频在线观看| 国产亚洲精久久久久久无码77777| 国产偷国产偷亚洲清高APP| 国产美女无遮挡免费视频网站 | 国内精品乱码卡1卡2卡3免费 | 亚洲日本在线电影| 午夜男人一级毛片免费| 亚洲成av人片在线天堂无| 午夜国产羞羞视频免费网站| 美女扒开屁股让男人桶爽免费 | 国产成人免费a在线视频app| 免费国产黄网站在线看| 久久精品国产亚洲7777| 国产免费AV片在线观看| 亚洲精品国产肉丝袜久久| 最近中文字幕mv免费高清电影 | 亚洲欧美第一成人网站7777| 日本媚薬痉挛在线观看免费| 老司机午夜免费视频| 亚洲一区二区三区AV无码| 免费国产午夜高清在线视频| 亚洲黄色免费网址| 午夜a级成人免费毛片| 特级做a爰片毛片免费看| 亚洲国产精品一区第二页| 成人免费观看一区二区| 在线观看亚洲免费| 国产自偷亚洲精品页65页| 亚洲免费中文字幕| 特a级免费高清黄色片| 亚洲一区二区三区夜色| 永久免费观看的毛片的网站| 久久精品无码专区免费| 亚洲国产成人91精品| 亚洲日本在线观看视频| 免费三级毛片电影片| av午夜福利一片免费看久久| 亚洲国产日韩在线一区| 亚洲色一色噜一噜噜噜| 台湾一级毛片永久免费|