2013年3月16日 星期六

Spring 最輕鬆的完整配置方式

本文目的是要去除所有無謂的宣告,並且將多datasource與交易的設定全都建立起來,aop 的功能也要建立起來。

一般工程師抗拒使用Spring的原因通常只是為了設定很麻煩。如果能直接new 為何要設定半天 ? 不過如果連new 都不用,也不用寫什麼設定檔,不是更好嗎 ?

我看過一些實際專案的Spring的XML,有些團隊好像覺得用了Spring就是了不起的事,但是當專案越來越龐大的時候,過多的xml 絕對是痛苦的來源。真正好的設計是在專案中驗證出來的,一開始的易用,並不代表當需求開始增加時,仍能保持易用性。這個時候就可以看的出來設計上有沒有問題。

以下的配置以Spring 3.2為基礎。

學一個東西先看怎麼用,好用的話再參考。

Action



@Controller
@Scope("prototype")

public class EmeaAction {
@Autowired
EmeaService emeaService;

public String index() {

System.out.println(emeaService.list());
return "success";
}  
}

對一般人來說不清楚的就是紅色的Annotation的部份。先不說細節。

Service


@Service
public class EmeaService {
@Autowired
private QuotationDAO quotationDAO ;

@Transactional(value="quo", readOnly=true)
public List<QuoQuotationMain>  list() {
return quotationDAO.listAll();
}
}


到目前為止應該都還ok吧,Service layer的部份又看到一次 @Autowired,  這很明白的表示,請spring 自動幫我注入這個dao。其它細節也不先說。

DAO


@Repository
public class QuotationDAO { 

@Autowired

private SessionFactory sessionFactory2;

public List<QuoQuotationMain> listAll() {
return sessionFactory2.getCurrentSession().createQuery("from    QuoQuotationMain").list();
}
}


好,程式的部份就這樣子了。應該還算好用吧,如果覺得很難用的話,那就回去原來的世界吧…只是原來的寫法不可能更少,如果原來的Java寫法程式可以這麼少的話,還有誰想要學Spring。先來解釋一下這三層最上面會出現的註示。

@Controller=@Component
@Service =@Component
@Repository=@Component

這算什麼解釋啊 ? 因為這些注釋都是語意而已,其實都是代表 @Component,那@Component是做什麼的,這樣宣告可以讓Spring知道說「喔,這個就是Bean,我會自動幫你們註冊,然後id就和類別一樣吧,只是前一個字要小寫」等於Spring 自動幫你產生xml了,於是乎我們就等同有了三個已註冊的bean 在xml裡了。

@Controller 代表他是MVC 中的C,控制流程為主,下面的scope=prototype就是說每次呼叫都會產生一個新的。不信的話你在方法中去印this,得到的物件其實每次都會不同。

@Service 是中間層的處理方式,也包含了交易的部份,與dao溝通的部份。
@Repository 就是指DAO

對程式設計人員來說,你所要知道的就只要這樣子就好了。就算是Grails來說,寫法也不會再更簡單了,頂多它不用宣告Annotation,以命名方式為主,但是有一點註解其實還是比較好,一看到就知道這個類別負責的功能是哪一塊。

好了,再來你應該會想像有很多的xml要設定。但其實不會,你看上面的程式之後,一定要設定的就是datasource與session factory,這個不可能主動幫你建吧,所以這個要怎麼設定?



<bean id="dataSource1" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/deu"></property>
</bean>
<bean id="dataSource2" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/sap"></property>
</bean>


你的jndi是什麼就自己改吧。


<bean id="sessionFactory1" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="hibernateProperties" value="classpath:hibernate.cfg.xml" />  
<property name="packagesToScan" value="tw.entity.deu" />
</bean>
<bean id="sessionFactory2" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="hibernateProperties" value="classpath:hibernate.cfg.xml" />
<property name="packagesToScan" value="tw.entity.emea" />
</bean>


目前不到20 行,而且這二個東西和db 有關,通常很少再動了。就算dba 逼你連到另一個schema 來存取資料,只要加一個sessionFactory和一個dataSource即可。然後在service layer中,value記得用你取的新名字即可。整個衝擊修改過程不用1分鐘。

packagesToScan 這個好像有一點陌生? 他可是專案膨風後的救星,因為再也不用「多一個表格 就要再去xml宣告一次」了。我一直覺得多一個資料庫表格就要在Spring設定一次真的是很無聊的事,現在你可以叫session factory 去掃那個資料夾就好。專案中多一個表格的衝擊就是 : 打開編輯器,自動從table建出annotation 式的entity後結束。當你一次要弄20幾個table出來一個一個宣告這些無意義的程式時,就知道這個屬性真棒!

好了,那xml 裡還有什麼呢?

還有交易的部份。這個訂xml也不過份啦,而且日後就很少需要改。我把會動到的用粗體標示。


<bean id="transactionManager1" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory1"></property>
<qualifier value='deu'></qualifier>
</bean>
<bean id="transactionManager2" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2"></property>
<qualifier value='quo'></qualifier>
</bean>


交易管理員會以aop 的方式插到service layer去,一個交易管理員對應一個session factory(剛設定過了),一個session factory對應一個datasource(也設定好了),所以交易的部份現在都ready了,專案膨風後也不太需要再做設定。

你說他用aop 的部份,剛剛怎麼看不出來?


Service


@Service
public class EmeaService {
@Autowired
private QuotationDAO quotationDAO ;

@Transactional(value="quo", readOnly=true)
public List<QuoQuotationMain>  list() {
return quotationDAO.listAll();
}
}


@Transactional(value="quo", readOnly=true)這裡就是叫Spring 用aop 的方式在前、後自動補上交易管理,並且使用的是quo 這個交易管理員(transactionManager2啦,上面有)。

這邊全部已經設定完了。在xml 的最上面加上一些tag告訴Spring你要用掃瞄的方式注入。這三行一定要寫。



<context:component-scan base-package="tw"><
/context:component-scan>

<aop:aspectj-autoproxy />
<tx:annotation-driven />


第一行是叫Spring用掃的方式注入。
第二行是啟動aop +annotation來注入 ( 在之前講過不再多提)
第三行是啟動annotation+aop注入交易管理員。

再整理一次。xml 只要寫這三行,以及

  • Datasource
  • Transaction manager
  • Session Factory

之後xml 幾乎就不太需要再更動了。
至於新的Action的話,目前我是用Struts2,改成Spring後再分享一下以Spring 為 MVC 要如何設定。

沒有留言:

張貼留言