SpringBoot 学习第五天:日志框架整合 + AOP 切面编程 + 拦截器机制 + 新面试题(无重复)
SpringBoot 学习第五天:日志框架整合 + AOP 切面编程 + 拦截器机制 + 新面试题(无重复)
一、今日核心目标
-
掌握SpringBoot日志规范(SLF4J+Logback),实现日志分级、文件滚动、多环境配置
-
精通AOP核心原理与5种通知类型,完成接口日志、性能统计实战开发
-
理解SpringMVC拦截器工作机制,实现登录校验、请求拦截等生产级场景
-
掌握Day5专属高频面试题(与Day1-Day4无任何重复),适配面试场景
二、SpringBoot 日志框架整合(生产必备)
2.1 核心规范与默认配置
-
默认组合:SLF4J(日志门面) + Logback(日志实现),SpringBoot自动引入依赖,无需手动添加
-
日志级别(由低到高,优先级递增):TRACE < DEBUG < INFO < WARN < ERROR(默认全局级别为INFO)
-
配置优先级:logback-spring.xml > logback.xml > application.yml/application.properties
2.2 最简配置(application.yml)
logging:
# 全局日志级别(root级别)
level:
root: info
# 自定义包的日志级别(如controller包,方便调试)
com.example.controller: debug
# 日志输出文件(指定路径和文件名)
file:
name: logs/springboot-day5.log
# 控制台输出格式(时间、线程、级别、类名、日志信息)
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n"
# 文件输出格式(新增日志大小、换行标识)
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n"
2.3 日志框架切换(Logback → Log4j2)
实际开发中,若需切换为Log4j2(性能更优,支持异步日志),步骤如下:
-
排除默认Logback依赖(在pom.xml中配置)
-
引入Log4j2 Starter依赖
-
创建log4j2-spring.xml配置文件,配置日志规则
// pom.xml 依赖配置(核心片段)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
// 排除默认Logback依赖
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
// 引入Log4j2依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
三、AOP 面向切面编程(核心原理+实战)
3.1 AOP核心概念(必背)
-
切面(Aspect):横切功能的模块(如日志、权限校验、性能统计),用@Aspect注解标记
-
切点(Pointcut):匹配需要拦截的方法规则,用切点表达式定义
-
通知(Advice):在切点处执行的具体逻辑,分为5种类型
-
连接点(JoinPoint):程序中可被AOP拦截的方法执行点(所有方法均可作为连接点)
3.2 5种通知类型(重点)
| 通知注解 | 执行时机 | 核心作用 |
|---|---|---|
| @Before | 目标方法执行前 | 前置处理(如参数校验、日志记录开始) |
| @AfterReturning | 目标方法正常返回后 | 后置处理(如返回值记录、结果封装) |
| @AfterThrowing | 目标方法抛出异常后 | 异常处理(如异常日志记录、异常通知) |
| @After | 目标方法执行完成后(无论成败) | 最终处理(如资源释放) |
| @Around | 环绕目标方法执行(前后都执行) | 完全控制目标方法(如性能统计、超时控制) |
3.3 切点表达式(常用必背)
核心格式:execution(返回值类型 包路径.类名.方法名(参数类型))
// 1. 匹配com.example.controller包下所有类、所有方法、任意参数(最常用)
@Pointcut("execution(* com.example.controller.*.*(..))")
public void controllerPointcut() {}
// 2. 匹配com.example.service包及子包下所有类的所有方法
@Pointcut("execution(* com.example.service..*.*(..))")
public void servicePointcut() {}
// 3. 匹配指定方法(如UserController的getUserById方法,参数为Long)
@Pointcut("execution(* com.example.controller.UserController.getUserById(Long))")
public void userGetPointcut() {}
通配符说明:* 匹配任意单个字符(如任意返回值、任意类);.. 匹配任意多个字符(如任意参数、任意子包)。
3.4 实战:接口执行耗时统计
用@Around通知实现接口耗时统计,可直接复制到项目中使用:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
// 标记为切面类,并注册到Spring容器
@Aspect
@Component
public class TimeStatisticAspect {
// 定义切点:匹配controller包下所有方法
@Around("execution(* com.example.controller.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
// 1. 方法执行前:记录开始时间
long startTime = System.currentTimeMillis();
// 2. 执行目标方法(核心,不可省略)
Object result = pjp.proceed();
// 3. 方法执行后:计算耗时并打印
long endTime = System.currentTimeMillis();
String methodName = pjp.getSignature().getName(); // 获取方法名
System.out.println("接口【" + methodName + "】执行耗时:" + (endTime - startTime) + "ms");
// 返回目标方法的执行结果(必须返回,否则前端无法获取响应)
return result;
}
}
四、SpringMVC 拦截器(Interceptor)
4.1 核心作用
统一拦截Controller层的请求,用于登录校验、权限控制、请求日志记录、跨域处理等场景,是Web开发中接口安全的重要保障,区别于AOP(AOP可拦截所有方法,拦截器仅拦截Controller请求)。
4.2 实现步骤(三步到位)
-
实现HandlerInterceptor接口,重写核心方法
-
重写preHandle(请求拦截)、postHandle(请求处理后)、afterCompletion(请求完成后)方法
-
通过WebMvcConfigurer注册拦截器,指定拦截路径和排除路径
4.3 实战:登录拦截(生产级场景)
// 1. 自定义拦截器:实现登录校验
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginInterceptor implements HandlerInterceptor {
// 核心方法:请求拦截(Controller执行前),返回true则放行,false则拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从Session中获取登录用户信息
Object user = request.getSession().getAttribute("loginUser");
// 未登录:返回401未授权,拦截请求
if (user == null) {
response.setStatus(401);
response.getWriter().write("请先登录");
return false;
}
// 已登录:放行请求
return true;
}
}
// 2. 注册拦截器
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册登录拦截器
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/login", "/register"); // 排除登录、注册接口(不拦截)
}
}
4.4 拦截器 vs 过滤器(面试易混点)
| 对比维度 | 拦截器(Interceptor) | 过滤器(Filter) |
|---|---|---|
| 所属规范 | SpringMVC组件,依赖Spring容器 | Servlet规范,依赖Web容器(Tomcat等) |
| 执行顺序 | 后执行(在Filter之后) | 先执行(在Interceptor之前) |
| 可操作对象 | 可使用Spring容器中的Bean(如Service),灵活度高 | 仅可操作ServletRequest、ServletResponse,无法直接使用Spring Bean |
| 拦截范围 | 仅拦截Controller请求 | 拦截所有请求(包括静态资源、Servlet请求) |
五、Day5 专属高频面试题(无重复,直接背诵)
基础必背题(入门级)
-
问:SpringBoot默认的日志组合是什么?SLF4J的作用是什么?
答:默认SLF4J(日志门面)+Logback(日志实现);SLF4J的核心作用是统一日志API,解耦具体的日志实现,方便后续切换日志框架(如从Logback切换到Log4j2),无需修改业务代码。 -
问:AOP的5种通知类型分别是什么?各自的执行时机是什么?
答:① @Before:目标方法执行前;② @AfterReturning:目标方法正常返回后;③ @AfterThrowing:目标方法抛出异常后;④ @After:目标方法执行完成后(无论成败);⑤ @Around:环绕目标方法,前后都执行,可控制目标方法的执行。 -
问:SpringMVC拦截器的核心作用是什么?实现步骤有哪些?
答:核心作用是统一拦截Controller请求,用于登录校验、权限控制等场景;实现步骤:1. 实现HandlerInterceptor接口;2. 重写preHandle等核心方法;3. 通过WebMvcConfigurer注册拦截器,指定拦截和排除路径。
进阶高频题(开发级)
-
问:如何将SpringBoot的默认日志框架从Logback切换为Log4j2?
答:三步实现:1. 在pom.xml中排除spring-boot-starter-logging(默认Logback依赖);2. 引入spring-boot-starter-log4j2依赖;3. 创建log4j2-spring.xml配置文件,配置日志级别、输出路径等规则。 -
问:AOP中切点表达式execution的格式是什么?通配符*和..的作用分别是什么?
答:格式:execution(返回值类型 包路径.类名.方法名(参数类型));* 匹配任意单个字符(如任意返回值、任意类);.. 匹配任意多个字符(如任意参数、任意子包)。 -
问:拦截器和过滤器的核心区别是什么?(至少答2点)
答:① 所属规范不同:拦截器是SpringMVC组件,过滤器是Servlet规范;② 执行顺序不同:过滤器先执行,拦截器后执行;③ 可操作对象不同:拦截器可使用Spring Bean,过滤器不可。
原理加分题(面试加分项)
-
问:Spring AOP的底层实现原理是什么?SpringBoot 2.0后默认使用哪种动态代理?
答:底层基于动态代理,分为两种:① JDK动态代理:面向接口,目标类必须实现接口才能使用;② CGLIB动态代理:面向类,通过生成目标类的子类实现代理,无需实现接口;SpringBoot 2.0后默认使用CGLIB动态代理。 -
问:拦截器的preHandle、postHandle、afterCompletion三个方法的执行顺序是什么?
答:执行顺序:preHandle(Controller执行前,请求拦截)→ Controller方法执行 → postHandle(Controller执行后,页面渲染前)→ 页面渲染 → afterCompletion(整个请求完成后,无论成败,用于资源释放)。 -
问:AOP中的@Around通知和其他四种通知的核心区别是什么?
答:@Around是唯一能控制目标方法执行的通知,可通过ProceedingJoinPoint的proceed()方法触发目标方法执行,也可阻止目标方法执行;而其他四种通知(@Before等)只能在目标方法执行前后做辅助处理,无法控制目标方法的执行。
六、Day5 学习总结
今日学习的日志框架、AOP切面编程、拦截器,均为SpringBoot生产级项目必备知识点,且与Day1-Day4(Bean生命周期、自动配置、全局异常等)无任何重复:
-
日志框架:解决项目问题排查、日志审计需求,是项目上线后定位问题的核心工具;
-
AOP:实现横切逻辑复用(如日志、性能统计),减少代码冗余,提升开发效率;
-
拦截器:保障接口安全,实现统一的请求拦截和校验,适配登录、权限等常见场景。
建议结合今日实战代码,手动编写案例验证知识点,同时背诵专属面试题,为后续项目开发和面试做好准备。
(注:文档部分内容可能由 AI 生成)

浙公网安备 33010602011771号