Servlet笔记(5):ServletConfig、ServletContext 详解

文章目录

    • ServletConfig
      • ContextPath
      • ServletConfig 详解
        • Servlet 初始化配置加载(配置见博客文章 Servlet Web.xml配置)
        • API 使用
        • 注意事项
        • 代码如下
    • ServletContext
      • 简介
      • 应用
        • 上下文参数
        • 利用 ServletContext 获取资源文件
        • 利用 ClassLoader 获取资源文件
    • 参考

ServletConfig

ContextPath

一个Web工程,如名为 Learning-Servlet,访问的路径 http://localhost:8080/servletWeb/XXXX

  1. 这整个 web 应用就成为一个 Context
  2. 路径 /servletWeb 被称为上下文路径, 即 ContextPath。可以通过请求对象 request.getContextPath() 获取

ServletConfig 详解

Servlet 初始化配置加载(配置见博客文章 Servlet Web.xml配置)

  1. ServletConfig 是处理装载 Servlet 初始化参数的。init-param 标签配置的数据.如:

    ServletConfigServlet
    com.learning.select2.config.ServletConfigServlet
    
        user
        Sam
    


    ServletConfigServlet
    /servletConfigServlet

  1. Servlet 配置了初始化参数后,web容器在创建Servlet实例对象时,会自动将这些初始化参数封装到 ServletConfig 对象中,并在调用 servletinit() 方法时,将 ServletConfig 对象传递给 servlet。进而,通过 ServletConfig 对象就可以得到当前servlet的初始化参数。GenericServlet 中源码如下:
public void init() throws ServletException {
}

public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
}
  1. SpringMvc 的配置,就是使用 ServletConfig 初始化参数处理配置文件加载

API 使用

  1. 服务器会自动封装在 ServletConfig 中,我们利用 init() 或者 init(ServletConfig config) 方法,可以只获取一次 ServletConfig 对象。如果要重写 init 方法,需要小心,见注意事项。
  2. 通过 getInitParameter() 方法,获取配置好的参数。这个方法父类通过 ServletConfig.getInitParameter(),或者使用 GenericServlet 封装好的。
  3. ServletConfig 对象也可以直接通过父类 GenericServlet 封装好的 getServletConfig() 方法获取
public String getInitParameter(String name) {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
        throw new IllegalStateException(
            lStrings.getString("err.servlet_config_not_initialized"));
    }
    return sc.getInitParameter(name);
}
    
public ServletConfig getServletConfig() {
	return config;
}
  1. 通过getInitParameterNames(),可以获取枚举类型的所有初始化参数
public Enumeration getInitParameterNames() {
    ServletConfig sc = getServletConfig();
    if (sc == null) {
        throw new IllegalStateException(
            lStrings.getString("err.servlet_config_not_initialized"));
    }

    return sc.getInitParameterNames();
} 
  1. 实际项目中,参数放在xml与properites文件中更灵活,写程序获取即可。

注意事项

  1. 如果要重写 init 方法,推荐使用不带参数的init()方法
  2. 如果重写父类带参数的 init() 方法,这句一定写,super.init(config),不然 ServletConfig 对象空指针。原因在于,父类中代参的 init() 实现的时候,先 this.config = config;然后调用无参this.init()。其实你复写两个init()方法后,输出的顺序也解释了这一点。

代码如下

public class ServletConfigServlet extends HttpServlet {

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("带参数的init方法,先调用");
        // 这句一定要写,不然不会装载 ServletConfig 对象
        super.init(config);

    }

    @Override
    public void init() throws ServletException {
        System.out.println("无参的init方法,后调用");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取 ContextPath
        String contextPath = req.getContextPath();
        System.out.println("上下文路径 contextPath: " + contextPath);

        // 直接通过父类封装的 getInitParameter 方法
        String user = getInitParameter("user");
        System.out.println("ServletConfigServlet 初始化参数 user 的值: " + user);

        // 使用 ServletConfig 内部的 getInitParameter 方法
        String user1 = getServletConfig().getInitParameter("user");
        System.out.println("ServletConfigServlet 初始化参数 user 的值: " + user1);

        Enumeration parameterNames = getInitParameterNames();
        while (parameterNames.hasMoreElements()) {
            String thisName = parameterNames.nextElement().toString();
            System.out.println("初始化参数 : " + thisName);
        }
    }
}

ServletContext

简介

  1. 生命周期:Web容器在启动时,它会为每个 Web 应用程序都创建一个对应的 ServletContext 对象,它代表当前Web应用。ServletContext 对象只在Web应用被关闭时才被销毁;不同的Web应用,ServletContext各自独立存在
  2. api 获取:
  • SevletConfig 对象中维护了 ServletContext 对象的引用,通过 SevletConfig.getServletContext()方法获取ServletContext 对象。
  • 直接调用父类封装好的 getServletContext() 方法即可获取
  1. 作用域:由于一个Web应用中的所有 Servlet 共享同一个ServletContext 对象,因此 Servlet 对象之间可以通过ServletContext 对象来实现通讯。 ServletContext 对象通常也对称之为 context 域对象
  2. Spring 就是使用 ServletContext, 上下文参数处理配置文件的加载

应用

上下文参数

  1. 获取上下文参数。context-param 标签配置得参数是供 web 应用共享的,所有的servlet都可以访问。

    context_user
    Admin

// 获取 ServletConfig 配置,最对某个 Servlet 有效
String servlet_user = getInitParameter("servlet_user");
System.out.println("本 Servlet 私有的配置: " + servlet_user);


// 获取 ServletContext 配置,最对所有 Servlet 有效
ServletContext servletContext = getServletContext();
String context_user = servletContext.getInitParameter("context_user");
System.out.println("所有的 Servlet 共有的配置: " + context_user);
  1. 利用ServletContext,实现 Servlet 对象之间通讯。 主要是4个有关 Attribute 的方法:setAttribute()、getAttribute()、removeAttribute()、getAttributeNames()
// 所有servlet实现通信,使用 上下文 Context 域
ServletContext servletContext = getServletContext();
servletContext.setAttribute("new_user", "");
String new_user = (String) servletContext.getAttribute("new_user");
System.out.println("所有servlet实现通信: " + new_user);
servletContext.removeAttribute("new_user");
servletContext.getAttributeNames();

利用 ServletContext 获取资源文件

  1. 环境:基本 Maven 工程,有文件两个,路径如下
Learning-Servlet/servlet-2x/src/main/resources/file.properties # resources 下的资源编译的时候放入 classes 目录(classpath根目录)
Learning-Servlet/servlet-2x/src/main/webapp/downLoad/file2.properties # webapp 下的资源编译的时候会直接放入根目录
  1. ServletContext 获取资源地址的方法有三个:默认从 Web 应用根目录下取资源,Tomcat下 path 是否以 ‘/’ 开头无所谓, 建议加上’/’, 和具体的容器有关
  • servletContext.getResourceAsStream(): 直接获取流对象
  • servletContext.getResource():获取URL对象,然后再次获取path与数据流
  • servletContext.getRealPath():获取绝对路径
// 直接获取流对象
InputStream resourceAsStream = servletContext.getResourceAsStream("/downLoad/file.properties");
getProperties(resourceAsStream);

// 获取绝对路径
String realPath = servletContext.getRealPath("downLoad/file.properties");
System.out.println(realPath);
InputStream stream = new FileInputStream(realPath);
getProperties(stream);

// 获取URL对象,然后再次获取path与数据流
URL resource = servletContext.getResource("downLoad/file.properties");
String path = resource.getPath();
System.out.println(path);
InputStream inputStream = resource.openStream();
getProperties(inputStream);
  1. 根目录 与 classPath 目录的不同处理方式
// 这种情况Spring 是可以很好处理的, 见博客文章 Spring 分类
// 使用 ServletContext 不怎么好处理(毕竟 classes 是编译以后生成的),可以使用类加载器(ClassLoader)处理
String realPath2 = servletContext.getRealPath("/WEB-INF/classes/file2.properties");
System.out.println(realPath2);
InputStream stream2 = new FileInputStream(realPath2);
getProperties(stream2);

// 默认则是从 ClassPath 根下获取,path不能以'/'开头,最终是由 ClassLoader 获取资源。
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("file2.properties");
getProperties(resourceAsStream);

利用 ClassLoader 获取资源文件

  1. getClassLoader().getResourceAsStream : 默认是从 ClassPath 根下获取,path不能以’/'开头,最终是由 ClassLoader 获取资源
  2. getClass().getResourceAsStream : path 不以’/‘开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath(Src根目录)根下获取
// 默认则是从 ClassPath 根下获取,path不能以'/'开头,最终是由 ClassLoader 获取资源。
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("file2.properties");
getProperties(resourceAsStream);


// path 不以'/'开头时默认是从此类所在的包下取资源,以'/'开头则是从ClassPath(Src根目录)根下获取。
// 其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。
resourceAsStream = getClass().getResourceAsStream("/file2.properties");
getProperties(resourceAsStream);

参考

  1. 源码地址
  2. Servlet学习笔记(五):ServletConfig和ServletContext详解

你可能感兴趣的:(Servlet)