2.6.1 application对象
2.6.1 application对象
在介绍application对象之前,先简单介绍一些web服务器的实现原理。虽然绝大部分读者都不需要、甚至不曾想过自己开发Web服务器,但了解一些web服务器的运行原理,对于更好地掌握JSP知识将有很大的帮助
虽然常把基于Web应用称为B/S(Browser/Server)架构的应用,但其实Web应用一样是C/S(Client/Server)结构的应用,只是这种应用的服务器是Web服务器,而客户端是浏览器。
浏览器功能
现在抛开Web应用直接看Web服务器和浏览器,对于大部分浏览器而言,它通常负责完成三件事情.
- 向远程服务器发送请求
- 读取远程服务器返回的字符串数据。
- 负责根据字符串数据渲染出一个丰富多彩的页面。
实际上,浏览器是一个非常复杂的网络通信程序,它除了可以向服务器发送请求、读取网络数据之外,最大的技术难点在于将HTML文本渲染成页面,建立HTML页面的DOM模型,支持JavaScript脚本程序等。
通常浏览器有InternetExplorer,FireFox、Chrome、Opera、Safari等,至于其他如MyE、傲游等浏览器可能只是对它们进行了简单的包装。
Web服务器功能
Web服务器则负责接收客户端请求,每当接收到客户端连接请求之后,web服务器应该使用单独的线程为该客户端提供服务:接收请求数据、送回响应数据。
图2.16显示了Web服务器的运行机制。
如图2.16所示的应用架构总是先由客户端发送请求,服务器接收到请求,然后后送回响应的数据,所以也将这种架构称做“请求响应”架构。根
Web服务器处理请求步骤
据如图2.16所示的机制进行归纳,对于每次客户端请求而言,Web服务器大致需要完成如下几个步骤。
- 启动单独的线程。
- 使用
I/O流读取用户请求的二进制流数据。 - 从请求数据中解析参数
- 处理用户请求。
- 生成响应数据。
- 使用
I/O流向客户端发送请求数据。
最新版的Tomcat已经不需要对每个用户请求都启用单独的线程、使用普通I/O读取用户请求的数据,最新的Tomcat使用的是异步I/O,具有更高的性能
在上面6个步骤中,第1、2和6步是通用的,可以由Web服务器来完成,但第3、4和5步则存在差异:因为不同请求里包含的请求参数不同,处理用户请求的方式也不同,所生成的响应自然也不同。那么Web服务器到底如何执行第3、4和5步呢?
Servlet的_jspService方法
实际上,web服务器会调用Servlet的_jspService()方法来完成第3、4和5步。编写JSP页面时,页面里的静态内容、JSP脚本都会转换成_jspService方法的执行代码,这些执行代码负责完成解析参数、处理请求、生成响应等业务功能,而web服务器则负责完成多线程、网络通信等底层功能。Web服务器在执行了第3步解析到用户的请求参数之后,将需要通过这些请求参数来创建HttpServletRequest、HttpServletResponse等对象,作为调用_jspService()方法的参数,实际上一个Web服务器必须为Servlet API中绝大部分接口提供实现类。
JSP和Servlet如何交换数据
从上面介绍可以看出,Web应用里的JSP页面、Servlet等程序都将由Web服务器来调用,JSP、Servlet之间通常不会相互调用,这就产生了一个问题:JSP、Servlet之间如何交换数据?
通过application,session,request,page交换数据
为了解决这个问题,几乎所有Web服务器(包括Java、ASP、PHP、Ruby等)都会提供4个类似Map的结构,分别是:application、session、request、page,并允许JSP、Servlet将数据放入这4个类似Map的结构中,并允许从这4个Map结构中取出数据。这4个Map结构的区别是范围不同:
application:对于整个Web应用有效,一旦JSP、Servlet将数据放入application中,该数据将可以被该应用下其他所有的JSP、Servlet访问session:仅对一次会话有效,一旦JSP、Servlet将数据放入session中,该数据将可以被本次会话的其他所有的JSP、Servlet访问。request:仅对本次请求有效,一旦JSP、Servlet将数据放入request中,该数据将可以被该次请求的其他JSP、Servlet访问.page:仅对当前页面有效,一旦JSP、Servlet将数据放入page中,该数据只可以被当前页面的JSP脚本、声明部分访问。
类似银行
就像现实生活中有两个人,他们的钱需要相互交换,但他们两个人又不能相互接触那么只能让A把钱存入银行,而B从银行去取钱。因此可以把application、session、request和page理解为类似银行的角色。
把数据放入application、session、request或page之后,就相当于扩大了该数据的作用范围,所以认为application、session、request和page中的数据分别处于application、session、request和page范围之内。
application,session,request,pageContext内置对象
JSP中的application、session、request和pageContext4个内置对象分别用于操作application、sessionrequest和page范围中的数据
application对象代表Web应用本身,因此使用application来操作Web应用相关数据。application对象通常有如下两个作用:
- 在整个
Web应用的多个JSP、Servlet之间共享数据。 - 访问
Web应用的配置参数。
1. 让多个JSP、Servlet共享数据
setAttribute getAttribute方法
application通过setAttribute(String attrName, Object value)方法将一个值设置成application的attrName属性,该属性的值对整个Web应用有效,因此该Web应用的每个JsP页面或Servlet都可以访问该属性访问属性的方法为getAttribute(String attrName)
put-application.jsp
看下面的页面,该页面仅仅声明了一个整型变量,每次刷新该页面时,该变量值加1,然后将该变量的值放入application内。下面是页面的代码
1 | <%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %> |
以上页面在每次刷新该页面时,变量i都先自加,并被设置为application的counter属性的值,即每次application中的counter属性值都会加1。
get-application.jsp
再看下面的JSP页面,该页面可以直接访问到application的counter属性值。
1 | <%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %> |
get-application.jsp页面中的代码:
1 | <%=application.getAttribute("counter")%> |
直接输出application的counter属性值,虽然这个页面和put-application.Jsp没有任何关系,但它一样可以访问到application的属性,因为application的属性对于整个Web应用的JSP、Servlet都是共享的。
测试1
在浏览器的地址栏中访问第一个put-application.jsp页面,经多次刷新后,看到如图2.17所示的页面。
访问get-application.Jsp页面,也可看到类似于图2.17所示的效果,因为get-application.Jsp页面可以访问application的counter属性值。
application不仅可以用于两个JSP页面之间共享数据,还可以用于Servlet和JSP之间共享数据。可以把application理解成一个Map对象,任何JSP、Servlet都可以把某个变量放入application中保存,并为之指定一个属性名;而该应用里的其他JSP、Servlet就可以根据该属性名来得到这个变量。
GetApplication.java
下面的Servlet代码示范了如何在Servlet中访问application里的变量。
1 | package lee; |
由于在Servlet中并没有application内置对象,所以上面程序中的代码:
1 | ServletContext sc = getServletConfig().getServletContext(); |
显式获取了该Web应用的ServletContext实例,每个Web应用只有一个ServletContext实例,在JSP页面中可通过application内置对象访问该实例,而Servlet中则必须通过代码获取。
程序代码:
1 | out.println(sc.getAttribute("counter")); |
访问、输出了application中的counter变量。
该Servlet类同样需要编译成class文件才可使用,实际上该Servlet还使用了@WebServlet注解进行部署,关于Servlet的用法请参看2.7节。编译Servlet时可能由于没有添加环境出现异常,只要将Tomcat8.5的lib路径下的jsp-api.jar、servlet-api.jar两个文件添加到CLASSPATH环境变量中即可。
测试2
将Servlet部署在Web应用中,在浏览器中访问Servlet(http://localhost:8080/jspObject/get-application),出现如图2.18所示的页面。
最后要指出的是:虽然使用application(即Servletcontext实例)可以方便多个JsP、Servlet共享数据,但不要仅为了JSP、Servlet共享数据就将数据放入application中!由于application代表整个Web应用,所以通常只应该把Web应用的状态数据放入application里。
2. 获得Web应用配置参数
application还有一个重要用处:可用于获得web应用的配置参数。看如下JSP页面,该页面访问数据库,但访问数据库所使用的驱动、URL、用户名及密码都在web.xml中给出
getWebParam.jsp
1 | <%@ page contentType="text/html; charset=GBK" language="java" errorPage="" %> |
获取Web应用配置参数 getInitParameter方法
上面的程序中使用application的getInitParameter(String paramName)来获取Web应用的配置参数,这些配置参数应该在web.xml文件中使用context-param元素配置.
context-param元素
每个<context-param>元素配置一个参数,该元素下有如下两个子元素
param-name:配置web参数名。param-value:配置Web参数值。
web.xml文件中使用<context-param>元素配置的参数对整个Web应用有效,所以也被称为web应用的配置参数。与整个web应用有关的数据,应该通过application对象来操作。
web.xml
为了给Web应用配置参数,应在web.xml文件中增加如下片段
1 |
|
在浏览器中浏览getWebParam.jsp页面时,可看到数据厍连接、数据査询完全成功。可见,使用application可以访问Web应用的配置参数。
通过这种方式,可以将一些配置信息放在web.xml文件中配置,避免使用硬编码方式写在代码中,从而更好地提高程序的移植性.