如何在没有任何请求、会话等的情况下获取上下文?

6

我有一个类中的方法,它没有获取任何可用于获取实际servlet上下文的东西。实际上,就像这样:

public String getSomething() { ... }

但是为了计算结果,我需要实际的、特定于线程的servlet结构。

我认为,在应用程序上下文的深处,应该存在一些类似于特定于线程的存储,可以通过调用某个系统类的静态方法来访问它。

我正在使用tomcat6 servlet容器,但如果需要的话,也可以使用Spring。

4个回答

10

在你的web.xml中添加一个ServletContextListener。这将在你的Web应用程序被加载时调用。在contextInitialized()方法中,你可以将ServletContext存储在一个静态变量中以供以后使用。然后,你将能够以静态方式访问ServletContext

class MyListener implements ServletContextListener {

    public static ServletContext context;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        context = sce.getServletContext();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        context = null;
    }

}

将其添加到 web-xml 中,方法如下:

<web-app>
    <listener>
        <listener-class>
            com.something.MyListener
        </listener-class>
    </listener>
</web-app>

你可以像这样从任何地方访问它:

public String getSomething() {
    // Here you have the context:
    ServletContext c = MyListener.context;
}

注意:

你可能希望将其存储为private,并提供一个getter方法,在使用它之前还要检查null值。


6

如果您没有指向有用内容的指针,我所知道的唯一方法是在包含当前ServletContext的类中具有静态属性。使用ServletContextListener非常简单:

@WebListener
public class ServletContextHolder implements ServletContextListener {
    private static ServletContext servletContext;

    public static ServletContext getServletContext() {
        return servletContext;
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        servletContext = sce.getServletContext();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        servletContext = null;
    }    
}

然后,您可以从任何地方使用

ServletContextHolder.getServletContext();

如果您使用Spring,还可以使用RequestContextHolder来访问当前请求(以及您所需的任何内容)。
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                                 .getRequestAttributes()).getRequest();

当然,如果在Servlet应用程序中可以这样使用,但在Portlet应用程序中则不行 - 您将需要使用PortletRequestAttributes并最终获得一个PortletRequest。

3
显然的解决方案是将上下文作为参数传递,因为你肯定是在通常可获得上下文的代码中运行该代码。
如果由于某种原因你认为这不是你能做到的(我想听听原因),另一种方法是创建一个Servlet过滤器,然后创建例如ThreadLocal<ServletContext>。

1
需要一个ThreadLocal吗?据我所知,ServletContext在VM中只定义一次。 - epoch
@epoch 或许不同的网络应用程序有不同的ServletContext? - peterh
非常感谢 - 最终我采用了您的第一个想法:我将servletContext作为新setter提供给bean。也许这不是最美丽的解决方案,但肯定是最简单和最独立于平台的。 - peterh
@Kayaman:当您在不同的API /库项目中有一些公共代码部分,并且在该库中具有多态构造函数时,这是必需的。 - zookastos

1
您可以按照以下方式自动装配servlet上下文。
@Autowired
ServletContext servletContext;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接