欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ServletConfig与ServletContext

程序员文章站 2022-03-02 22:41:02
...

ServletConfig对象

web容器负责调用Servlet的init(ServletConfig config)方法,web容器会将该Servlet在web.xml中的配置信息拿出来,创建一个ServletConfig对象,封装这些信息,再作为参数传入该Servlet的init方法。init方法在GenericServlet中就相当于GenericServlet中成员属性config(该属性虽然引用了另一个对象,但它被transient关键字修饰,所以该属性引用的另一个对 象不会随着GenericServlet对象的序列化被序列化)的set方法。ServletConfig代表当前Servlet在web.xml中的配置信息,可以用来获取<servlet>中用<init-param>配置的初始化参数。例如:

<servlet>
    <!-- 配置当前Servlet的初始化参数,只有当前Servlet能访问到 -->
    <init-param>
        <param-name>driver</param-name>
        <param-value>com.mysql.jdbc.Driver</param-value>
    </init-param>
</servlet>

ServletConfig有什么用呢?它涉及到我们软件的可维护性:

情景:如果将一个属性定义到一个Servlet实体类中,我们明天要修改这个driver的值。

解决方案一:你找到所有用到driver属性的实体类,将它们对应的driver属性的值改了,然后将编译后的class文件再重新发布到服务器上

解决方案二:你之前将这个driver属性以键值对的方式写到web.xml文件中,然后在Servlet实体类中,你通过this.getServletConfig()方法获取了一个ServletConfig对象,用这个对象的getInitParameter("driver")获取web.xml中配置的driver属性的值。所以你只修改了web.xml文件中的值,并且你也不用重新发布项目。

毫无疑问,解决方案二的可维护性更高。

*ServletContext对象

ServletContext这个类对web应用进行抽象,一个ServletContext对象与一个具体的web应用相对应(java面向对象思想:使用对象封装了与它对应的现实事物的各种属性值),所以ServletContext对象当中封装了web应用中的各种属性值。

生命周期

当服务器启动时会依次加载web应用,并在加载完成之后会创建一个ServletContext对象来唯一代表该web应用,它随着web应用的存在而一直存在,直到web应用移出容器或者服务器关闭时,随着web应用销毁,ServletContext对象跟着销毁。

注:加载web应用其实是把web应用中的各种对象:filter(过滤器对象)、listener(监听器对象)等加载到内存中,如果你想直接操作这些对象是找不到的,所以有了ServletContext对象来代表这个web应用,你想操作web应用中的组件,直接找它就行了。

获取方法(自定义Servlet的doGet方法中)

方法1:通过ServletConfig对象提供getServletContext()方法

// 获取ServletContext的方法1
ServletContext sc1 = this.getServletConfig().getServletContext();

方法2:在GenericServlet中提供了便捷的getServletContext()方法,我们写的Servlet继承自GenericServlet,所以可以通过this.getServletContext()来获取ServletContext对象。(其实底层也是用的ServletConfig对象获取的)

// 获取ServletContext的方法2
ServletContext sc1=this.getServletContext();

实际应用

1.读取web.xml中web应用的初始化参数(这个参数和ServletConfig的参数不太一样),在web应用中的所有组件都可以访问到。

以下这两段代码是在web.xml中将配给Servlet的编码集改为整个站点配置并通过ServletContext获取。(注意web.xml改完之后要重启一下服务器)注意:每个参数都是一组<context-param>标签

<!-- 配置当前web应用的初始化参数,在其所有组件有效 -->
<context-param>
	<param-name>encode</param-name>
	<param-value>utf-8</param-value>
</context-param>
// 获取web.xml中配置的初始化参数
String encode=sc1.getInitParameter("encode");

拓展:使用迭代器查看web应用中所有的初始化参数名

Enumeration<String> names= sc1.getInitParameterNames();
    while(names.hasMoreElements()){
        String name=names.nextElement();
        System.out.println(name+":"+sc1.getInitParameter(name));
}

2.ServletContext对象作为域对象使用,也被称为Application作用域。利用这个对象上的map就可以在整个web应用内实现资源的共享

域:这个对象在一定范围内是可见的,利用这个对象身上的map,在这个范围内共享数据,这样的对象叫做域对象。

Javaweb开发中一共有四大域对象

ServletContext(Application)域:

   作用范围:整个web应用中都可见
   生命周期:ServletContext代表当前web应用,当服务器启动时会依次加载web应用,并在加载完成之后会创建一个ServletContext对象来唯一标识该web应用,它随着web应用的存在而一直存在,直到web应用移出容器或者服务器关闭时,随着web应用一起被销毁

操作域的方法:                

setAttribute(String name,Object obj);//向域中设置数据
Object getAttribute(String name);//从域中获取数据
removeAttribute(String name);//从域中移除数据

Application作用域和Request作用域对比

生命周期:一个是整个web应用周期,一个是一次请求一次应答

作用范围:一个是整个web应用,一个是整个请求链

具体作用:一个是整个web应用内实现共享,一个是Servlet带数据给JSP

问题:理论上Request作用域能做的事儿,Application作用域都能做,但为什么还会有Request作用域呢?

答:核心思想是多用户。我们根据两种情景来解释。

使用Request作用域:用户1请求Servlet1,在Request1中存入属性name,值为张三,然后Servlet1将请求转发给Servlet2,Servlet2会从Request1中取出数据执行。用户2请求Servlet1,在Request2中存入属性name,值为李四,然后Servlet1将请求转发给Servlet2,Servlet2会从Request2中取出数据执行。不会产生错误。

使用Application作用域:用户1请求Servlet1,在Application中存入属性name,值为张三,然后Servlet1将请求转发给Servlet2,Servlet2还没来得及将数据从Application作用域中取出,用户2的请求到了,属性也是name,但是值为李四,由于Application中的map集合中又放了一个name,那么之前name的值会被覆盖成为李四。当用户1请求Servlet2时拿到的值就是李四了。

所以Application作用域的局限性在于它只有一个,碰到多线程访问时会产生并发安全问题。而Request作用域是为每个用户的每次请求设计的专属对象,用来存储用户当前请求的所有数据

3.

 

相关标签: JavaWeb