java 共享对象_J2EE组件间共享对象技术

本文深入探讨了在J2EE环境中,如何在页面、请求、会话和应用程序级别设置和访问共享对象,以及如何处理多线程问题。详细分析了四种共享对象的生命周期和访问模式,提供了实例代码展示如何在Servlet和JSP中实现对象共享。同时,文章强调了在多线程环境下同步共享对象的重要性,并提出了相应的解决方案。
摘要由CSDN通过智能技术生成

想要用好Struts应用框架,必须了解J2EE Web级JSP和Servlet技术存放共享对象的几种方式。同时,要利用J2EE 开发Web应用程序也必须掌握组件间对象共享的机制。

像Java程序有类级别变量、方法级别变量一样,J2EE Web应用程序有四个对象存放共享对象。这些共享对象存放在那里,以便存放者或者其它程序代码日后使用。这四个对象分别是页面、请求、会话和应用程序,它们都是以数据结构键/值对的形式保存的。同时这四个对象形成了四个级别的共享对象存放地,即应用程序对象中的共享对象是全局性的,在整个应用程序的生命周期内有效(当然主动去掉除外),属于所有的上网用户;会话对象中的共享对象是在一个会话期内有效,属于用户的当前会话;请求对象中的共享对象在一个请求期内有效,属于用户发送的当前请求;页面对象中的共享对象只属于当前页面的执行实例。本文主要分析共享对象的设置和访问方法,包括共享对象的有效范围、具体访问方法、辅助显示手段和多线程下的实现策略。

在JSP中访问共享对象

Servlet运行时已经准备好了这些范围对象,如表1所示。

表1 JSP中的共享对象

变量名

变量类名

对象可访问范围

页面

pageContext

javax.servlet.jsp.PageContext

在执行某一个JSP时,Servlet运行时会为它初始化pageContext变量,这个变量可以被整个JSP代码访问,包括INCLUDE指示符插进来的代码。

请求

ruquest

javax.servlet.http.HttpServletRequest

用户提交一个HTTP请求给Servlet容量,Servlet运行时会把请求封装成HttpServletRequest的一个实例,在JSP中表现为request变量。能访问pageContext的JSP代码也能访问request,另外被处理这个请求的JSP代码FORWARD到的JSP代码也能访问。

会话

session

javax.servlet.http.HttpSession

一个HttpSession会话由被创建到关闭或失效期间的用户请求组成。处理这些请求的JSP可以访问到这期间的session对象中的共享对象。在会话关闭或失效时,这些对象会丢失。

应用程序

application

javax.servlet.ServletContext

这个对象在应用程序的整个生命周期间都有效,存放在这个对象内的数据任何JSP都能访问到。

在Servlet中访问共享对象

Servlet中的共享对象如表2。

表2 Servlet中的共享对象

请求

SERVLET类的一系列服务方法的request参数。

javax.servlet.http.HttpServletRequest

用户提交一个HTTP请求给Servlet容器,Servlet运行时会把请求封装成HttpServletRequest的一个实例,并作为Servlet服务方法的request参数传递给Servlet。这个Servlet也可以把这个实例传递给其它Web组件。

会话

request.getSession()或者request.getSession(boolesn)方法获得。

javax.servlet.http.HttpSession

一个HttpSession会话由被创建到关闭或失败期间的用户请求组成。处理这些请求的Servlet可以访问到这期间的session对象中的共享对象。在会话关闭或失效时,这些共享对象会丢失。

应用程序

SERVLET的.getServletContext()

javax.servlet.ServletContext

这个对象在应用程序的整个生命周期间都有效,存放在这个对象内的数据任何Web组件都能访问到。

资源组合

在JSP技术中,有两种把资源片断组合成一个资源的技术:include 指示符和jsp:include元素。指示符的语法为:

当一个JSP被翻译成Servlet时,它会被处理。jsp:include元素的语法是:

当这个JSP页面被执行时,它会被处理。指示符是代码的组合,元素则是结果的组合。fragmentresource.jsp和主页面具有一样的上下文,如页面对象;而included.jsp不具有和主页面一样的页面对象,但请求对象是同一个。

在Servlet中,RequestDispatcher.include(request,response)实现结果的整合,示例代码如下:

RequestDispatcher dispatcher =request.getRequestDispatcher("/template.jsp");

if (dispatcher !=null)

dispatcher.include(request,response);

控制传递

在利用RequestDispatcher.forware(request,response)把控制传给另一个Web组件设置形成一个控制管道时,要严格遵循“前面的组件处理request,最后的组件处理response”的准则。前面的组件甚至不能企图获取response输出流的引用。这个控制管道中的组件具有同一个request对象,不具有相同的pageContext对象(针对JSP)。Servlet中传递控制的例子如下:

RequestDispatcher dispatcher =request.getRequestDispatcher("/template.jsp");

if (dispatcher !=null)

dispatcher.forward(request,response);

JSP中传递控制的例子如下:

在JSP中,可以通过jsp:param元素来增加请求对象的参数,适用于jsp:include和jsp:forward两元素。 示例如下:

显示共享对象

f2288545bc66433a044033e2699e9a6e.png

图1 显示共享信息类图

在网页上显示各个级别的共享对象是一个非常不错的调试手段。下面的显示共享对象类图(如图1)实现了这个功能。它以类org.i18.struts.AttributeUtils为核心,这个类负责把四个对象的共享对象保存为键/值对的HashMap对象。通过它可以得到请求对象中的共享对象及参数信息,以及页面对象、会话对象、应用对象这些共享对象的函数接口。在JSP页面中,通过下面的代码可以给这个类的对象提供输入:

class="org.i18.struts.AttributeUtils" />

JSP页面可以利用Struts提供的logic标签库显示这些共享对象:

这是页对象内的共享对象
共享对象名 共享对象相关内容

在Servlet中,AttributeDisplayHelper帮助者类完成JSP中logic标签库相应的功能。帮助者类完成工作后,AttrServlet把帮助者类完成的结果放在request中的一个共享属性Attr中,接着把控制传给servletAttr.jsp,再由它访问AttrServlet在request中设置的共享属性Attr,并显示结果。

使用者可以通过attr.jsp、AttrServlet的url映射和index.jsp的提交按钮来查看当前上下文所有级别的共享对象。关于多线程问题

J2EE系列规范中,EJB规范保证了组件开发者在单线程的环境下编程,但Servlet规范没有规定Servlet的系列服务方法在单线程模式下运作,所以开发者在使用共享对象时要注意线程同步问题。一个比较通用的原则是:在一个专职的组件中设置共享对象,当设置和访问破坏数据的一致性时,使用Java的同步控制。

一个Servlet(包括JSP)的生命周期由其所在的容器控制。当有一个Servlet请求时,容器执行如下步骤:

1.如果此Servlet的实例不存在,容器先装载Servlet的类代码,创建一个Servlet实例,接着调用这个实例的init方法。

2.如果此Servlet的实例存在,容器分配一个处理用户请求的工作线程。如果Servler实现了SingleThreadModel接口,工作线程会在这个实例上同步,并且在取得访问权限后调用实例的service方法,否则直接调用实例的service方法。javax.servlet.http.HttpServlet的service方法会根据用户的HTTP请求类型调用相应的doxxx方法。

3.只有当所有的线程从这个实例中退出,容器在回收这个实例时才会调用这个实例的destroy方法。

Servlet实例线程图(如图2)体现了这个生命周期模型。

d849d19b1ccb8fdc3dbb0afc1668b37e.png

图2 Servlet实例线程图

虽然可以让所有的Servlet实现SingleThreadModel接口,但这会严重影响程序的性能。要解决多线程的同步问题,我们首先要分析共享对象的访问模式。在一个Web程序中,共享对象按访问模式可以分为以下两类:一次设置、多次读取的共享对象和多次设置、多次读取的共享对象。

一次设置、多次读取

对于这种共享对象,可以开发一个事件监听器,监听程序启动和停止事件,代码如下:

package org.i18.listen

import org.i18.utils.*;

import javax.servlet.*;

import util.Counter;

public final class ContextListener implements ServletContextListener {

private ServletContext context =null;

public void contextInitialized(ServletContextEvent event){

context =event.getServletContext();

SynObject synObject = new SynObject();

//在这里把共享对象放在应用对象中

context.setAttribute("SYNOBJECT",synObject);

}

public void contextDestroyed(ServletContextEvent event){

context =event.getServletContext();

//清除保存在应用对象中的共享属性

context.removeAttribute("SYNOBJECT ");

}

}

这样,当Web应用程序启动时,容器会调用监听器,从而设置共享对象。共享对象的访问只需直接调用getAttribute方法即可。

多次设置、多次读取

对于多次设置、多次读取的共享对象,必须利用Java的同步机制,访问步骤如下:

第一步,首先设计一个同步类。这个同步类的代码非常简单:

package org.i18.utils

public final class SynObject{

}

以上代码可以看出,它其实什么都没做,但继承了Object关于同步的方法和机制。

第二步,把这个类的实例放到应用对象中作为一个共享对象。可以看出这个同步对象属于一次设置、多次使用的共享对象。在应用程序启动事件监听器中设置它,请参见前面的代码。

第三步,设置共享对象。如果有对象需要整个应用程序共享,可以在Servlet的service中利用同步机制来设置:

public void doGet (HttpServletRequest request,HttpServletResponse response)

throws ServletException,IOException {

ServletContext context= getServletContext();

//得到同步对象

Object obj = context.getAttribute("SYNOBJECT");

//获取同步钥匙

synchronized(obj){

//先检查是否存在这个共享对象

Object obj2 = context.getAttribute("Attr");

if (obj2 == null) {

//不存在,设置共享对象

obj2 = new TestBean();

context.setAttribute("Attr",obj2);

}

}

}

第四步,读取共享对象。当需要访问多次设置、多次访问的共享对象时,同样需要利用同步机制,代码如下:

public void doGet (HttpServletRequest request,HttpServletResponse response)

throws ServletException,IOException {

ServletContext context= getServletContext();

//得到同步对象,因为这个对象是一次设置、多次读取型的,不需要同步

Object obj = context.getAttribute("SYNOBJECT");

//获取同步钥匙

synchronized(obj){

//得到需要的共享对象

Object obj2 = context.getAttribute("Attr");

}

}

会话对象内共享对象的多线程问题可以和应用对象一样处理。请求对象和页面对象正常情况下是线程安全的,除非开发者自己引入了额外的线程。

本文分析了开发好的J2EE应用必须掌握的、组件间对象共享的技术,这种分析技术同样适用于EJB中。在EJB容器中,信息存放的位置变成了实现JNDI的服务提供者,大家通过JNDI的接口方法查询、绑定共享对象。需要注意的是,同步对象不能在JNDI中实现,因为大家搜索出来的不是同一个内存对象。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值