嵌入式Tomcat中如何访问Servlet Context外部声明的静态变量?
问题根本原因
该问题是类加载器隔离导致的:
嵌入式Tomcat默认会为部署的Web应用创建独立的WebAppClassLoader,你项目里的Main类是由JVM系统类加载器加载的,而带@WebServlet注解的Servlet类是由Tomcat的Web应用类加载器加载的。不同类加载器加载的全限定名相同的类会被JVM识别为两个不同的类,各自的静态变量完全独立互不影响,所以你在main方法里操作的是系统类加载器加载的Main类的静态变量,Servlet里访问的是WebAppClassLoader加载的Main类的静态变量,自然拿到的是初始值0。
可行解决方案
方案1:关闭Tomcat Web应用类加载器隔离(最简单)
直接配置Tomcat使用系统类加载器加载Web应用的所有类,避免出现两份类实例,在tomcat.start()前添加一行配置即可:
public static void main(String[] args){ list.add(new Object()); tomcat = new Tomcat(); tomcat.setPort(8080); // 新增这一行,指定Web应用使用系统类加载器 tomcat.getHost().setClassLoader(ClassLoader.getSystemClassLoader()); try { tomcat.start(); tomcat.getServer().await(); } catch (Exception e) { e.printStackTrace(); } }
方案2:使用ServletContext共享数据(符合Servlet规范的标准做法)
静态变量跨类加载器共享本身就不符合容器设计规范,推荐将共享数据存入ServletContext全局上下文:
- 启动Tomcat时往上下文里存入共享集合
// 注册Web应用上下文 Context context = tomcat.addContext("", System.getProperty("java.io.tmpdir")); // 把list存入上下文 context.setAttribute("sharedList", list); // 注册Servlet Tomcat.addServlet(context, "servlet name", new ServletClass()); context.addServletMappingDecoded("/test", "servlet name");
- Servlet中从上下文取数据
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { List<Object> list = (List<Object>) getServletContext().getAttribute("sharedList"); System.out.println("LIST SIZE: " + list.size()); }
修改后即可拿到预期的大小1。
内容的提问来源于stack exchange,提问作者nadhem
相关产品推荐
相关产品推荐

