那么用有状态的session bean不是那么可靠了
sun还说什么用来做购物车,如果超时了都不知道怎么回事

解决方案 »

  1.   

    有状态会话 Bean 只保存短暂的数据 
    当用户终止与Session beans互操作的时候.会话终止了
    所以用户不操作又想长时间保存是不现实的
    然后被抛弃 
    钝化/激活只是容器管理其状态的方法 回收条件:
    超时 (无论是激活的或钝化的) 
    被调用 remove() 
      

  2.   

    Http session 超时我是能判断出来的
    可是session bean超时呢,我只能接受到一个RemoteException,我怎么知道它是由超时引起的呢RMI和无状态session bean呢,我从JNDI上得到一个引用,过了很长时间才用,会不会出错?
    比如我把JNDI上找到的Home接口的引用缓存起来,避免每次都要查找JNDI,Home接口的引用会不会超时?
      

  3.   

    Service Locator模式可以解决你的问题
    在本地为需要的jndi引用做一个cache,需要时从cache 里面取,如果cache中坏了或没有就再创建,用完了放回cache中
      

  4.   

    抱歉刚才有翻了一下《使用J2EE设计模式编程指南》,它好象没有考虑会发生引用损坏的情况,是否不会有损坏这种情况呢?(因为它毕竟只是一个接口),思考中....我待会儿把代码发上来给你参考
      

  5.   

    package dataaccess;import java.sql.*;
    import javax.sql.DataSource;
    import java.util.Hashtable;
    import javax.naming.*;
    import javax.ejb.*;
    import javax.rmi.PortableRemoteObject;
    import session.counter.CounterHome;
    import session.title.TitleDAOHome;
    import session.editor.EditorDAOHome;/*
     *  The ServiceLocator pattern is abstracts away the JNDI
     *  logic necessary for retrieving a JDBC Connection or EJBHome 
     *  interface
     */
    public class ServiceLocator{
      private static ServiceLocator serviceLocatorRef = null;
      private static Hashtable      ejbHomeCache      = null;
      private static Hashtable      dataSourceCache   = null;  /*Enumerating the different services available from the Service Locator*/
      public static final int COUNTER        = 0;
      public static final int TITLEDAO       = 1;
      public static final int EDITORDAO      = 2;
      public static final int SUBSCRIPTIONDB = 3;  /*The JNDI Names used to lookup a service*/
      private static final String COUNTER_JNDINAME="counter/Counter";
      private static final String TITLEDAO_JNDINAME="title/TitleDAO";
      private static final String EDITORDAO_JNDINAME="editor/EditorDAO";
      private static final String SUBSCRIPTIONDB_JNDINAME="jdbc/subscriptionDS";  /*References to each of the different EJB Home Interfaces*/
      private static final Class COUNTERCLASSREF = CounterHome.class;
      private static final Class TITLECLASSREF   = TitleDAOHome.class;
      private static final Class EDITORCLASSREF  = EditorDAOHome.class;  static {
        serviceLocatorRef = new ServiceLocator();
      }  /*Private Constructor for the ServiceLocator*/
      private ServiceLocator(){
        ejbHomeCache    = new Hashtable();
        dataSourceCache = new Hashtable();
      }  /*
       * The ServiceLocator is implemented as a Singleton.  The getInstance()
       * method will return the static reference to the ServiceLocator stored
       * inside of the ServiceLocator Class.
       */
      public static ServiceLocator getInstance(){
        return serviceLocatorRef;
      }  /*
       * The getServiceName will retrieve the JNDI name for a requested
       * service.  The service is indicated by the ServiceId passed into
       * the method.
       */
      static private String getServiceName(int pServiceId)
        throws ServiceLocatorException{
        String serviceName = null;
        switch (pServiceId){
          case COUNTER:          serviceName = COUNTER_JNDINAME;
                         break; 
          case TITLEDAO:         serviceName = TITLEDAO_JNDINAME;
         break;
          case EDITORDAO:        serviceName = EDITORDAO_JNDINAME;
         break;
          case SUBSCRIPTIONDB:   serviceName = SUBSCRIPTIONDB_JNDINAME;
         break;
          default:               throw new ServiceLocatorException(
         "Unable to locate the service requested in " +
         "ServiceLocator.getServiceName() method.  ");
        }
        return serviceName;
      }  /*
       * Returns the EJBHome Class reference for a requested service.
       * If the method can not make a match, it will throw a ServiceLocatorException
       * .
       */
      static private Class getEJBHomeRef(int pServiceId) 
        throws ServiceLocatorException{
        Class homeRef = null;
        switch (pServiceId){
          case COUNTER:          homeRef = COUNTERCLASSREF;
                         break; 
          case TITLEDAO:         homeRef = TITLECLASSREF;
         break;
          case EDITORDAO:        homeRef = EDITORCLASSREF;
         break;
          default:               throw new ServiceLocatorException(
         "Unable to locate the service requested in " +
         "ServiceLocator.getEJBHomeRef() method.  ");
        }
        return homeRef;
      }  /*
       * The getEJBHome method will return an EJBHome interface for a requested
       * service.  If it can not find the requested EJB, it will throw a
       * servicelocator exception.
       *
       * The getEJBHome interface caches a requested EJBHome so that the first 
       * time an EJB is requested, a home interface will be retrieved but then
       * be placed into a cache.
       *
       */
      public EJBHome getEJBHome(int pServiceId)
        throws ServiceLocatorException{
       
          /*Trying to find the JNDI Name for the requested service*/
           String serviceName = getServiceName(pServiceId);
           EJBHome ejbHome    = null;    try{
          /*Checking to see if I can find the EJBHome interface in cache*/
          if (ejbHomeCache.containsKey(serviceName)){
            ejbHome = (EJBHome) ejbHomeCache.get(serviceName);
    return ejbHome;
          }
          else{
            /*
     * If I could not find the EJBHome interface in the cache, look it
     * up and then cache it.
     * */
    Context ctx = new InitialContext();
            Object jndiRef     = ctx.lookup(serviceName);        Object portableObj = 
              PortableRemoteObject.narrow(jndiRef, getEJBHomeRef(pServiceId));        ejbHome = (EJBHome) portableObj;        ejbHomeCache.put(serviceName, ejbHome);
    return ejbHome;
          }
      }
        catch(NamingException e){
          throw new ServiceLocatorException("Naming exception error in ServiceLocator.getEJBHome()" ,e);
        }
        catch(Exception e){
          throw new ServiceLocatorException("General exception in ServiceLocator.getEJBHome",e);
        }
      
      }  /*
       * The getDBConn() method will create a JDBC connection for the
       * requested database.  It too uses a cachin algorithm to minimize
       * the number of JNDI hits that it must perform.
       */
      public Connection getDBConn(int pServiceId)
        throws ServiceLocatorException{
         /*Getting the JNDI Service Name*/
        String     serviceName = getServiceName(pServiceId);
         Connection conn        = null;
        try{
          /*Checking to see if the requested DataSource is in the Cache*/ 
          if (dataSourceCache.containsKey(serviceName)){
    DataSource ds = (DataSource) dataSourceCache.get(serviceName);
                conn = ((DataSource)ds).getConnection();

    return conn;
          }
          else{
    /*
     * The DataSource was not in the cache.  Retrieve it from JNDI
     * and put it in the cache.
     */
    Context ctx = new InitialContext();
            DataSource newDataSource = (DataSource) ctx.lookup(serviceName);
      dataSourceCache.put(serviceName, newDataSource);
      conn = newDataSource.getConnection();
      return conn;
          }
        }
        catch(SQLException e){
          throw new ServiceLocatorException("A SQL error has occurred in " +
                            "ServiceLocator.getDBConn()", e);
        }
        catch(NamingException e){
          throw new ServiceLocatorException("A JNDI Naming exception has occurred "+ 
                                " in ServiceLocator.getDBConn()" , e);
        }
        catch(Exception e){
    throw new ServiceLocatorException("An exception has occurred "+
                            " in ServiceLocator.getDBConn()"  ,e);
        }
      }
    }
      

  6.   

    书上的例子往往比较简单,只关注于它的知识点
    然而我们要做出健壮的程序就必须考虑到各种问题引用肯定是会失效的,比如远程服务器重启了
    不知道的是如果服务器没有重启动的化,我一直保留引用是否可以,服务器怎么知道客户端是否还在引用某个对象?如果引用失效,在引用上调用方法会有RemoteException,但是引起RemoteException的原因很多,我怎么知道是引用失效引起的呢,这时怎么从错误中恢复?
      

  7.   

    远程服务器重启是比较极端的例子,不过你可以不管是什么原因引起的失效,只要从cache里面得到的引用无法用,你就重新创建一个引用,用完放入cache中,如果这个新创建的引用都没法用,就是程序本身的问题而和会话失效无关了
      

  8.   

    》只要从cache里面得到的引用无法用
    我怎么知道它无法用,我只受到一个远程异常而已,这也可能是因为数据库异常或是短暂的IO异常引起的
    我怎么知道应该去新建一个引用呢
      

  9.   

    我有一个自已做的session bean 。在超时十分钟后自动断开。。在客户端保存数据。。需要的发我eamil:[email protected]  交流交流
      

  10.   

    得到home接口Handle存起来(Serialization),用的时候再create()
      

  11.   

    (流浪的风) 你没有理解我的意思
    我的意思是:

    》只要从cache里面得到的引用无法用
    我怎么知道它无法用,我只是在引用上调用方法的时候受到一个远程异常而已,这也可能是因为数据库异常或是短暂的IO异常引起的,也可能是引用超时。按你的说法,引用超时应该新建,不过运行时我的程序怎么知道是引用超时而不是SQL错误并且去新建一个引用呢