过滤器(Filter)本质上是基于 Servlet 规范的组件,而 Spring Boot 是对 Servlet 容器(如 Tomcat、Jetty 等)的封装和简化
一、Servlet 的定义Servlet 是 JavaEE 规范中定义的接口,用于处理客户端(如浏览器)的 HTTP 请求并返回响应。它是运行在 Web 服务器(如 Tomcat)中的 Java 程序,是 Web 应用的 “控制器”,负责接收请求、处理业务逻辑、调用模型层,并将结果返回给视图层。二、Servlet 的核心作用处理 HTTP 请求与响应:接收客户端的请求(如 GET、POST 请求),解析请求参数(如表单数据、URL 参数)。生成响应内容(如 HTML、JSON 数据),并返回给客户端。动态生成内容:区别于静态 HTML,Servlet 可根据请求动态生成内容(如用户登录后的个性化页面)。衔接前后端逻辑:作为 Web 应用的中间层,连接前端页面与后端数据库、服务层,实现数据交互。三、Servlet 的工作原理(生命周期)Servlet 的生命周期由 Web 容器(如 Tomcat)管理,分为三个阶段,通过接口方法实现:
- 初始化阶段(init)
当 Web 容器启动或接收到第一个请求时,创建 Servlet 实例,并调用init(ServletConfig config)方法。
该方法仅执行一次,用于加载资源(如数据库连接)。 - 服务阶段(service)
接收到请求后,容器调用service(ServletRequest req, ServletResponse res)方法。
该方法会根据请求类型(GET/POST 等),转发至对应的处理方法:
doGet():处理 GET 请求(如查询数据)。
doPost():处理 POST 请求(如提交表单)。
每次请求都会触发service()方法,但 Servlet 实例是单例的(多线程共享),需注意线程安全。 - 销毁阶段(destroy)
当 Web 容器关闭或应用卸载时,调用destroy()方法。
用于释放资源(如关闭数据库连接),仅执行一次。
四、Servlet 的关键接口与类
核心接口:javax.servlet.Servlet
定义了三个生命周期方法(init、service、destroy),以及获取配置信息的方法。
常用实现类:HttpServlet
继承自GenericServlet,专门处理 HTTP 请求,重写service()方法以区分 GET/POST 等请求类型。
开发中通常继承HttpServlet,重写doGet/doPost等方法。
五、Servlet 与 Web 容器的关系
容器负责管理 Servlet 生命周期:创建、初始化、调用、销毁 Servlet 实例。
容器提供请求 / 响应封装:将 HTTP 请求封装为HttpServletRequest对象,响应封装为HttpServletResponse对象,供 Servlet 使用。
常见 Web 容器:Tomcat、Jetty、WildFly 等。
六、Servlet 的应用场景
传统 Java Web 应用:如早期的企业级网站、管理系统,通过 Servlet 处理业务逻辑。
作为 MVC 框架的基础:如 Spring MVC 中的DispatcherServlet,本质上也是 Servlet 的扩展,负责请求分发。
七、面试中可能延伸的问题
Servlet 如何处理多线程请求?
Servlet 是单例的,多请求共享同一个实例,需避免在实例中存储线程不安全的变量(如成员变量),可使用局部变量或线程安全的工具类(如ThreadLocal)。
Servlet 与 JSP 的区别?
Servlet 是 Java 代码,专注于逻辑处理;JSP 是嵌入 Java 代码的 HTML,更适合视图渲染。JSP 本质上会编译为 Servlet 运行。
通过以上内容,你可以清晰说明 Servlet 的定义、原理及应用,展现对 Java Web 基础的理解。如果面试官进一步追问,可以结合生命周期、线程安全等细节深入回答。
问题二:一、AOP 的核心定义与背景
定义:
AOP 通过将程序中的横切逻辑(如日志、事务、权限校验) 与核心业务逻辑分离,实现代码的解耦。横切逻辑指的是多个业务模块中重复出现的逻辑,若使用 OOP 实现,会导致代码冗余(如在每个方法中重复编写日志代码)。
与 OOP 的关系:
OOP 以 “对象” 为核心,解决纵向业务逻辑(如用户管理、订单处理)。
AOP 以 “切面” 为核心,解决横向重复逻辑,是 OOP 的补充而非替代。
二、AOP 的核心概念(必背考点)
概念 解释 示例(日志切面)
切面(Aspect) 封装横切逻辑的类,定义切入点和通知的组合。 LogAspect类,包含记录日志的逻辑。
通知(Advice) 横切逻辑的具体实现,定义 “何时” 及 “如何” 执行。 @Before(方法前执行日志记录)、@After(方法后记录)。
连接点(Joinpoint) 程序执行中的特定点(如方法调用、字段修改),AOP 可干预的位置。 所有Service层的方法调用都是连接点。
切入点(Pointcut) 定义通知作用的具体位置,通过表达式匹配连接点。 execution(* com.service..(..)):匹配Service包下所有方法。
目标对象(Target) 被切面代理的对象,即横切逻辑应用的对象。 UserService对象,其方法会被日志切面拦截。
代理(Proxy) AOP 通过代理模式实现对目标对象的增强,分为静态代理和动态代理。 Spring AOP 使用动态代理(JDK 代理或 CGLIB 代理)生成目标对象的代理对象。
三、通知(Advice)的类型(重点)
AOP 定义了 5 种通知类型,对应横切逻辑的不同执行时机:
- 前置通知(@Before)
时机:目标方法执行前。
应用:权限校验、参数日志记录。
java
@Before(“execution(* com.service..(..))”)
public void beforeLog() {
System.out.println(“方法执行前:记录参数…”);
}
- 后置通知(@After)
时机:目标方法正常执行后(无论是否有返回值)。
应用:资源清理、通用日志记录。
java
@After(“…”)
public void afterLog() {
System.out.println(“方法执行后:记录耗时…”);
}
- 返回通知(@AfterReturning)
时机:目标方法返回结果后。
应用:结果日志记录、数据格式转换。
java
@AfterReturning(pointcut = “…”, returning = “result”)
public void afterReturningLog(Object result) {
System.out.println(“方法返回后:结果为 ” + result);
}
- 异常通知(@AfterThrowing)
时机:目标方法抛出异常时。
应用:异常日志记录、事务回滚。
java
@AfterThrowing(pointcut = “…”, throwing = “ex”)
public void afterThrowingLog(Exception ex) {
System.out.println(“方法异常:” + ex.getMessage());
}
- 环绕通知(@Around)
时机:包裹目标方法,可控制方法的执行(如提前 / 延迟执行,甚至不执行)。
应用:事务管理(开启事务→执行方法→提交 / 回滚事务)、性能监控。
java
@Around(“execution(* com.service..(..))”)
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed(); // 执行目标方法
long end = System.currentTimeMillis();
System.out.println(“方法耗时:” + (end – start) + “ms”);
return result;
}
四、AOP 的实现原理(面试高频)
AOP 的核心是代理模式,根据代理生成时机分为:
动态代理(运行期生成)
代表:Spring AOP(默认实现)。
实现方式:
JDK 代理:基于接口实现(目标对象必须实现接口),通过InvocationHandler动态生成代理类。
CGLIB 代理:基于类继承(生成目标类的子类),通过字节码生成库实现,无需接口。
代理选择:
若目标对象有接口,Spring 使用 JDK 代理;若无接口,自动切换为 CGLIB 代理(需引入cglib依赖)。
五、Spring AOP 的实际应用场景
事务管理:
通过@Transactional注解,在方法调用前后自动管理数据库事务(开启、提交、回滚)。
日志记录:
自动记录方法的入参、出参和执行耗时,避免在业务代码中硬编码日志逻辑。
权限校验:
在接口调用前校验用户权限,如@PreAuthorize(“hasRole(‘ADMIN’)”)。
缓存处理:
如@Cacheable注解,自动处理缓存的查询和写入,减少数据库访问。
性能监控:
统计方法执行耗时,定位系统瓶颈(如使用@Around记录耗时)
静态代理(编译期生成)
代表:AspectJ(需编译器支持)。
原理:在编译阶段将切面代码织入目标类,生成新的字节码文件。
特点:性能高,但需修改编译流程。
在 Redis 中,持久化是将内存数据保存到磁盘的机制,用于在重启后恢复数据。Redis 提供了两种主要的持久化方式:RDB(快照) 和 AOF(追加日志)