wayne

          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 on 2008-09-12 23:19 waynemao 閱讀(440) 評論(0)  編輯  收藏 所屬分類: Java ee

          My Links

          Blog Stats

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          default

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 巨野县| 凭祥市| 电白县| 宁蒗| 吴旗县| 湘阴县| 房产| 沧州市| 徐州市| 文成县| 崇义县| 叶城县| 泽普县| 时尚| 景宁| 和政县| 哈巴河县| 探索| 西和县| 阳新县| 上虞市| 冀州市| 久治县| 鹤壁市| 黄骅市| 贞丰县| 天台县| 青海省| 潍坊市| 疏勒县| 中牟县| 乌审旗| 和平县| 上杭县| 平乐县| 巴里| 青阳县| 治县。| 运城市| 静海县| 屏东市|