1. 基础概念与原理
JavaServlet 是运行在 Web 服务器上的小型 Java 程序,用于处理客户端请求并生成动态响应。它是 Java EE 平台的核心组件之一,主要用于开发 Web 应用程序。
核心原理:
- Servlet 容器(如 Tomcat)负责加载和管理 Servlet 生命周期
- 客户端请求通过 HTTP 协议发送到服务器,由容器将请求分发到对应 Servlet
- Servlet 通过实现
doGet()
、doPost()
等方法处理请求,并返回响应 - 采用多线程模型,每个请求由独立线程处理,需注意线程安全问题
2. 生命周期详解
Servlet 生命周期由容器管理,包含以下阶段:
public class MyServlet extends HttpServlet {
// 1. 初始化方法,容器加载Servlet时调用(单例)
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("Servlet初始化完成");
}
// 2. 处理GET请求
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().println("Hello from GET");
}
// 3. 处理POST请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().println("Hello from POST");
}
// 4. 销毁方法,容器卸载Servlet时调用
@Override
public void destroy() {
System.out.println("Servlet即将销毁");
}
}
3. 请求与响应处理
请求处理示例:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取请求参数
String username = request.getParameter("username");
// 获取请求头
String userAgent = request.getHeader("User-Agent");
// 设置响应内容类型
response.setContentType("text/html;charset=UTF-8");
// 获取输出流
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>欢迎 " + username + "</h1>");
out.println("</body></html>");
}
请求转发与重定向:
// 请求转发(服务器内部跳转)
request.getRequestDispatcher("/target.jsp").forward(request, response);
// 重定向(客户端跳转)
response.sendRedirect("/contextPath/target.jsp");
4. 高级特性
过滤器(Filter):
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 设置请求编码
request.setCharacterEncoding("UTF-8");
// 传递请求到下一个过滤器或Servlet
chain.doFilter(request, response);
// 响应处理(可在此添加响应处理逻辑)
}
}
监听器(Listener):
public class SessionCounterListener implements HttpSessionListener {
private static int activeSessions = 0;
@Override
public void sessionCreated(HttpSessionEvent se) {
activeSessions++;
System.out.println("新会话创建,当前活跃会话: " + activeSessions);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
activeSessions--;
System.out.println("会话销毁,当前活跃会话: " + activeSessions);
}
}
5. 异步 Servlet 处理
Java Servlet 3.0 引入异步处理支持,适用于长耗时操作:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 开启异步处理
AsyncContext asyncContext = request.startAsync();
// 设置超时时间
asyncContext.setTimeout(30000);
// 启动异步线程处理
asyncContext.start(() -> {
try {
// 模拟耗时操作
Thread.sleep(5000);
// 获取响应并输出
PrintWriter out = asyncContext.getResponse().getWriter();
out.println("异步处理完成");
// 完成异步处理
asyncContext.complete();
} catch (Exception e) {
e.printStackTrace();
}
});
}
6. 与 Spring 框架集成
Servlet 与 Spring 集成是现代 Java Web 开发的主流方式:
// 配置Spring MVC DispatcherServlet
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 创建Spring应用上下文
AnnotationConfigWebApplicationContext context =
new AnnotationConfigWebApplicationContext();
context.register(AppConfig.class);
// 添加DispatcherServlet
DispatcherServlet dispatcherServlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration =
servletContext.addServlet("dispatcher", dispatcherServlet);
// 设置映射路径
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
7. 面试常考问题
-
Servlet 与 CGI 的区别
- Servlet 在服务器进程内运行,效率高;CGI 为每个请求创建新进程
- Servlet 线程安全需开发者处理;CGI 无此问题
- Servlet 可管理会话状态;CGI 需依赖外部机制
-
Servlet 线程安全问题
- 多个请求可能同时访问同一个 Servlet 实例
- 避免使用实例变量,或使用 ThreadLocal 存储线程私有数据
- 可使用
synchronized
关键字,但可能影响性能
-
Servlet 生命周期关键方法
init()
:初始化 Servlet(单例)service()
:处理请求的核心方法destroy()
:Servlet 销毁前调用
-
请求转发与重定向的区别
- 转发是服务器内部跳转,地址栏不变
- 重定向是客户端跳转,地址栏改变
- 转发效率高,重定向更灵活
-
过滤器的应用场景
- 字符编码处理
- 权限验证
- 日志记录
- 敏感信息过滤
8. 性能优化与最佳实践
-
合理配置线程池
- 在 Servlet 容器中调整线程池参数,避免创建过多线程
- 如 Tomcat 的
maxThreads
、acceptCount
等参数
-
使用异步处理
- 对于长耗时操作(如 IO 密集型任务),使用异步 Servlet
-
避免阻塞操作
- 数据库查询、网络调用等应使用连接池和异步 API
-
适当缓存
- 使用 ServletContext 缓存常用数据
- 考虑使用分布式缓存(如 Redis)
-
安全加固
- 防止 SQL 注入和 XSS 攻击
- 合理设置 HTTP 头(如 CSP、X-Frame-Options)
- 避免暴露敏感信息