[转帖]使用EJB来访问持久性数据,共享session_Tomcat, WebLogic及J2EE讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Tomcat, WebLogic及J2EE讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3301 | 回复: 0   主题: [转帖]使用EJB来访问持久性数据,共享session        下一篇 
赖文婷
注册用户
等级:少校
经验:1094
发帖:81
精华:0
注册:2012-11-5
状态:离线
发送短消息息给赖文婷 加好友    发送短消息息给赖文婷 发消息
发表于: IP:您无权察看 2012-11-12 11:02:24 | [全部帖] [楼主帖] 楼主

问题:

我们需要这样一种J2EE应用,那就是具有相同用户id的客户端需要共享维持在服务器端的会话数据。除此之外,客户端并不仅仅是Web客户,也是applet和其他程序。我们怎样来实现它呢?

解决办法:

这是一个在编写J2EE应用程序时遇到的典型问题,因为J2EE API不能为之提供一种开箱即用的解决办法。

Servlet API通常使用Web客户所提供的较好方式来处理客户之间的会话及相关数据,但是不能为客户之间会话数据的共享提供一条直接的途径(出于安全原因)。仅对Web客户来说它也有些限制。

相反,Enterprise Java Beans (EJBs)就很容易做到这一点,因为他们能与任何类型的Java客户端一起工作。这看起来可能较复杂,但是在程序上看来是非常浅显易懂的。下面我们就来仔细分析一下。

我们很容易想到一个无状态会话 EJB,因为它能在服务器端保持客户机的状态。在客户会话之间的会话 EJB(或是他们的实例)也是可共享的,就像servlet一样,他们通过在应用程序中传送引用给客户机(或者给他们的远程接口)来实现这种共享。为了在会话之间传输引用,应用程序需要显式地为每个不同的客户机维持一个引用查询表,因此它需要知道把用户(及用户id)与一个已经存在的会话 EJB的合适实例相关联。

可是,当使用实体 EJBs时这些就需要WLS来做了 - 或者在这种情况下至少它们所做的有很多相似性。它能对存储器中实例化的每个实体EJB保持引用,然后再将它(或者对EJB的远程接口的引用)传送给客户机,这需要调用Home Interfacebean findByPrimaryKey方法。如果由于实体EJB根本不存在而找不到它的话,为与客户机和客户第一次登录时的会话相关联,它可以动态建。因此,实体EJB实例是很容易被共享的,即使是那些不在同一JVM中运行的客户机之间的实体EJB也是如此。

注意:一个实体EJB 实例通常不指数据库中的一行,它可以完全是虚拟的。但是因为实体EJB特别擅长于访问持久性数据,因此,万一遇到应用程序崩溃等情况,它也能提供一个保持会话(以及会话中的数据)的机会。

为了查找客户的会话引用,使用findByPrimaryKey方法是合理的,因为主键实际上是用户在此应用程序中的用户id。接下来应用程序唯一需要做的是,在客户们通过beanfindByPrimaryKey方法访问会话数据之前,对客户进行适当的身份验证。

创建示例应用程序

现在我们准备设计一个示例应用程序。首先,我们把应用程序分为四个部分:

1. UserSession:此类包含了保存在Hashtable里的用户会话数据以及一些别的信息如用户的用户id。为保持会话数据的持久性它使用Serializer类(见下面)。UserSession 类首先在本地被使用,然后通过实体EJB “包装器”很容易地被多种类型的多个客户(如JSP Java 客户等)远程进行共享。

2. UserSessionSerializer:此类用于维持会话数据的持久性。为了使此过程尽可能地简单,第一步需要用使用Java序列化来代替JDBC。接下来,对分布式大规模应用程序使用基于JDBC的面向池的持久性技术。每个会话(即使由多个客户所共享)通常有一个磁盘上的文件和一个访问它的EJB 实例。

3. EJB 包装器:用于分布式UserSession对象。它是UserSession的一个子类。作为一个实体EJB,它由sharedSessionSample.remote包中的三个独立的类所组成(别的存储在“local”包中)。

4. 示例 JSP客户端:使用SessionData对象,首先本地使用,然后远程使用。

接下来,我们创建一个名为sharedSession-Sample.local的包,并且把两个类放在其中:UserSession类和UserSessionSerializer类。UserSession类有三个类成员(变量)和方法:

Members: protected String path;
protected String userId;
protected Hashtable sessionData;
Methods (the throw definitions are not shown):   public void create(String userId)
public void load(String userId)
public void save()         public void remove()         public Object getValue(String name)         public void setValue(String name, Object object)         public void removeValue(String name)         public Hashtable getValues()         public void setValues(Hashtable values)


类成员路径定义了序列化会话存储及装载地址的目录。通常这个路径对于所有会话都是相同的。用户id定义了会话的所有者,并且被用于在序列化时命名文件(如一个会话用户“John”将被序列化为名为“John.session”的文件,存储在特定目录的磁盘上)。注意:序列化时我们实际上不存储整个 UserSession ,只存储sessionData成员对象。

Getters Setters

方法构建出来以后,能够很容易被扩展成作为一个实体EJB来工作。create()方法用来创建一个新的、空的会话,这个会话通过setterssetValue() setValues()方法被赋予一个或多个值后,通过save()方法所保存。这些setters之间的区别是显而易见的:前者当时设定了一个指定的值,然而后者为会话设定了所有的值(作为Hashtable来传递)。这些对于gettersgetValue()getValues()方法也是一样的。load()方法用于装载一个现有的会话以及来自磁盘的数据,并且在没找到会话的情况下(在这种情况下,会话可能会被创建),抛出一个异常,这与create()方法是相反的,create()方法是当会话已经存在的情况下抛出一个异常。

setters不能自动执行save()方法;save()方法必须显式地由客户来调用。可是,这一点对于实体EJB来说可以实现。

需要注意的是UserSession通过这种方式来执行,以至于getValues()方法和setValues()方法是“按值传递”而不是“按引用传递”来进行工作。在这里,这是一种首选的方法,它避免了在JSP上的会话数据的无意识的变化(我看到这种情况已经发生了很多次了,并且它还带有如Hashtable这样的对象)。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论