wayne

          2008年9月12日 #

          JMS (2)

          異步隊列消息的接收有一點區別,但發送的代碼不用改變:

           1@Stateless
           2public class JMSReceiveBean implements JMSReceiveRemote {
           3
           4    @Resource(name = "jms/Queue")
           5    private Queue queue;
           6    @Resource(name = "jms/ConnectionFactory")
           7    private ConnectionFactory queueFactory;
           8
           9    private void receiveJMSMessageFromQueue() throws Exception {
          10        Connection connection = null;
          11        Session session = null;
          12        connection = queueFactory.createConnection();
          13        session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
          14        MessageConsumer consumer = session.createConsumer(queue);
          15        consumer.setMessageListener(new MessageListener() {
          16
          17            public void onMessage(Message message) {
          18                TextMessage msg = (TextMessage) message;
          19                try {
          20                    String txt = msg.getText();
          21                    Logger.getLogger(JMSReceiveBean.class.getName()).log(Level.SEVERE, txt);
          22                }
           catch (Exception ex) {
          23                    ex.printStackTrace();
          24                }

          25            }

          26        }
          );
          27        
          28        connection.start();
          29    }

          30
          31    public void receiveMessage() {
          32        try {
          33            receiveJMSMessageFromQueue();
          34        }
           catch (Exception ex) {
          35            Logger.getLogger(JMSReceiveBean.class.getName()).log(Level.SEVERE, null, ex);
          36        }

          37    }

          38}

          在15行消息使用者上設置了一個消息監聽器,而沒有使用同步的receive方法。由于這是異步接收消息,程序并沒有處于阻塞狀態,為了避免在接收到消息之前連接終止,所以在28行之后并沒有關閉Connection,實際上這一步是不可缺少的。

          posted @ 2008-09-14 16:40 waynemao 閱讀(115) | 評論 (0)編輯 收藏

          JMS (1)

               摘要: 開發任何JMS應用之前,首先要做的事是在應用服務器中配置JMS被管對象:連接工廠和目的地。它們最好不要以編程的方式實現,因為其背后的技術有多種不同的API實現,可能無法移植。以下是glassfish中的配置: 在配置--java消息服務里創建兩個物理目的地  名稱:myQueue  類型:javax.jms.Queue  名稱:myTopic  類...  閱讀全文

          posted @ 2008-09-14 05:31 waynemao 閱讀(314) | 評論 (0)編輯 收藏

          EJB3 (7)

          有狀態會話bean的開發,首先創建遠程接口:

          @Remote
          public interface HelloRemote {

              String sayHi();

              
          void init(String name);
              
              
          void remove();
              
          }

          接著開發有狀態會話bean:
          @Stateful
          public class HelloBean implements HelloRemote {
              
          private String name;
              
          private Logger log = Logger.getLogger(this.getClass().getName());
              
              
          public String sayHi() {
                  
          return "Hi " + name;
              }


              
          public void init(String name) {
                  
          this.name = name;
              }

              
              @PostConstruct
              
          public void postConstrut(){
                  log.info(
          "create " + this);
              }

              
              @PreDestroy
              
          public void preDestory(){
                  log.info(
          "destory " + this);
              }

              
              @PostActivate
              
          public void postActivate(){
                  log.info(
          "activate " + this);
              }

              
              @PrePassivate
              
          public void prePassivate(){
                  log.info(
          "passivate " + this);
              }

              
              @Remove
              
          public void remove(){
                  log.info(
          "remove " + this);
              }

          }

          @Stateful注釋表明這是一個有狀態會話bean,其他的注釋是管理會話bean的生命周期。@PostConstruct注釋表明方法將會在bean實例化并完成依賴注入后由容器調用此方法;@PreDestory注釋表示方法會在容器刪除bean實例前由容器調用;以上兩個注釋所有的EJB(包括MDB)都可以用。@PostActivate注釋表示容器在激活bean后調用此方法;@PrePassivate注釋表示容器在鈍化bean前調用此方法;以上兩個注釋是有狀態會話bean所特有。@Remove注釋也是有狀態會話bean所特有,也是用戶唯一可以能控制的生命周期方法,一旦用戶在客戶端調用此方法,容器將刪除bean實例。接著看客戶端的測試代碼:
          <%
                     InitialContext ctx 
          = new InitialContext();
                     HelloRemote helloBean 
          = (HelloRemote)ctx.lookup(HelloRemote.class.getName());
                     helloBean.init(
          "Tom");
                     out.println(helloBean.sayHi());
                     helloBean.remove();
          %>

          很簡單,只是多調用了一個remove方法。

          posted @ 2008-09-13 11:14 waynemao 閱讀(189) | 評論 (0)編輯 收藏

          EJB3 (6)

          Web服務客戶端可以通過bean的Web服務端點實現類來訪問無狀態會話Bean。在默認情況下,bean類中的所有公共方法對于Web服務客戶端都是可訪問的。@WebMethod注釋可以自定義Web服務方法,一旦在公共方法上使用該注釋,那么其他沒使用@WebMethod注釋的方法將不會對Web服務客戶端展現。
          首先新建一個EJB模塊,然后在EJB模塊上新建一個WebService,代碼如下:

          @WebService()
          @Stateless()
          public class Dog {
              
              @WebMethod(operationName 
          = "ganr")
              
          public String ganr() {
                  
          return "Wo-Wo-Wo";
              }


          }

          Dog類同時使用了@WebService和@Stateless注釋,web服務端點只能是無狀態會話bean,web服務本身就是無狀態的。我們還用@WebMethod注釋向Web服務客戶端公開了一個ganr方法,完成后打包部署。
          接著我們創建一個Web模塊,然后在Web項目上右鍵,選新建--Web服務客戶端,指定項目或者WSDL url。接著新建一個Servlet,然后右鍵調用Web服務操作,我們找到Dog服務的garn方法點確定,代碼自動生成:
          @WebServiceRef(wsdlLocation = "http://localhost:8080/DogService/Dog?wsdl")
              
          private DogService service;

          @WebServiceRef注釋聲明了一個到Web服務的引用
          try // Call Web Service Operation

                          ejb.Dog port 
          = service.getDogPort();
                          
          // TODO process result here
                          java.lang.String result = port.ganr();
                          out.println(
          "Result = " + result);
                      }
           catch (Exception ex) {
                          
          // TODO handle custom exceptions here
                      }

          service.getDogPort()方法獲取到服務的一個代理,也稱為端口。接著看jsp:
            <%
              
          try {
              ejb.DogService service 
          = new ejb.DogService();
              ejb.Dog port 
          = service.getDogPort();
              
          // TODO process result here
              java.lang.String result = port.ganr();
              out.println(
          "Result = "+result);
              }
           catch (Exception ex) {
              
          // TODO handle custom exceptions here
              }

              
          %>

          發現只有一點點不同,完成后部署web應用并運行測試。

          我們還可以通過一個現有的會話Bean創建Web服務,還是拿HelloWorld舉例,首先創建一個遠程接口:
          @Remote
          public interface HelloRemote {

              String sayHi(String name);
          }

          再創建一個無狀態會話bean,先已經說過了,只能是無狀態會話bean:
          @Stateless
          public class HelloBean implements HelloRemote {

              
          public String sayHi(String name) {
                  
          return "Hi " + name; 
              }

          }

          然后新建一個Web服務Hello,只不過在彈出窗口中要選中“通過現有會話bean創建Web服務”單選框,并瀏覽指定HelloBean,代碼自動完成:
          @WebService()
          @Stateless()
          public class Hello {
              @EJB
              
          private HelloRemote ejbRef;
              
          // Add business logic below. (Right-click in editor and choose
              
          // "Web Service > Add Operation"

              @WebMethod(operationName 
          = "sayHi")
              
          public String sayHi(@WebParam(name = "name")String name) {
                  
          return ejbRef.sayHi(name);
              }

          }

          我們看到Hello服務里引用了一個HelloRemote接口,并發現遠程接口公開的方法也被Hello服務公開,完成后打包部署EJB模塊。接著在Web服務客戶端測試,這和之前的步驟一樣,不再贅述,直接看代碼吧:
          @WebServiceRef(wsdlLocation = "http://localhost:8080/HelloService/Hello?wsdl")
              
          private HelloService service;

              
          protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                      
          throws ServletException, IOException {
                  response.setContentType(
          "text/html;charset=UTF-8");
                  PrintWriter out 
          = response.getWriter();
                  
          try {
                      
          try // Call Web Service Operation

                          ejb.Hello port 
          = service.getHelloPort();
                          
          // TODO initialize WS operation arguments here
                          java.lang.String name = "Tom";
                          
          // TODO process result here
                          java.lang.String result = port.sayHi(name);
                          out.println(
          "Result = " + result);
                      }
           catch (Exception ex) {
                          
          // TODO handle custom exceptions here
                      }

           

          <%
              
          try {
              ejb.HelloService service 
          = new ejb.HelloService();
              ejb.Hello port 
          = service.getHelloPort();
               
          // TODO initialize WS operation arguments here
              java.lang.String name = "Tom";
              
          // TODO process result here
              java.lang.String result = port.sayHi(name);
              out.println(
          "Result = "+result);
              }
           catch (Exception ex) {
              
          // TODO handle custom exceptions here
              }

              
          %>

          發現一個問題,一個應用上不能新建兩個Web服務客戶端(Dog和Hello),只有一個能有效使用(只找到一份工件),這是為什么?

          posted @ 2008-09-13 04:36 waynemao 閱讀(144) | 評論 (0)編輯 收藏

          WebService (1)

          新建web項目,然后創建一個WEB服務:

          @WebService()
          public class Hello {
              @WebMethod(operationName 
          = "sayHi")
              
          public String sayHi(@WebParam(name = "name")String name) {
                 
          return "Hi " + name;
              }

          }


          可以在源圖上右鍵,選Web服務--添加操作,也可以在設計圖上直接添加操作。@WebService標注表明該類是一個web服務,展現給web服務客戶端的業務方法必須使用@WebMethod標注來表示。打包部署該web應用,web服務自動會發布。可以在glassfish應用服務器上找到該web服務,直接測試或者查看服務器生成的WSDL

          <?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.3.1-hudson-417-SNAPSHOT. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.3.1-hudson-417-SNAPSHOT. -->
          <definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://webservice/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://webservice/" name="HelloService">
              
          <types>
                  
          <xsd:schema>
                      
          <xsd:import namespace="http://webservice/" schemaLocation="http://localhost:8080/WebServiceApp/HelloService?xsd=1">
                      
          </xsd:import>
                  
          </xsd:schema>
              
          </types>
              
          <message name="sayHi">
                  
          <part name="parameters" element="tns:sayHi">
                  
          </part>
              
          </message>
              
          <message name="sayHiResponse">
                  
          <part name="parameters" element="tns:sayHiResponse">
                  
          </part>
              
          </message>
              
          <portType name="Hello">
                  
          <operation name="sayHi">
                      
          <input message="tns:sayHi">
                      
          </input>
                      
          <output message="tns:sayHiResponse">
                      
          </output>
                  
          </operation>
              
          </portType>
              
          <binding name="HelloPortBinding" type="tns:Hello">
                  
          <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document">
                  
          </soap:binding>
                  
          <operation name="sayHi">
                      
          <soap:operation soapAction="">
                      
          </soap:operation>
                      
          <input>
                          
          <soap:body use="literal">
                          
          </soap:body>
                      
          </input>
                      
          <output>
                          
          <soap:body use="literal">
                          
          </soap:body>
                      
          </output>
                  
          </operation>
              
          </binding>
              
          <service name="HelloService">
                  
          <port name="HelloPort" binding="tns:HelloPortBinding">
                      
          <soap:address location="http://localhost:8080/WebServiceApp/HelloService">
                      
          </soap:address>
                  
          </port>
              
          </service>
          </definitions>


          也可以編寫客戶端測試,新建一個普通的java項目,在項目上右鍵,選擇新建--Web服務客戶端,在彈出窗口中指定WebService項目或者WSDL url,點擊完成。在源代碼上右鍵,選擇Web服務客戶端資源--調用Web服務操作,在彈出窗口中選擇sayHi操作,點確定,測試代碼自動生成:

          public class Main {

              
          public static void main(String[] args) {

                  
          try 

                      webservice.HelloService service 
          = new webservice.HelloService();
                      webservice.Hello port 
          = service.getHelloPort();
                      
                      java.lang.String name 
          = "Tom";
                      java.lang.String result 
          = port.sayHi(name);
                      System.out.println(
          "Result = " + result);
                  }
           catch (Exception ex) {
                      
          // TODO handle custom exceptions here
                  }

              }

          }

          運行該客戶端,結果將會輸出

          posted @ 2008-09-13 02:31 waynemao 閱讀(164) | 評論 (0)編輯 收藏

          oracle視頻

          oracle10g_1

          oracle10g_2

          oracle10g_3_1

          oracle10g_3_2

          oracle10g_4_1

          oracle10g_4_2

          oracle10g_5_1

          oracle10g_5_2

          oracle10g_6

          oracle10g_7_1

          oracle10g_7_2

          oracle10g_8

          oracle10g_9

          oracle10g_10

          oracle10g_11

          oracle10g_12

          oracle10g_13

          oracle10g_14

          posted @ 2008-09-13 01:01 waynemao 閱讀(162) | 評論 (0)編輯 收藏

          EJB3 (5)

          同一個會話bean也可以實現多個遠程接口,不過代碼上有些地方要注意,首先寫第一個接口:

          @Remote
          public interface HelloRemote {

              String sayHi(String name);
          }

          第二個接口:
          @Remote
          public interface HelloRemote1 {
              
              String sayBye(String name);
          }

          接下來寫會話bean,同時實現以上兩個接口:
          @Stateless(mappedName="hello")
          public class HelloBean implements HelloRemote, HelloRemote1 {

              
          public String sayHi(String name) {
                  
          return "Hi " + name; 
              }


              
          public String sayBye(String name) {
                  
          return "Bye " + name;
              }
              
          }

          注意這里用到了mappedName元素,這個很關鍵。把EJB模塊打包部署,接下來在遠程客戶端測試,先寫Servlet:
              @EJB(mappedName="hello#ejb.HelloRemote1")
              
          private HelloRemote1 helloBean1;
              @EJB(mappedName
          ="hello#ejb.HelloRemote")
              
          private HelloRemote helloBean;

          注意@EJB標注里也使用了mappedName元素,值的樣式是:JNDI名#包名.接口名。再看Jsp:
          <%
                      InitialContext ctx 
          = new InitialContext();
                      HelloRemote helloBean 
          = (HelloRemote)ctx.lookup("hello#ejb.HelloRemote");
                      out.println(helloBean.sayHi(
          "Tom"));
                      HelloRemote1 helloBean1 
          = (HelloRemote1)ctx.lookup("hello#ejb.HelloRemote1");
                      out.println(
          "<br>" + helloBean1.sayBye("Tom"));
          %>

          和Servlet中的一樣

          posted @ 2008-09-13 00:42 waynemao 閱讀(139) | 評論 (0)編輯 收藏

          EJB3 (4)

          如果一個遠程接口有兩個實現,需要用mappedName來區分
          首先定義一個遠程接口:

          @Remote
          public interface HelloRemote {

              String sayHi(String name);
          }


          第一個實現:
          @Stateless(mappedName="hello")
          public class HelloBean implements HelloRemote {

              
          public String sayHi(String name) {
                  
          return "Hi " + name; 
              }

          }

          第二個實現:
          @Stateless(mappedName="hello2")
          public class HelloBean2 implements HelloRemote{

              
          public String sayHi(String name) {
                  
          return "Hello " + name;
              }


          }

          兩個無狀態會話bean實現了同一個遠程接口,但它們的mappedName不一樣,還有它們各自重寫了sayHi業務方法。部署EJB模塊然后測試,首先是Servlet:
              @EJB(mappedName="hello2")
              
          private HelloRemote helloBean2;
              @EJB(mappedName
          ="hello")
              
          private HelloRemote helloBean;

          然后是JSP:
          <%
                      InitialContext ctx 
          = new InitialContext();
                      HelloRemote helloBean 
          = (HelloRemote)ctx.lookup("hello");
                      out.println(helloBean.sayHi(
          "Tom"));
                      HelloRemote helloBean2 
          = (HelloRemote)ctx.lookup("hello2");
                      out.println(
          "<br>" + helloBean2.sayHi("Tom"));
          %>

          呵呵,遠程調用也實現了多態

          posted @ 2008-09-13 00:21 waynemao 閱讀(173) | 評論 (0)編輯 收藏

          EJB3 - Session bean

          EJB3 - Session bean

          description

          其實session bean是最一開始就看的, 回過頭來看再記重點有點心浮氣躁.

          reference

          EJB3 in Action - CH3 - Building business logic with session beans

          Focal Points

        1. session bean一定要有一個以上的interface與一個實現
        2. 一個session bean可以有多個interface, 所以當客戶端調用一個@Local的interface, 就是使用local的session bean. 使用@Remote或@WebService就是用remote或web service的session bean.
        3. session bean一定要是concrete class, 一定要有無參構造函數, 不能是abstract或final.
        4. session bean可以是其他session bean或POJO的subclass.
        5. session bean的business method與lifecycle callback可定在super class或session bean class裡.
        6. session bean的annotation的繼承是有條件的, 就是class level比方說@Stateless, @Stateful會被忽略, 不過lifecycle callback會被繼承下來.
        7. session bean的business method name不能以ejb開頭, 比方說不能是ejbDoit()
        8. session bean的method必須是public且不能是static或final
        9. 使用一個remote business interface要注意argument與return type必須實作Serizable
        10. 所有session bean都有的生命週期是creation / destruction
        11. stateful bean比stateless bean又多了passivation / activation
        12. stateless bean的lifecycle callback為@PostConstruct, @PreDestroy
        13. stateful bean的lifecycle callback為@PostConstruct, @PreDestroy, @PostActivate, @PrePassivate
        14. @PostConstruct, @PreDestroy比較簡單.就是container實例化session bean後調用@PostContruct, container移除session bean前會調用@PreDestroy
        15. @PostActivate, @PrePassivate比較特別.  一旦container判斷一個stateful bean停用了而決定要暫時讓這個session bean失去效用, 這個動作叫鈍化. 而container讓已經失效的stateful bean再度生效就叫激活. 所以@PostActivate就是activation後調用的method, @PrePassivate就是鈍化前呼叫的method.
        16. lifecycle callback可以是public, private, protected, package-protected
        17. lifecycle callback主要用來替session bean準備實例化後需要的資源以及從container移除前要釋放的資源.
        18. lifecycle callback除了放在session bean以外也可放在分開的interceptor class
        19. stateless session bean有pool, 也就是說有一定數量的stateless session bean在container的pool中
        20. @Stateless的定義
          1. 屬性有name, mappedName, description
          2. name屬性用來指定bean的name, 有的container用來和JNDI綁定. 如果name沒有設定就會是bean的class name.
          3. mappedName是vender-specific(特定于廠商), 也就是依不同container有不同的情形. 以GlassFish來說是將mappedName的值綁定到JNDI name.
        21. @Local: stateless session bean的local interface, local interface表示這個session bean和client放在同一個JVM上執行.
        22. @Remote: 當client存在於container外的JVM時就必須使用@Remote
          1. 一個@Remote interface可以繼承java.rmi.Remote
             public interface TestRemote extends Remote { ... } 
            就算程序裡面沒寫繼承Remote, container還是會在byte code階段插入繼承Remote的動作
          2. 沒有程序上繼承java.rmi.Remote的好處就是不用處理java.rmi.RemoteException
          3. @Remote business interface有個需求就是所有的參數與回傳值都必須是Serializable, 因為這樣才能通過RMI
        23. @WebService: 透過@WebService可讓session bean成為SOAP-based web service. 唯一要做的就是在interface上加上@WebService.
        24. 不能讓一個business interface同時@Local又@Remote或是又@WebService, 不過可以透過interface的繼承改變要使用的是@Remote session bean還是@Local的 session bean.
        25. 放session bean的lifecycle callback
        26. 可以有多個@PostConstruct, @PreDestroy (不過我試起來一個session bean就只能一個lifecycle callback有效, 頂多除了callback以外還指定interceptor, 就加上interceptor的一個lifecycle callback有效.)
        27. lifecycle callback要符合pattern: void < METHOD >()
        28. interceptor內的lifecycle callback要符合pattern: Object < METHOD >(InvocationContext) throws Exception, 然後記得回傳InvocationContext.proceed, 除非打算不繼續執行. (可參考EJB3 Interceptor)
        29. session bean的lifecycle callback不可有checked exception, interceptor的則可以.
        30. session bean的lifecycle callback不可有傳入參數, interceptor則要傳入InvocationContext, 否則有java.lang.IllegalArgumentException: wrong number of arguments
        31. stateless session bean與stateful session bean的差別主要在於container管理的方式, stateless session bean起始之後會被container放進pool, 等client要使用的時候再從pool取出, 用完再放回pool. stateful session bean則是讓一個client擁有一個stateful session bean直到client離開或stateful session bean destroy為止. stateful session bean與client是one to one的關係.
        32. stateful session bean需要付出代價, stateless session bean由於所有client共用session bean比較能節省資源, stateful session bean則因為與client是one to one的關係所以比較耗資源. 一旦container判斷消耗資源太多或佔用資源太久就會開始執行passivate的動作.
        33. 由於stateful session bean比較耗資源, 所以注意要在stateful session bean加上@Remove method, 當呼叫此method, container就會負責將此method destroy以節省資源.
        34. 由於stateful session bean在passivate的時候會做serialize的動作, 所以注意stateful session bean的class 成員必須實做Serializable或必須是原始類型. 否則在passivate的時候會出現例如[NRU-stateful.SimpleStatefulBean]: passivateEJB(), Exception caught 的exception, 就是因為無法serialize該object的關係. 如果要使用不須serialize的class 成員只要用transient聲明該class member或在@PrePassivate把class member改成null再於@PostActivate設定回來即可.
        35. 使用stateful session bean的方式幾乎和stateless session bean的方式幾乎一樣, 唯一不一樣的是stateful session bean的business interface只能使用@Local與@Remote而不能用@WebService. 因為SOAP-based web Service本來就不是stateful因此無法使用.
        36. stateful session bean的生命週期中有重要的一點就是container在destroy一個passivate的時候會先將該stateful session bean先activate再passivate.
          @Stateful(name="SimpleStatefulBean", mappedName="ejb/SimpleStatefulBean")
          public class SimpleStatefulBean implements SimpleStatefulRemote {
          private Logger logger = Logger.getLogger("SimpleStatefulBean");
          private byte[] b = new byte[100000];
          {
          for ( int i = 0; i < b.length; i++ ) {
          b[i] = (byte) 100;
          }
          }
          public String simpleShow() {
          return this + ":This is simple show" + b;
          }
          @PostConstruct
          public void postConstruct() {
          logger.info("create " + this);
          }
          @PreDestroy
          public void preDestroy() {
          logger.info("destroy " + this);
          }
          @PostActivate
          public void postActivate() {
          logger.info("activate " + this);
          }
          @PrePassivate
          public void prePassivate() {
          logger.info("passivate " + this);
          }
          @Remove
          public void remove() {
          logger.info("remove " + this);
          }
          }
          
          放interceptor的lifecycle callback
          @Stateless
          @Interceptors(value={SimpleInterceptor.class})
          public class SimpleStatelessBean implements SimpleStatelessLocal {
          private Logger logger = Logger.getLogger("SimpleStatelessBean");
          @Resource(name="TestQueueConnectionFactory")
          private ConnectionFactory connectionFactory;
          @Resource(name="jms/TestQueueDestination")
          private Destination destination;
          public String simpleShow() {
          try {
          Connection conn = connectionFactory.createConnection();
          Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
          MessageProducer messageProducer = session.createProducer(destination);
          TextMessage message = session.createTextMessage();
          message.setText("This is text message");
          messageProducer.send(message);
          messageProducer.close();
          session.close();
          conn.close();
          } catch (JMSException ex) {
          throw new RuntimeException( ex );
          }
          return this + ":This is simple show";
          }
          }
          public class SimpleInterceptor {
          Logger logger = Logger.getLogger("SimpleStatefulBeanInterceptor");
          @PostConstruct
          public void onCreate(InvocationContext ic) {
          try {
          logger.info("create " + this);
          ic.proceed();
          } catch (Exception ex) {
          Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex);
          }
          }
          @AroundInvoke
          public Object aroundInvoke(InvocationContext ctx) throws Exception {
          logger.info(ctx + " is invoked.");
          return ctx.proceed();
          }
          @PreDestroy
          public void onDestroy(InvocationContext ic) {
          try {
          logger.info("destroy " + this);
          ic.proceed();
          } catch (Exception ex) {
          Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex);
          }
          }
          }
          
          stateful bean的@PrePassivate, @PostActivate也可放interceptor
          @Interceptors(value={SimpleInterceptor.class})
          @Stateful(name="SimpleStatefulBean", mappedName="ejb/SimpleStatefulBean") public class SimpleStatefulBean implements SimpleStatefulRemote { private byte[] b = new byte[100000]; { for ( int i = 0; i < b.length; i++ ) { b[i] = (byte) 100; } } public String simpleShow() { return this + ":This is simple show" + b; } @Remove public void remove() { Logger.getLogger("SimpleStatefulBean").info("remove " + this); } } public class SimpleInterceptor { @PostConstruct public void onCreate(InvocationContext ic) { try { Logger.getLogger(SimpleInterceptor.class.getName()).info("create " + this); ic.proceed(); } catch (Exception ex) { Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex); } } @PostActivate public void onActivate(InvocationContext ic) { try { Logger.getLogger(SimpleInterceptor.class.getName()).info("activate " + this); ic.proceed(); } catch (Exception ex) { Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex); } } @PrePassivate public void onPassivate(InvocationContext ic) { try { Logger.getLogger(SimpleInterceptor.class.getName()).info("passivate " + this); ic.proceed(); } catch (Exception ex) { Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex); } } @AroundInvoke public Object aroundInvoke(InvocationContext ctx) throws Exception { Logger.getLogger(SimpleInterceptor.class.getName()).info(ctx + " is invoked."); return ctx.proceed(); } @PreDestroy public void onDestroy(InvocationContext ic) { try { Logger.getLogger(SimpleInterceptor.class.getName()).info("destroy " + this); ic.proceed(); } catch (Exception ex) { Logger.getLogger(SimpleInterceptor.class.getName()).log(Level.SEVERE, null, ex); } } }
        37. @EJB用來注入session bean到client code. @EJB有幾個屬性: name, beanInterface, beanName. name用來指定JNDI name, beanName則是當一個interface有兩個實作時用來決定要注入哪個實作.
        38. 使用@EJB注入的時候如果沒有指定JNDI name, container就會用interface name當成JNDI name注入.
        39. 如果要注入同個interface不同的實作可透過指定JNDI name或beanName
          @Stateless(name="SimpleStatelessBean1")
          public class SimpleStatelessBean1 implements SimpleStatelessLocal { ... }
          @Stateless(name="SimpleStatelessBean2")
          public class SimpleStatelessBean2 implements SimpleStatelessLocal { ... }
          public class SimpleStatelessServlet extends HttpServlet {
          @EJB(beanName="SimpleStatelessBean1")
          private SimpleStatelessLocal simpleStatelessLocal1;
          @EJB(beanName="SimpleStatelessBean2")
          private SimpleStatelessLocal simpleStatelessLocal2;
          ...
          }
          
        40. 可注入stateless bean或stateful bean到其他的stateful bean. 但不能注入stateful bean到stateless bean, 因為這樣stateful session bean就會被所有client分享.
        41. 注入stateful bean到另一個stateful bean時, 一旦持有注入的stateful bean destroy了, 被持有的stateful bean也會一起destroy.
        42. 如果不用stateful bean可將狀態放在DB中或放在server side的檔案或放HttpSession, 不過要注意清除不必要的資源.
        43. 儲存conversation state的時候要注意儲存的值愈小愈好, 例如primitive.
        44. stateful bean要記得定義@Remove method.
        45. 調整server到stateful bean效能最佳的狀態, 小心頻繁的passivate / activate造成效能變差太多.
        46. posted @ 2008-09-12 23:19 waynemao| 編輯 收藏

          EJB3 (3)

          我想在遠程對象中調用本地對象,我嘗試這樣編寫代碼,首先創建一個本地接口:
          @Local
          public interface MessageLocal {

              String getMessage();
              
          }

          接著編寫一個會話bean實現該接口:
          @Stateless
          public class MessageBean implements MessageLocal {

              
          public String getMessage() {
                  
          return "Hello world";
              }

              
          }

          然后創建一個遠程接口:

          @Remote
          public interface HelloRemote {

              String welcome();
              
          }

          編寫一個會話bean實現該接口:
          @Stateless
          public class HelloBean implements HelloRemote {
              @EJB
              
          private MessageLocal messageBean;

              
          public String welcome() {
                  
          return messageBean.getMessage();
              }

              
          }

          在遠程對象里聲明了一個本地接口的引用,并嘗試在遠程方法當中調用本地接口的本地方法。這些都沒問題,打包部署成功。
          <%
                      InitialContext ctx 
          = new InitialContext();
                      HelloRemote helloBean 
          = (HelloRemote)ctx.lookup(HelloRemote.class.getName());
                      out.println(helloBean.welcome());
          %>

          在遠程客戶端的代碼如此,看起來一切正常,不過在部署WEB模塊的時候報異常:正在域中部署應用程序 失敗;為模塊 [EjbWebClient] 裝入部署描述符時出錯 -- Cannot resolve reference Unresolved Ejb-Ref ejb.HelloBean/messageBean@jndi: @null@ejb.MessageLocal@Session@null

          posted @ 2008-09-12 22:24 waynemao 閱讀(231) | 評論 (0)編輯 收藏

          EJB3 (2)

          一個會話bean即可以遠程訪問,也可以本地訪問,盡管這種現象不常見。
          我們先定義遠程接口:

          @Remote
          public interface HelloRemote {

              String sayHi(String name);

              String sayByeBye(String name);
              
          }

          接著定義本地接口:
          @Local
          public interface HelloLocal {

              String sayBye(String name);
              
          }

          然后編寫一個會話bean同時實現兩個接口:
          @Stateless
          public class HelloBean implements HelloRemote, HelloLocal {

              
          public String sayHi(String name) {
                  
          return "Hi " + name;
              }

              
              
          public String sayBye(String name) {
                  
          return "Bye " + name;
              }

              
              
          public String sayByeBye(String name) {
                  
          return sayBye(name);
              }

              
          }

          那么,這還是一個無狀態會話bean,不過即可以遠程訪問,也可以本地訪問。
          <%
                      InitialContext ctx 
          = new InitialContext();
                      HelloRemote helloBean 
          = (HelloRemote)ctx.lookup(HelloRemote.class.getName());
                      out.println(helloBean.sayHi(
          "Tom"));
                      out.println(
          "<br>" + helloBean.sayByeBye("Tom"));
          %>

          遠程訪問只能獲得遠程接口的代理,然后調用遠程業務方法。在遠程客戶端是無法獲得本地接口的引用,更別說訪問本地方法了。

          posted @ 2008-09-12 21:29 waynemao 閱讀(140) | 評論 (0)編輯 收藏

          EJB3 (1)

          新建一個EJB模塊
          先寫一個最簡單的無狀態Session Bean,首先定義一個遠程接口:

          @Remote
          public interface HelloRemote {

              String sayHi(String name);
              
          }
          用@Remote標注表明這是一個遠程接口,在接口里聲明一些業務方法。接著定義一個會話Bean實現該接口:
          @Stateless
          public class HelloBean implements HelloRemote {

              
          public String sayHi(String name) {
                  
          return "Hi " + name;
              }

              
          }

          @Stateless標注表明這是一個無狀態會話Bean,完成了這個簡單的Demo后,打包部署到服務器上。接著我們來測試這個會話Bean,新建一個WEB模塊,我們利用這個web應用來遠程調用會話Bean。我們可以在web模塊里新建一個Servlet:
          public class HelloServlet extends HttpServlet {
              @EJB
              
          private HelloRemote helloBean;
          在Servlet里定義了一個成員變量,@EJB標注表明遠程接口的代理將依賴注入到成員變量,在doGet或doPost方法里可以直接使用該代理調用會話Bean的業務方法:
          PrintWriter out = response.getWriter();
                  
          try {
                     out.println(helloBean.sayHi(
          "Tom"));
                  }
           finally 
                      out.close();
                  }
          JSP卻有所不同,這里不能使用@EJB標注,要使用傳統的JNDI lookup方式:
          <%
                      InitialContext ctx 
          = new InitialContext();
                      HelloRemote helloBean 
          = (HelloRemote)ctx.lookup(HelloRemote.class.getName());
                      out.println(helloBean.sayHi(
          "Tom"));
          %>

          這個測試用web模塊已經完成,將WEB模塊打包部署后即可以運行
          不過,如果我們自己指定了會話Bean的JNDI名,那么以上的測試代碼將發生異常,例如:
          @Stateless(mappedName="hello")
          public class HelloBean implements HelloRemote {

              
          public String sayHi(String name) {
                  
          return "Hi " + name;
              }

              
          }

          這里我們指定了會話bean的JNDI名為"hello",更改后的EJB模塊需要重新部署,還要更改相應的Servlet和Jsp中的代碼:
          @EJB(mappedName="hello")
              
          private HelloRemote helloBean;

          Servlet已經更改了,只有一點點不同。
          <%
                      InitialContext ctx 
          = new InitialContext();
                      HelloRemote helloBean 
          = (HelloRemote)ctx.lookup("hello");
                      out.println(helloBean.sayHi(
          "Tom"));
                  
          %>

          Jsp也做了小小的改動,如此更新后重新部署WEB模塊,測試代碼即可順利運行

          posted @ 2008-09-12 20:49 waynemao 閱讀(113) | 評論 (0)編輯 收藏

          My Links

          Blog Stats

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          default

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 怀远县| 新乐市| 平罗县| 义马市| 镇平县| 芒康县| 湘潭县| 汤阴县| 汉沽区| 唐海县| 景德镇市| 田东县| 丰宁| 大厂| 绵竹市| 伊宁市| 新和县| 阿克| 北流市| 古丈县| 如皋市| 屯门区| 贵定县| 丹阳市| 同仁县| 新泰市| 珲春市| 桃园县| 宜章县| 台东县| 玉山县| 瑞丽市| 综艺| 崇明县| 吉安县| 衡阳县| 仁怀市| 西藏| 无极县| 阳曲县| 乌兰察布市|