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
文件中配置,避免使用硬编码方式写在代码中,从而更好地提高程序的移植性.