09 October 2006

Original System Configuration:

  • Spring 1.2.8
  • Hibernate 3.0.5

Upgrade to:

  • Spring 2.0
  • Hibernate 3.2.0rc4

Lists:

  1. 改變 xml 的 dtd 到 xsd,原來:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
        "http://www.springframework.org/dtd/spring-beans.dtd">
    <beans>
    成:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:util="http://www.springframework.org/schema/util"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd 
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd"
    >
    上面包括 beans/util/aop/tx 等重要的 xsd,其他還有 jee/lang/tool 等不常用的,詳情請見 xsd-config
  2. singleton="true" 要改為 scope="singleton",singleton="false" 要改為 scope="prototype"
  3. <util:foo> 很好用,例如:
    <bean id="configProperties"
    	class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    	<property name="location">
    		<value>classpath:config.properties</value>
    	</property>
    </bean>
    可改為
    <util:properties id="configProperties" location="classpath:config.properties"/>
  4. jdbcTemplate 的 ResultReader 已經正式拿掉了。原本:
    jdbcTemplate.query(sql, new RowMapperResultReader(new MyRowMapper()));
    改寫為:
    jdbcTemplate.query(sql, new MyRowMapper());
  5. Hibernate3 的 count 回傳原本是 Integer,新版變成回傳 Long (改這個真的是太狠了...)
    //原本可以直接 cast 成 Integer:
        Integer count = (Integer) hibernateTemplate.find("select count(...) ... ").get(0);
    
    //新版的則回傳 Long,所以幹脆全改為用 Number
    
        Number countNumber = (Number) hibernateTemplate.find("select count(...) ... ").get(0);
        int count = countNumber.intValue();
  6. 承上,在 hql 直接 new 也受影響:
    //如果直接在 hql 裡 new 物件,遇到了 count/sum... etc)
    
        String hql = " select new Foo(name, count(*)) from ... " 
    
        //該物件的 argument 型別要為 Long
    
        public Foo(String name, Long count) {...}
  7. Hibernate3 的 UserType 原本在 HQL 只能用 string/int... 代入,現在可直接用 原來的 type:
    // MyEnum 經由 UserType 將 enum mapping 為 string
    
    //原本要用 string 代入: 
    
        hibernateTemplate.find(" from myPO where myEnum = ? ", MyEnum.SOMETHING.name() ) ;
    
    //要改為: 
    
        hibernateTemplate.find(" from myPO where myEnum = ? ", MyEnum.SOMETHING ) ;
  8. Hibernate3 interceptor 加了四個 method: onCollectionRecreate()/onCollectionUpdate()/onCollectionRemove()/onPrepareStatement() 。跟其他 method 不一樣的是,String onPrepareStatement(String statement) 預設最少要回傳 argument statement,而不是 null
  9. spring.jar 不再內建 hibernate2 相關的 class,舊系統需要的話要加入 spring-hibernate2.jar
  10. Hibernate3 預設不再偵測 ehcache,需手動設定
    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
       <property name="hibernateProperties">
          <props>
             <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
          </props>
       </property>
    </bean>
  11. 測試用的 MockServletContext 改變尋找路徑的方法。原本測試時我們可以這樣做假的 webApplicationContext
    String[] testPaths = new String[]{
    	   "/com/foo/config/test-applicationConfig*.xml",
    	   "/com/other/foo-applicationConfig*.xml"
    	};
    	XmlWebApplicationContext ctx = new XmlWebApplicationContext();
    	ctx.setConfigLocations(testPaths);
    	ctx.setServletContext(new MockServletContext());
    	ctx.refresh();
    升級後發現 MockServletContext 內部會改(先?) 用 filesystem 的方式去找檔案,當然就掛了... 解決的方法是強制要它走 classpath:
    String[] testPaths = new String[]{
    	   "classpath:/com/foo/config/test-applicationConfig*.xml",
    	   "classpath:/com/other/foo-applicationConfig*.xml"
    	};
    光這個就搞了我兩個小時... 暈倒...
  12. MockHttpSesseion 做 setAttribute/removeAttribute 時,現在會 trigger event 給 HttpSessionBindingListener 了 (越來越像真的...快不能叫 Mock 囉)

感覺升級 hibernate 問題比較多 =_=;。至於那個 aop 新的 transaction 的寫法... 呃,我還是覺得 txProxyTemplate 的寫法比較好... aspectj 的方式對 package/class 名稱的限制太多了 (因為要讓 pointcut wildcard "寫的出來"...)。改天拿便當系統來亂改試試,呵

最後,令人失望的是 Spring 2 沒有像 EJB3 那樣直接寫個 @Stateless 就可以定義一個 bean,還是得在 xml 寫一個 <bean>... 真希望能夠在 class 上加個 @Bean(id="fooService") 就 ok 了。很多 bean 都很簡單,不需要什麼設定,很適合這種寫法說。 Spring 就是死也不走侵略式的做法。可我不 care 被 Spring 侵略啊!下次自己寫一個算了 =_=

[Update] 加兩條和測試有關的。


回響

可以用 Tag <I>、<B>,程式碼請用 <PRE>