
1. JavaWeb学习笔记Day11概述今天要分享的是JavaWeb开发中几个关键组件的实战应用主要涉及Servlet生命周期管理、Filter过滤器的配置使用以及Listener监听器的实现原理。这些内容构成了JavaWeb应用的基础架构也是面试中经常被问到的核心知识点。在实际企业级开发中Servlet作为最基础的Web组件承担着请求处理的核心职责Filter则像安检通道一样对请求进行预处理Listener则默默监控着应用的各种状态变化。三者的协同工作构成了JavaWeb应用的完整生命周期管理体系。2. Servlet生命周期深度解析2.1 生命周期阶段详解Servlet的生命周期由Web容器如Tomcat全权管理主要经历三个阶段初始化阶段容器首次加载Servlet时调用init()方法只会执行一次常用于加载静态资源或建立数据库连接可通过WebServlet注解或web.xml配置启动参数Override public void init() throws ServletException { // 初始化数据库连接池 DataSource ds createDataSource(); getServletContext().setAttribute(dataSource, ds); }服务阶段每次请求都会调用service()方法根据请求类型自动路由到doGet()/doPost()线程安全问题需要特别注意典型处理流程protected void doGet(HttpServletRequest req, HttpServletResponse resp) { // 1. 获取请求参数 String param req.getParameter(key); // 2. 业务逻辑处理 Object result businessService.process(param); // 3. 响应输出 resp.setContentType(application/json); resp.getWriter().write(JSON.toJSONString(result)); }销毁阶段容器关闭时调用destroy()释放数据库连接等资源保存必要的持久化状态2.2 线程安全最佳实践Servlet的线程安全问题常被初学者忽视。由于Servlet是单例的所有请求共享同一个实例重要提示不要在Servlet中定义可修改的成员变量必须将共享数据存储在ServletContext应用级别HttpSession会话级别请求参数请求级别线程安全改造示例// 危险写法非线程安全 private int counter 0; protected void doGet(...) { counter; // 多线程并发时会出问题 } // 正确写法使用原子类 private final AtomicInteger counter new AtomicInteger(0); protected void doGet(...) { counter.incrementAndGet(); }3. Filter过滤器实战应用3.1 过滤器链工作原理Filter就像洋葱的层层包裹请求和响应会依次通过配置的过滤器链客户端请求 - Filter1 - Filter2 - Servlet - Filter2 - Filter1 - 客户端响应典型应用场景权限验证请求/响应日志记录字符编码设置敏感词过滤3.2 编码过滤器实现示例WebFilter(/*) public class EncodingFilter implements Filter { private String encoding UTF-8; Override public void init(FilterConfig config) { String param config.getInitParameter(encoding); if(param ! null) this.encoding param; } Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { // 请求到达Servlet前的处理 req.setCharacterEncoding(encoding); resp.setCharacterEncoding(encoding); // 放行到下一个过滤器或Servlet chain.doFilter(req, resp); // 响应返回客户端前的处理 // 可以在这里添加响应头等操作 } }3.3 过滤器执行顺序控制过滤器的执行顺序由以下规则决定web.xml中按配置顺序执行注解方式按类名字母序执行混合配置时web.xml优先实际经验对于有依赖关系的过滤器建议统一使用web.xml配置并明确指定 顺序4. Listener监听器开发技巧4.1 常用监听器类型监听器接口触发时机典型应用ServletContextListener应用启动/关闭初始化全局配置HttpSessionListener会话创建/销毁在线人数统计ServletRequestListener请求开始/结束请求耗时统计4.2 应用启动初始化示例WebListener public class AppInitListener implements ServletContextListener { Override public void contextInitialized(ServletContextEvent sce) { // 创建线程池 ExecutorService pool Executors.newFixedThreadPool(10); sce.getServletContext().setAttribute(threadPool, pool); // 加载系统配置 Properties config loadConfig(); sce.getServletContext().setAttribute(sysConfig, config); } Override public void contextDestroyed(ServletContextEvent sce) { // 优雅关闭线程池 ExecutorService pool (ExecutorService) sce.getServletContext().getAttribute(threadPool); pool.shutdownNow(); } }4.3 监听器使用注意事项性能影响监听器中的逻辑应尽量轻量避免阻塞主流程异常处理监听器中未捕获的异常可能导致应用启动失败作用域管理注意监听器实例的生命周期与作用域5. 三大组件配置方式对比5.1 注解配置 vs web.xml配置配置方式优点缺点注解配置简洁直观与代码结合紧密修改需要重新编译web.xml集中管理可动态调整配置冗长容易出错5.2 企业级应用推荐方案对于大型项目建议采用基础组件使用web.xml集中配置如编码过滤器业务组件使用注解配置如特定功能的Servlet全局监听器混合使用核心监听器用web.xml确保加载顺序6. 常见问题排查指南6.1 过滤器不生效问题可能原因url-pattern配置错误检查是否覆盖目标路径通配符/*要放在最后过滤器链被中断确认调用了chain.doFilter()注解未扫描检查web.xml的metadata-complete属性6.2 内存泄漏问题典型场景在Servlet中缓存了大量数据Listener中持有未释放的资源静态集合持续增长排查工具JDK自带的jvisualvmEclipse Memory Analyzer6.3 线程阻塞问题现象请求响应时间越来越长线程池耗尽解决方案使用异步ServletWebServlet(asyncSupportedtrue))限制业务执行超时时间引入熔断机制7. 性能优化实战技巧7.1 Servlet优化方案启用load-on-startupservlet servlet-nameinitServlet/servlet-name servlet-classcom.example.InitServlet/servlet-class load-on-startup1/load-on-startup /servlet合理使用线程局部变量private static ThreadLocalSimpleDateFormat dateFormat ThreadLocal.withInitial(() - new SimpleDateFormat(yyyy-MM-dd));7.2 Filter性能优化通过FilterConfig缓存配置private MapString,String configMap; public void init(FilterConfig config) { configMap new HashMap(); EnumerationString names config.getInitParameterNames(); while(names.hasMoreElements()) { String name names.nextElement(); configMap.put(name, config.getInitParameter(name)); } }避免在Filter中做耗时IO操作7.3 监听器优化建议使用PostConstruct替代部分初始化逻辑对于高频事件监听考虑事件合并处理异步处理耗时监听逻辑8. 现代框架中的组件演变虽然现在主流使用Spring MVC等框架但理解底层机制仍然重要DispatcherServlet本质仍是ServletSpring拦截器基于Filter机制应用事件基于Listener模式掌握这些基础组件的工作原理能帮助开发者更好地理解框架行为定制特殊需求排查深层问题在实际项目中我通常会根据业务特点混合使用传统组件和框架功能。比如在需要最高性能的接口处直接使用原生Servlet而在业务复杂的模块使用Spring MVC。这种灵活组合往往能取得最佳效果。