servlet的线程安全问题和ServletContext

907 阅读3分钟

Servlet是线程安全的吗

其实这个问题怎么说呢,感觉不应该这么问,因为一个Servlet只会实例化一次,在整个web容器中,他是单例的(分布式环境除外),所以线程安全问题跟他本身没有关系,而是跟Tomcat的处理方式有关,Tomcat对每一个请求都会分配一个线程来处理servlet,所以其实所谓的线程安全问题是针对某个Servlet中的共享变量来说的,如果一个servlet中没有没有共享变量,那么无论多少个请求同时发起,都不会存在线程安全问题,其实这个道理就好比问你,Controller是线程安全的吗?,当然我们也可以为每一个请求创建一个Servlet实例子,通过实现SingleThreadModel接口,不过他还是有一个数量上限的,而且在servlet2.4的时候已经被声明过期了,并不推荐继续使用。只了解一下就好了。

ServletContext

在上一篇已经提到了,我们可以通过getServletConfig()来获取当前servlet的私有配置,比如初始化参数,名称等,但其实最重要的还是他的getServletContext()方法,获取到的是一个代表当前整个web应用视图等ServletContext,他是所有servlet共享的也是全局唯一的,所以我们可以把它当作整个web应用最大的缓存。我们可以通过<context-param>标签配置整个web的初始化参数等,也可在编写Servlet的时候就可以借助它来获取跟路径下的资源文件,也能动态注册Filter,Listener,Servlet,功能非常强大,列举几个常用方法:

public InputStream getResourceAsStream(String path); //获取资源
public String getInitParameter(String name);//获取全局初始化参数
public ServletRegistration.Dynamic addServlet(
    String servletName, Servlet servlet); //注册servlet
public FilterRegistration.Dynamic addFilter(
    String filterName, Filter filter); //注册Filter

但值得注意的是,添加servlet和filter的这两种配置方法是有调用要求的,参考servlet3.1规范和java doc,这几种配置方法是在servlet3.0开始添加进来的,以便启用编程方式定义 Servlet、 Filter 和它们映射到的url模式,这些方法只能在应用初始化期间从 ServletContextListener 接口实现的 contexInitialized方法或者 ServletContainerInitializer 接口实现的 onStartup 方法中调用,还记得上篇文章留下的伏笔吗,ServletContainerInitializer是留给我们的扩展方法,而且可以在这里面注册servlet,filter。后面还会继续说道,这里可以先看一个例子,脱离web.xml来注册一个servlet

public class AnimalServletContainerInitializer implements ServletContainerInitializer {
    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) {

        ServletRegistration.Dynamic servlet = ctx.addServlet("initializerServlet", new HttpServlet() {
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                System.out.println("这是编程方式注册的");
            }
        });
        servlet.addMapping("/init");
    }
}

当然我这里时使用的最快捷的方式,仅仅是为了演示这是一个可行的方案,没做其他设置,主要是看一下这个方法的返回值,ServletRegistration.Dynamic

interface Dynamic extends ServletRegistration, Registration.Dynamic

一通继承组合拳,把能通过web.xml配置servlet的方式都做成了接口方法,这样我们就能通过编程的方式来脱离web.xml的束缚了,看一眼他的方法,大概都能看懂他们分别是干什么的

image.png 然后Filter也是类似的注册方式,下篇再说一说Servlet中的Filter和Listener