国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Matrix - 與 Java 共舞 - 不需要應(yīng)用服務(wù)器的J2EE

盡管J2EE平臺(tái)(應(yīng)用程序服務(wù)器)及其編程模型(企業(yè)JAVA組件,簡稱EJB)擁有的眾所周知的復(fù)雜性,但是基于J2EE的應(yīng)用程序仍然在企業(yè)領(lǐng)域里變得非常成功.我們要感謝應(yīng)用于輕量級(jí)容器的控制反轉(zhuǎn)(IoC)和面向方面編程(AOP),比如Spring框架. 我們能夠更簡單地設(shè)計(jì)更大型的編程模型。然而,即使有了這些工具,應(yīng)用服務(wù)器仍然是復(fù)雜度和消耗的一個(gè)重要瓶頸。這篇文章提供了一個(gè)對(duì)J2EE的簡化,展示了如何消除應(yīng)用服務(wù)器的消耗和限制。特別地,這篇文章提到了:許多應(yīng)用程序?qū)嶋H上并不需要運(yùn)行應(yīng)用服務(wù)器。這樣,J2EE應(yīng)用組件將會(huì)變得:
·        開發(fā)更容易:不再需要EJB運(yùn)行代碼;
·        更簡單: 繼承不需要EJB類或接口;
·        測(cè)試更容易:你的應(yīng)用程序及測(cè)試能在你的開發(fā)環(huán)境(IDE)中直接運(yùn)行;
·        更少的資源消耗:你只需要你的對(duì)象,不需要應(yīng)用服務(wù)器,更不需要應(yīng)用服務(wù)器的對(duì)象;
·        安裝更容易:沒有運(yùn)行應(yīng)用服務(wù)專門的安裝軟件, 沒有加載額外的XML文件;
·        維護(hù)更容易:所有的過程都更簡單,因此維護(hù)也更容易。

J2EE不必要的復(fù)雜度已經(jīng)成為一個(gè)阻礙。今天,這種復(fù)雜度能夠通過在這篇文章中提到的方法來避免。另外,程序還能夠保留事務(wù)和安全這些典型的服務(wù)。J2EE程序從來沒有比這更有趣過。

版權(quán)聲明:任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必保留以下作者信息和鏈接
作者:Guy Pardon;chmei83(作者的blog:http://blog.matrix.org.cn/page/chmei83)
原文:http://www.onjava.com/pub/a/onjava/2006/02/08/j2ee-without-application-server.html
譯文:http://www.matrix.org.cn/resource/article/44/44250_J2ee+Application+Server.html
關(guān)鍵字:J2ee;Application;Server

例子:消息驅(qū)動(dòng)Bank

為了闡述我們的觀點(diǎn),我們將開發(fā)和安裝一個(gè)完整的樣板應(yīng)用程序:一個(gè)消息驅(qū)動(dòng)的銀行系統(tǒng). 通過(幸虧有Spring)改進(jìn)的基于POJOs的編程模型和保留相同的事務(wù),我們可以不需要EJB或者一個(gè)應(yīng)用服務(wù)器來實(shí)現(xiàn)這個(gè)系統(tǒng)。在下一個(gè)部分,我們將從消息驅(qū)動(dòng)架構(gòu)產(chǎn)生到另一個(gè)架構(gòu).就像基于WEB的架構(gòu)一樣.圖1展示我們的樣本應(yīng)用程序的架構(gòu).  


Figure 1. Architecture of the message-driven bank

在我們的例子中,我們將處理來自Java消息服務(wù)隊(duì)列的銀行定單.一張定單的處理包括通過JDBC來更新當(dāng)前帳戶的數(shù)據(jù)庫.為了避免信息的丟失和重復(fù),我們將使用JTA和JTA/XA事務(wù)來配合更新:處理信息和更新數(shù)據(jù)庫將發(fā)生在一個(gè)原子事務(wù)里.資源部分可得到JTA/XA的更多信息.

編寫應(yīng)用程序代碼

該應(yīng)用程序?qū)⒂蓛蓚€(gè)JAVA類組成: Bank(一個(gè)DAO)和MessageDrivenBank.如圖2.


Figure 2. Classes for the message-driven bank

Bank是一個(gè)數(shù)據(jù)訪問對(duì)象,這個(gè)對(duì)象封裝數(shù)據(jù)庫訪問。MessageDrivenBank是一個(gè)消息驅(qū)動(dòng)façade并且是DAO的委托.與典型的J2EE方法不同,這個(gè)應(yīng)用程序不包括EJB類.

第一步:編寫B(tài)ank DAO

如下, Bank源代碼是很直接和簡單的JDBC操作.

package jdbc;
import javax.sql.*;
import java.sql.*;
public class Bank
{
  private DataSource dataSource;
  public Bank() {}
  public void setDataSource ( DataSource dataSource )
  {
    this.dataSource = dataSource;
  }

private DataSource getDataSource()
  {
    return this.dataSource;
  }

  private Connection getConnection()
  throws SQLException
  {
    Connection ret = null;
    if ( getDataSource() != null ) {
        ret = getDataSource().
              getConnection();
    }
    return ret;
  }

  private void closeConnection ( Connection c )
  throws SQLException
  {
    if ( c != null ) c.close();
  }
    
  public void checkTables()
  throws SQLException
  {
        
    Connection conn = null;
    try {
      conn = getConnection();
      Statement s = conn.createStatement();
      try {
        s.executeQuery (
        "select * from Accounts" );
      }
      catch ( SQLException ex ) {
        //table not there => create it
        s.executeUpdate (
        "create table Accounts ( " +
        "account VARCHAR ( 20 ), " +
        "owner VARCHAR(300), " +
        "balance DECIMAL (19,0) )" );
        for ( int i = 0; i < 100 ; i++ ){
          s.executeUpdate (
          "insert into Accounts values ( " +
          "‘a(chǎn)ccount"+i +"‘ , ‘owner"+i +"‘, 10000 )"
          );
        }
      }
      s.close();
      }
      finally {
        closeConnection ( conn );

      }

      //That concludes setup
  }

    
  //
  //Business methods are below
  //

  public long getBalance ( int account )
  throws SQLException
  {
        
    long res = -1;
    Connection conn = null;

    try {
      conn = getConnection();
      Statement s = conn.createStatement();
      
      String query =
      "select balance from Accounts where account=‘"+
      "account" + account +"‘";
      
      ResultSet rs = s.executeQuery ( query );
      if ( rs == null || !rs.next() )
        throw new SQLException (
        "Account not found: " + account );
      res = rs.getLong ( 1 );
      s.close();
    }
    finally {
        closeConnection ( conn );
    }
    return res;
        
  }

  public void withdraw ( int account , int amount )
  throws Exception
  {
    Connection conn = null;

    try {
      conn = getConnection();
      Statement s = conn.createStatement();

      String sql =
      "update Accounts set balance = balance - "+
      amount + " where account =‘a(chǎn)ccount"+
      account+"‘";
      
      s.executeUpdate ( sql );
      s.close();
    
    }
    finally {
        closeConnection ( conn );

    }
  }
}


注意:代碼并沒有依賴EJB或任何專門的應(yīng)用程序服務(wù)器.實(shí)際上,這是一個(gè)純JAVA代碼,這個(gè)JAVA代碼是能在任何J2SE環(huán)境下運(yùn)行的.
你同時(shí)應(yīng)注意:我們使用了來自JDBC的DataSource接口.這意味著我們的類是獨(dú)立于目前JDBC供應(yīng)商提供的類. 你可能會(huì)疑惑,這怎么能與特定的數(shù)據(jù)管理系統(tǒng)(DBMS)提供商的JDBC實(shí)現(xiàn)緊密結(jié)合呢? 這里就是Spring框架幫你實(shí)現(xiàn)的. 這個(gè)技術(shù)被稱為依賴注入:在我們的應(yīng)用程序的啟動(dòng)期間,通過調(diào)用setDataSource方法,Spring為我們提供了相應(yīng)的datasource對(duì)象.在后面幾部分我們會(huì)更多地提到Spring.如果我們?cè)谝郧笆褂脩?yīng)用程序服務(wù)器,我們將不得不借助于JAVA命名綁定接口(JNDI)查詢.

除了直接使用JDBC,我們也可以使用Hibernate或者一個(gè)JDO工具來實(shí)現(xiàn)我們的持久層.這同樣不需要任何的EJB代碼.

第二步:配置BankDAO

我們會(huì)將便用Spring框架來配置我們的應(yīng)用程序.Spring不是必需的,但是使用Spring的好處是我們將可以簡單的添加服務(wù),如:我們JAVA對(duì)象的事務(wù)和安全.這類似于應(yīng)用服務(wù)器為EJB提供的東西,只是在我們的例子中Spring將變得更容易.
Spring也允許我們把我們的類從目前的JDBC驅(qū)動(dòng)實(shí)現(xiàn)中分離出來:Spring能夠配置Driver(基于我們的XML配置數(shù)據(jù))并把它提供給BankDAO對(duì)象(依賴注入原理).這樣可以保持我們的JAVA代碼的清淅和集中.這步的Spring配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>


<beans>

<bean id="datasource"
class="com.atomikos.jdbc.nonxa.NonXADataSourceBean">

    <property name="user">
        <value>sa</value>
    </property>
    <property name="url">
        <value>jdbc:hsqldb:SpringNonXADB
        </value>
    </property>
    <property name="driverClassName">
        <value>org.hsqldb.jdbcDriver</value>
    </property>
    <property name="poolSize">
        <value>1</value>
    </property>
    <property name="connectionTimeout">
        <value>60</value>
    </property>
</bean>

<bean id="bank" class="jdbc.Bank">
        <property name="dataSource">
            <ref bean="datasource"/>
        </property>
</bean>

</beans>


這個(gè)XML文件包括兩個(gè)對(duì)象的配置:訪問數(shù)據(jù)庫的DataSource和使用這個(gè)DataSource的Bank對(duì)象.下面是由Spring維護(hù)的一些基本任務(wù).
·        創(chuàng)建應(yīng)用程序(例: Bank和DataSource)需要的對(duì)象(“beans”).在XML文件中給出了這些對(duì)象的類名,并且在我們的例子中,這些對(duì)象需要有一個(gè)公共的無參數(shù)constructor (Spring也允許參數(shù),但是配置語法上有所不同).這些對(duì)象都被命名(XML中的id屬性),所以我們后面能夠引用這些對(duì)象. id也允許我們的應(yīng)用程序找回它需要的已配置對(duì)象.
·        這些對(duì)象的初始化是通過在XML文件中的properties的值實(shí)現(xiàn). 在XML文件中這些properties名 應(yīng)與對(duì)應(yīng)的類中的setXXX方法相對(duì)應(yīng).
·        將對(duì)象連接在一起 :一個(gè)property可能是另一個(gè)對(duì)象(例如:在我們例子中的數(shù)據(jù)源)的引用,引用可以通過id創(chuàng)建.

注意:在我們下一步中, 我們將選擇配置一個(gè)JTA-enabled的數(shù)據(jù)源(由Atomikos Transactions提供,可用于企業(yè)和J2SE的JTA產(chǎn)品,我們將應(yīng)用于我們的應(yīng)用程序). 簡單起見,我們將使用HypersonicSQLDB,這個(gè)DBMS不需要專門的安裝步驟—它是在.jar文件里,就像JTA和Spring.

但是,考慮到漸增的可靠性需求,強(qiáng)列推薦你使用XA-capable的DBMS和JDBC驅(qū)動(dòng).沒有XA的支持, 在crash或重啟之后你的應(yīng)用程序?qū)⒉荒芑謴?fù)原有數(shù)據(jù). 資源部分有鏈接到關(guān)于事務(wù)和XA的信息和一些例子.

作為一個(gè)練習(xí),你可以試試從HypersonicSQLDB轉(zhuǎn)換到FirstSQL,一個(gè)易安裝XA-compliant的DBMS.換句話說,任何其他為企業(yè)準(zhǔn)備的和XA-capable的DBMS也會(huì)做得很好.

第三步:測(cè)試BankDAO

讓我們來測(cè)試我們的代碼,(使用極限編程的程序員會(huì)首先寫測(cè)試,但因開始不是很清淅,所以我們直到現(xiàn)在才開始寫測(cè)試.)下面是一個(gè)簡單的單元測(cè)試.這個(gè)測(cè)試可在你的的應(yīng)用程序里運(yùn)行:它通過Spring獲得一個(gè)BANK對(duì)象來進(jìn)行測(cè)試(這在setUp方法中實(shí)現(xiàn)).注意:這個(gè)測(cè)試使用清楚的事務(wù)劃分:每一個(gè)測(cè)試開始之前開始一個(gè)事務(wù),每個(gè)測(cè)試結(jié)束時(shí)強(qiáng)制進(jìn)行事務(wù)回滾.這是通過手工的方式來減少測(cè)試對(duì)數(shù)據(jù)庫數(shù)據(jù)的影響.

package jdbc;
import com.atomikos.icatch.jta.UserTransactionImp;
import junit.framework.TestCase;
import java.io.FileInputStream;
import java.io.InputStream;
import org.springframework.beans.factory.xml.XmlBeanFactory;

public class BankTest extends TestCase
{

    private UserTransactionImp utx;

    private Bank bank;

    public BankTest ( String name )
    {
        super ( name );
        utx = new UserTransactionImp();
        

    }

    protected void setUp()
        throws Exception
    {
        //start a new transaction
        //so we can rollback the
        //effects of each test
        //in teardown!
        utx.begin();
        
        //open bean XML file
        InputStream is =
            new FileInputStream("config.xml");

        //the factory is Spring‘s entry point
        //for retrieving the configured
        //objects from the XML file

        XmlBeanFactory factory =
            new XmlBeanFactory(is);

        bank = ( Bank ) factory.getBean ( "bank" );
        bank.checkTables();
    }

    protected void tearDown()
        throws Exception
    {
        //rollback all DBMS effects
        //of testing
        utx.rollback();
    }

    public void testBank()
    throws Exception
    {
        int accNo = 10;
        long initialBalance = bank.getBalance ( accNo );
        bank.withdraw ( accNo , 100 );
        long newBalance = bank.getBalance ( accNo );
        if ( ( initialBalance - newBalance ) != 100 )
            fail ( "Wrong balance after withdraw: " +
                   newBalance );
    }
    
}


我們將需要JTA事務(wù)來確保JMS和JDBC都是原子操作.一般來說,當(dāng)經(jīng)常都是兩個(gè)或多個(gè)連接的時(shí)候,你應(yīng)考慮一下JTA/XA。例如,在我們例子中的JMS和JDBC. Spring本身不提供JTA事務(wù);它需要一個(gè)JTA實(shí)現(xiàn)或者委派一個(gè)應(yīng)用服務(wù)器來處理這個(gè)事務(wù).在這里,我們使用了一個(gè)JTA實(shí)現(xiàn),這個(gè)實(shí)現(xiàn)可以在任何J2SE平臺(tái)上工作.
最終架構(gòu)如下面圖3.白色方框代表我們的應(yīng)用程序代碼.


Figure 3. Architecture for the test

如你所看到的,當(dāng)我們執(zhí)行我們的測(cè)試,將會(huì)發(fā)生下面的情況:
1.        BankTest開始一個(gè)新事務(wù).
2.        然后,這個(gè)test在Spring運(yùn)行期間獲得一個(gè)BANK對(duì)象.這步觸發(fā)Sping的創(chuàng)建和初始化過程.
3.        這個(gè)test調(diào)用BANK的方法.
4.        BANK調(diào)用datasource對(duì)象,通過它自己的setDataSource 方法從Spring 獲取這個(gè)對(duì)像.
5.        這個(gè)數(shù)據(jù)源是JTA-enabled,并且與JTA實(shí)現(xiàn)交互來注冊(cè)當(dāng)前事務(wù).
6.        JDBC statements和帳戶數(shù)據(jù)庫交互.
7.        當(dāng)方法返回時(shí), test調(diào)用事務(wù)回滾.
8.        JTA記得住datasource對(duì)象,會(huì)命令它進(jìn)行回滾.

第四步:添加聲明式事務(wù)管理

Spring允許添加聲明式事務(wù)管理來管理java對(duì)象.假設(shè)我們想確認(rèn)bank總是和一個(gè)有效的事務(wù)上下文一起被調(diào)用.我們通過在實(shí)際對(duì)象的上部配置一個(gè)proxy對(duì)象. Proxy和實(shí)際對(duì)象有相同接口,所以客戶通過完全相同的方式使用它. 配置Proxy wrap每個(gè)BankDAO方法到事務(wù)中.結(jié)果配置文件如下. 不要被XML的龐大嚇倒—大多數(shù)內(nèi)容能通過復(fù)制和粘貼到你自己的工程中再使用.

<?xml version="1.0" encoding="UTF-8"?>

<beans>
    <!--
        Use a JTA-aware DataSource
        to access the DB transactionally
    -->
    <bean id="datasource"
        class="com.atomikos.jdbc.nonxa.NonXADataSourceBean">
        <property name="user">
            <value>sa</value>
        </property>
        <property name="url">
            <value>jdbc:hsqldb:SpringNonXADB</value>
        </property>
        <property name="driverClassName">
            <value>org.hsqldb.jdbcDriver</value>
        </property>
        <property name="poolSize">
            <value>1</value>
        </property>
        <property name="connectionTimeout">
            <value>60</value>
        </property>
    </bean>
    <!--
    Construct a TransactionManager,
    needed to configure Spring
    -->
    <bean id="jtaTransactionManager"
        class="com.atomikos.icatch.jta.UserTransactionManager"/>
    <!--
    Also configure a UserTransaction,
    needed to configure Spring  
    -->
    
    <bean id="jtaUserTransaction"
        class="com.atomikos.icatch.jta.UserTransactionImp"/>
    <!--
    Configure the Spring framework to use
    JTA transactions from the JTA provider
    -->
    <bean id="springTransactionManager"
    class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <ref bean="jtaTransactionManager"/>
        </property>
        <property name="userTransaction">
            <ref bean="jtaUserTransaction"/>
        </property>
    </bean>
    <!-- Configure the bank to use our datasource -->
    <bean id="bankTarget" class="jdbc.Bank">
        <property name="dataSource">
            <ref bean="datasource"/>
        </property>
    </bean>
    <!--
    Configure Spring to insert
    JTA transaction logic for all methods
    -->
    <bean id="bank"
    class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="springTransactionManager"/>
        </property>
        <property name="target">
            <ref bean="bankTarget"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">
                    PROPAGATION_REQUIRED, -Exception
                </prop>
            </props>
        </property>
    </bean>
</beans>


這個(gè)XML文件告訴Spring去配置下面的對(duì)象:
1.        需要通過JDBC連接的datasource.
2.         添加jtaTransactionManager和jtaUserTransaction用于為JTA事務(wù)的Spring配置作準(zhǔn)備.
3.        springTransactionManager用于告訴Spring需要使用JTA.
4.         BankDAO被重命名為bankTarget (因如下解釋的原因).
5.        bank對(duì)象被添加用于包裝事務(wù)和bankTarget的所有方法.我們通過配置bank對(duì)象來使用

springTransactionManager,這意味著所有事務(wù)將是JTA事務(wù). 每個(gè)事務(wù)都被設(shè)置為PROPAGATION_REQUIRED,這將在任何異常下出現(xiàn)強(qiáng)制回滾.

對(duì)這些對(duì)象包含的內(nèi)容,你都可以很容易的復(fù)制和粘貼jtaTransactionManager, jtaUserTransaction, springTransactionManager到其他工程.其他的是應(yīng)用程序相關(guān)的對(duì)象:datasource, bankTarget, bank. Bank對(duì)象很有趣:事實(shí)上對(duì)于bankTarget它是一個(gè)proxy;他們擁有相同的接口. Trick如下:當(dāng)我們的應(yīng)用程序請(qǐng)求Spring去配置和返回bank對(duì)象,Spring實(shí)際上將返回proxy(看起來和我們的應(yīng)用程序完全相同),隨后這個(gè)proxy將為我們開始/結(jié)束事務(wù).這樣,應(yīng)用程序和Bank類本身都不需要知道JTA!圖4闡述了在這步我們所得到的.  


Figure 4. Architecture with declarative JTA transactions in Spring

現(xiàn)在的工作如下:
1.        應(yīng)用程序調(diào)用bank對(duì)象.這將觸發(fā)Spring的初始化處理和返回proxy對(duì)象. 對(duì)應(yīng)用程序而言,這個(gè)proxy行為和我們的Bank是一樣的.
2.        當(dāng)bank的一個(gè)方法被調(diào)用, 這個(gè)調(diào)用將會(huì)通過proxy進(jìn)行.
3.        proxy使用springTransactionManager創(chuàng)建一個(gè)新事務(wù).
4.        springTransactionManager被配置為使用JTA,因些它委派到JTA.
5.        調(diào)用被forward到Bank的實(shí)際對(duì)象,bankTarget.
6.        bankTarget使用從Spring中得到的datasource.
7.        datasource對(duì)事務(wù)進(jìn)行注冊(cè).
8.        通過規(guī)則的JDBC訪問數(shù)據(jù)庫.
9.        在返回時(shí), proxy終止事務(wù):如果在先前的序列中沒有發(fā)生異常,那么將會(huì)提交終止指令.否則,它將會(huì)被回滾.
10.        transaction 管理器與數(shù)據(jù)庫配合進(jìn)行提交和回滾.

在這步中的測(cè)試怎樣進(jìn)行?我們可重用BankTest 和它清晰的事務(wù)劃分:因?yàn)镻ROPAGATION_REQUIRED, proxy將和在BankTest中創(chuàng)建的事務(wù)上下文一起執(zhí)行.

第五步:編寫PROPAGATION_REQUIRED

在這步,我們將添加JMS處理邏輯.為了做到這樣,我們主要需要實(shí)現(xiàn)JMS MessageListener接口.我們也會(huì)添加公共的setBank方法使Spring的依賴注入起作用.源代碼如下:

package jms;
import jdbc.Bank;
import javax.jms.Message;
import javax.jms.MapMessage;
import javax.jms.MessageListener;

public class MessageDrivenBank
implements MessageListener
{
    private Bank bank;

    public void setBank ( Bank bank )
    {
        this.bank = bank;
    }

    //this method can be private
    //since it is only needed within
    //this class
    private Bank getBank()
    {
        return this.bank;
    }

    public void onMessage ( Message msg )
    {
        try {
          MapMessage m = ( MapMessage ) msg;
          int account = m.getIntProperty ( "account" );
          int amount = m.getIntProperty ( "amount" );
          bank.withdraw ( account , amount );
          System.out.println ( "Withdraw of " +
          amount + " from account " + account );
        }
        catch ( Exception e ) {
          e.printStackTrace();
            
          //force rollback
          throw new RuntimeException (
          e.getMessage() );
        }
    }
    
}



第六步:配置MessageDrivenBank

這里我們配置MessageDrivenBank去監(jiān)聽事務(wù)的QueueReceiverSessionPool.這樣給我們可以實(shí)現(xiàn)和EJB(沒有丟失信息和冗余信息)類似的消息機(jī)制,但在這里我們是用簡單的POJO對(duì)象實(shí)現(xiàn).當(dāng)向pool中插入一個(gè)MessageListener,這個(gè)會(huì)話池將確保用JTA/XA事務(wù)接收到消息.結(jié)合JTA/XA-capable 的JDBC數(shù)據(jù)源,我們可以實(shí)現(xiàn)可靠的消息機(jī)制.  Spring的配置如下:

<?xml version="1.0" encoding="UTF-8"?>


<!--
        NOTE: no explicit transaction manager bean
        is necessary
        because the QueueReceiverSessionPool will
        start transactions by itself.
-->
<beans>
    <bean id="datasource"
        class="com.atomikos.jdbc.nonxa.NonXADataSourceBean">
        <property name="user">
            <value>sa</value>
        </property>
        <property name="url">
            <value>jdbc:hsqldb:SpringNonXADB</value>
        </property>
        <property name="driverClassName">
            <value>org.hsqldb.jdbcDriver</value>
        </property>
        <property name="poolSize">
            <value>1</value>
        </property>
        <property name="connectionTimeout">
            <value>60</value>
        </property>
    </bean>
    <bean id="xaFactory"
        class="org.activemq.ActiveMQXAConnectionFactory">
        <property name="brokerURL">
            <value>tcp://localhost:61616</value>
        </property>
    </bean>
    <bean id="queue"
        class="org.activemq.message.ActiveMQQueue">
        <property name="physicalName">
            <value>BANK_QUEUE</value>
        </property>
    </bean>
    <bean id="bank" class="jdbc.Bank">
        <property name="dataSource">
            <ref bean="datasource"/>
        </property>
    </bean>
    <bean id="messageDrivenBank"
        class="jms.MessageDrivenBank">
        <property name="bank">
            <ref bean="bank"/>
        </property>
    </bean>
    <bean id="queueConnectionFactoryBean"
        class="com.atomikos.jms.QueueConnectionFactoryBean">
        <property name="resourceName">
            <value>QUEUE_BROKER</value>
        </property>
        <property name="xaQueueConnectionFactory">
            <ref bean="xaFactory"/>
        </property>
    </bean>
    <bean id="queueReceiverSessionPool"
        class="com.atomikos.jms.QueueReceiverSessionPool"
        init-method="start">
        
        <property name="queueConnectionFactoryBean">
            <ref bean="queueConnectionFactoryBean"/>
        </property>
        <property name="transactionTimeout">
            <value>120</value>
        </property>
        <!--
        default license allows only limited
        concurrency so keep pool small
        -->
        <property name="poolSize">
            <value>1</value>
        </property>
        <property name="queue">
            <ref bean="queue"/>
        </property>
        <property name="messageListener">
            <ref bean="messageDrivenBank"/>
        </property>
    </bean>
</beans>


因?yàn)檫@篇文章需要一個(gè)便于安裝的JMS服務(wù),所以這里我們使用ActiveMQ.如果你正在使用另一個(gè)JMS實(shí)現(xiàn),那么你將仍然能使用這部分提出的技術(shù).接下來除了datasource和bank對(duì)象,我們將增加下面的對(duì)象定義:

·        xaFactory: 為建立JMS連接的connection工廠.
·        queue: queue代表我們將使用的JMS隊(duì)列, 這個(gè)隊(duì)列被配置成ActiveMQ要求的形式.
·        queueConnectionFactoryBean:一個(gè)JTA-aware的JMS連接器.
·        A queueReceiverSessionPool for JTA-enabled message consumption:注意:我們同時(shí)指定了用來調(diào)用的初始化方法(例:start);這是Spring的另一個(gè)特性. Start方法在session pool類里定義,它是在Spring配置文件中進(jìn)行配置的.
·        messageDrivenBank:負(fù)責(zé)處理消息.

你可以問問自己事務(wù)管理是在哪里進(jìn)行的.事實(shí)上, 在先前部分被添加的對(duì)象已消失.為什么呢?因?yàn)槲覀儸F(xiàn)在使用QueueReceiverSessionPool來接收來自JMS的消息,并且這個(gè)類也為每次接收啟動(dòng)一個(gè)JTA事務(wù).我們也可以保留JTA配置,另外添加JMS配置, 但是這樣可能會(huì)使XML文件更長. 現(xiàn)在session pool類將擔(dān)當(dāng)事務(wù)管理角色.它和proxy方法的工作相似; 只是這個(gè)類需要JMS  MessageListener 為之添加事務(wù). 通過這樣配置,在每個(gè)消息收接之前程序?qū)?dòng)一個(gè)新事務(wù) 無論何時(shí), 當(dāng)我們的消息實(shí)例正常返回時(shí), 這個(gè)事務(wù)將提交. 如果出現(xiàn)RuntimeException, 那么這個(gè)事務(wù)將回滾. 結(jié)構(gòu)如下面圖5(可以清淅地看到一些JMS對(duì)象).


Figure 5. Architecture for message-driven applications in Spring

現(xiàn)在該架構(gòu)工作如下:
1.        應(yīng)用程序調(diào)用bank對(duì)象和初始化數(shù)據(jù)庫表.
2.        應(yīng)用程序queueReceiverSessionPool, 因此觸發(fā)一個(gè)start方法的調(diào)用去監(jiān)聽到達(dá)的消息.
3.        queueReceiverSessionPool在隊(duì)列中偵察一個(gè)新消息.
4.        queueReceiverSessionPool開始一個(gè)新事務(wù),并且注冊(cè)這個(gè)事務(wù).
5.        queueReceiverSessionPool調(diào)用已注冊(cè)的MessageListener (messageDrivenBank).
6.        這將觸發(fā)對(duì)bank 對(duì)象的調(diào)用.
7.        bank 對(duì)象通過datasource訪問數(shù)據(jù)庫.
8.        datasource注冊(cè)事務(wù).
9.        通過JDBC訪問數(shù)據(jù)庫.
10.        當(dāng)處理完成時(shí), queueReceiverSessionPool會(huì)終止這個(gè)事務(wù)。然后進(jìn)行commint(除非發(fā)生RuntimeException).
11.        transaction manager開始消息隊(duì)列的兩階段提交.
12.        transaction manager開始數(shù)據(jù)庫的兩階段提交.

第七步:編寫應(yīng)用程序
因?yàn)槲覀儧]有使用容器,我們僅僅提供一個(gè)Java應(yīng)用程序就可以啟動(dòng)整個(gè)銀行系統(tǒng).我們的Java應(yīng)用程序是非常簡單: 它有能力找回配置的對(duì)象(Spring通過XML文件將他們放到一起). 這個(gè)應(yīng)用程序能在任何兼容的JDK(Java Development Kit)上運(yùn)行,并且不需要應(yīng)用服務(wù)器.

package jms;
import java.io.FileInputStream;
import java.io.InputStream;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import com.atomikos.jms.QueueReceiverSessionPool;
import jdbc.Bank;

public class StartBank
{
  public static void main ( String[] args )
  throws Exception
  {
    //open bean XML file
    InputStream is =
    new FileInputStream(args[0]);
    
    //the factory is Spring‘s entry point
    //for retrieving the configured
    //objects from the XML file
    XmlBeanFactory factory =
        new XmlBeanFactory(is);
    
    //retrieve the bank to initialize
    //alternatively, this could be done
    //in the XML configuration too
    Bank bank =
        ( Bank ) factory.getBean ( "bank" );
    
    //initialize the bank if needed
    bank.checkTables();

    //retrieve the pool;
    //this will also start the pool
    //as specified in the beans XML file
    //by the init-method attribute!

    QueueReceiverSessionPool pool  =
        ( QueueReceiverSessionPool )
        factory.getBean (
        "queueReceiverSessionPool" );

    //Alternatively, start pool here
    //(if not done in XML)
    //pool.start();

    System.out.println (
        "Bank is listening for messages..." );
        
  }
}


這就是J2EE!是不是認(rèn)為J2EE也很容易呢?

對(duì)通用性的考慮
這部分里我們看看更多的概念,這些概念在許多J2EE應(yīng)用程序中是很重要的.我們同樣將看到對(duì)這些概念來說,一個(gè)應(yīng)用服務(wù)器并不是必須的.

集群和可擴(kuò)展性
健壯的企業(yè)應(yīng)用程序需要集群來分流負(fù)擔(dān). 在消息驅(qū)動(dòng)應(yīng)用程序的例子中,這很容易:我們自動(dòng)地從JMS應(yīng)用程序繼承得來處理能力.如果我們需要更強(qiáng)大的處理能力,那么我們只需增加更多連接相同JMS服務(wù)器的進(jìn)程.一個(gè)對(duì)服務(wù)性能有效的衡量標(biāo)準(zhǔn)是在隊(duì)列中停留的消息的數(shù)量. 在其他情況下,如基于web的 架構(gòu)(如下)我們能很容易地使用web環(huán)境下的集群能力.

方法級(jí)別的安全
一個(gè)典型的觀點(diǎn)是認(rèn)為EJB能增加方法級(jí)的安全性.雖然并沒有在這篇文章中提到,但是在Sping中配置方法級(jí)別的安全是可能的.這種配置類似于我們?cè)黾臃椒?jí)的事務(wù)劃分的方式.

對(duì)非消息驅(qū)動(dòng)的應(yīng)用程序的通用性
在不改變?cè)创a的情況下(除了主應(yīng)用程序類),我們使用的平臺(tái)能很容易地被整合到任何J2EE web 應(yīng)用服務(wù)器. 換句話說 , 通過JMS進(jìn)行后臺(tái)處理;這使得web服務(wù)器在面對(duì)后臺(tái)處理的延遲問題上更可靠和更獨(dú)立.在任何情況下, 為了實(shí)現(xiàn)容器管理的事務(wù)或容器管理的安全性,我們都不再需要依靠EJB容器來實(shí)現(xiàn).

關(guān)于容器管理持久化?
存在并被很多開發(fā)者檢驗(yàn)過的技術(shù)例如:JDO或者Hibernate 都不一定需要一個(gè)應(yīng)用服務(wù)器. 另外,這些工具已經(jīng)占據(jù)了持久化市場.

結(jié)論
今天,不需要應(yīng)用服務(wù)器的J2EE已經(jīng)成為可能,也很容易. 有人或許會(huì)說,沒有應(yīng)用程序服務(wù)器,有一些應(yīng)用程序仍不能實(shí)現(xiàn):例如,如果你需要一般的JCA(Java Connectivity API) 功能性, 那么我們上面提供的平臺(tái)是不夠的. 但是,這可能會(huì)發(fā)生改變,因?yàn)椴挥檬褂靡粋€(gè)應(yīng)用程序服務(wù)器進(jìn)行開發(fā),測(cè)式和部署的好處實(shí)在是太大. 人們?cè)絹碓较嘈? 將來得J2EE是一個(gè)模塊化的”選擇你所需要”架構(gòu). 這與我們之前的完全基于應(yīng)用服務(wù)器的方法相反. 在這樣的情況下,J2EE開發(fā)者將從應(yīng)用服務(wù)器和EJB中解放出來.


本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
將Spring和Hibernate 與WAS一起使用
XA transactions using Spring | JavaWorld
Java事務(wù)處理全解析(八)
Ibatis2.0使用說明(二)——配置篇(1)
Spring對(duì)JTA的支持
在spring中使用聲明型事務(wù)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服