Spring in Action 學習筆記—第七章訪問企業服務
來源:互聯網
上載者:User
Spring in Action
學習筆記
—
第七章
訪問企業服務
本章向讀者展示了在Spring中如何整合其他企業服務,讀者將瞭解到使用Spring整合郵件服務、JMS甚至EJB都是那麼的容易。 Spring並沒有對一些企業服務提供直接的支援。它依賴其他API來提供有關服務,但對這些服務通過相應的抽象層進行了封裝,因此使用起來更為方便。
一、從
JNDI
中擷取對象 JNDI為Java應用程式提供了一個用於儲存應用對象的中心倉庫。 Spring的JNDI抽象使你可以在應用的設定檔中聲明JNDI對象。然後你就可以將這些對象裝配到其他Bean的屬性中,就如同JNDI對象與其他的POJO一樣。
1
.使用傳統的
JNDI 使用傳統的JNDI API,你編寫的代碼也許和下面的看上去差不多: InitialContext ctx =
null;
try { ctx =
new InitialContext(); DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/myDatasource"); }
catch (NamingException ne) { //exception }
finally {
if (ctx !=
null) {
try { ctx.close(); }
catch (NamingException ne) {} } } 這段代碼有點笨拙,總的說來,這種從JNDI中擷取對象的傳統方式的問題都來源於違背了依賴注入的原則。不是賦給你的代碼一個對象,而是你的代碼必須親自去擷取這個對象。這意味著你的代碼所做的不是真正的工作。這也意味著你的代碼不必要地與JNDI耦合了。
2
.代理
JNDI
對象 Spring的JndiObjectFactoryBean允許你同時得到這兩個不同領域中的好處。它是一個工廠Bean,這意味著當把它裝配到一個屬性上時,實際上它會建立一個其他類型的對象供裝配時使用。對於JndiObjectFactoryBean,它實際裝配的是一個從JNDI擷取的對象。 當Spring裝配sessionFactory Bean時,它會把從JNDI中擷取的DataSource對象注入到會話工廠Bean的dataSource屬性中。使用JndiObjectFactoryBean從JNDI中尋找對象的最大優勢在於惟一知道DataSource是從JNDI中擷取的代碼就是那段dataSource Bean的XML聲明。sessionFactory Bean不知道(也不關心)DataSource來自哪裡。這意味著如果以後你決定改從一個JDBC驅動管理器擷取DataSource,只需要重新定義dataSource Bean為一個DriverManagerDataSource即可。
二、寄送電子郵件 Spring中的郵件發送器由Spring的MailSender介面定義。郵件發送器抽象了某個特定的郵件實現。這樣就使應用代碼和實際使用的郵件實現之間沒有耦合。Spring提供了這個介面的兩個實現: CosMailSenderImpl——以Jason Hunter的Java Servlet Programming一書(O’Reilly,1998)中的COS(com.oreilly.servlet)實現為基礎的SMTP郵件發送器的簡單實現。 JavaMailSenderImpl——一個基於JavaMail API的郵件發送器實現。允許發送MIME郵件以及非SMTP郵件(比如Lotus Notes)。 採用哪個都將完成發送的工作,但是我們將選擇JavaMailSenderImpl,因為在兩者間它的功能更全面。你可以在Spring設定檔中按以下方式聲明它: <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host"> <value>mail.springtraining.com</value> </property> </bean> 屬性host指定了郵件伺服器的主機名稱,在這裡是Spring培訓應用的SMTP伺服器。在預設情況下,郵件發送器假設SMTP伺服器監聽25連接埠(標準的SMTP連接埠),但如果你的SMTP伺服器監聽在不同的連接埠上,可以使用JavaMailSenderImpl的port屬性來指定連接埠。 上面的mailSender聲明中顯式地命名了用於發送郵件的郵件伺服器。然而,如果你有一個位於JNDI中的javax.mail.MailSession對象(可能位於你的應用伺服器中),則也可以選擇從JNDI中擷取它。只需簡單地使用JndiObjectFactoryBean(如第7.1節中描述的)來擷取郵件會話對象,並按照下面的方式將它裝配到mailSender的mailSession屬性中即可: <bean id="mailSession" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName"> <value>java:comp/env/mail/Session</value> </property> </bean> <bean id="mailSender" class="org.springrframework.mail.javamail.JavaMailSenderImpl"> <property name="session"><ref bean="mailSession"/></property> </bean>
三、調度任務 Java的Timer類和OpenSymphony的Quartz調度器 [2] 是兩個流行的調度API。Spring為這兩個調度器提供了一個抽象層,使你可以更容易地使用它們。
1
.使用
Java Timer
調度任務 從Java 1.3開始,Java SDK就通過java.util.Timer類提供了基本的調度功能。這個類允許你調度一個任務(通過java.util.TimerTask子類定義)按任意周期運行。 建立一個定時器任務 使用Java Timer來調度發送註冊報表郵件的第一步是從java.util.TimerTask中派生出郵件任務:
public
class EmailReportTask
extends TimerTask {
public EmailReportTask() {}
public
void run() { courseService.sendCourseEnrollmentReport(); }
private CourseService courseService;
public
void setCourseService(CourseService courseService) {
this.courseService = courseService; } } run()方法定義了當任務運行時該做什麼。在上面的例子中,它調用CourseService的sendCourseEnrollmentReport()方法來發送註冊報表郵件。CourseService是通過依賴注入方式提供給EmailReportTask的。 按以下方式在Spring設定檔中聲明EmailReportTask: <bean id="reportTimerTask" class="com.springinaction.training.schedule.EmailReportTask"> <property name="courseService"> <ref bean="courseService"/> </property> </bean> 這個聲明本身只是將EmailReportTask放到應用上下文中,並在courseService屬性中裝配courseService Bean。在你調度它之前,它不會做任何有用的事。 調度定時器任務 Spring的ScheduledTimerTask定義了一個定時器任務的運行周期。既然課程主任要求每天向她發送註冊報表,你應該以如下方式裝配一個ScheduledTimerTask: <bean id="scheduledReportTask" class="org.springframework.scheduling.timer.ScheduledTimerTask"> <property name="timerTask"> <ref bean="reportTimerTask"/> </property> <property name="period"> <value>86400000</value> </property> </bean> 屬性timerTask告訴ScheduledTimerTask運行哪個TimerTask。在這裡,該屬性裝配了指向reportTimerTask的一個引用,它就是EmailReportTask。屬性period告訴ScheduledTimerTask以怎樣的頻度調用TimerTask的run()方法。這個屬性以毫秒作為單位,它被設定為86400000,指定這個任務應該每24小時運行一次。
啟動定時器 最後一步是啟動定時器。Spring的TimerFactoryBean負責啟動定時任務。按以下方式在Spring設定檔中聲明它: <bean class="org.springframework.scheduling.timer.TimerFactoryBean"> <property name="scheduledTimerTasks"> <list> <ref bean="scheduledReportTask"/> </list> </property> </bean> 屬性scheduledTimerTasks要求一個需要啟動的定時器任務的列表。既然你現在只有一個定時器任務,這個列表中只包含一個指向scheduledReportTask Bean的引用。 遺憾的是,即使這個任務已經能夠每隔24小時運行一次了,在這裡你無法指定它應該在一天中的哪個時間點執行。ScheduledTimerTask有一個delay屬性,允許你指定當任務第一次運行之前應該等待多久。例如,要將EmailReportTask的第一次運行延遲1小時,可以按照以下方式進行配置: <bean id="scheduledReportTask" class="org.springframework.scheduling.timer.ScheduledTimerTask"> <property name="timerTask"> <ref bean="reportTimerTask"/> </property> <property name="period"> <value>86400000</value> </property> <property name="delay"> <value>3600000</value> </property> </bean>
2
.使用
Quartz