稀土掘金技术社区 2024年12月14日
请不要自己写,Spring Boot非常实用的内置功能
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

文章介绍了Spring Boot框架中的多种内置功能,包括请求数据记录、请求/响应包装器、单次过滤器OncePerRequestFilter、AOP三件套等,帮助开发者高效开发和维护应用程序。

🎯Spring Boot内置日志记录,通过AbstractRequestLoggingFilter记录请求详细信息,常用CommonsRequestLoggingFilter,可自定义记录内容,启用需配置。

📦请求和响应包装器,包括ContentCachingRequestWrapper和ContentCachingResponseWrapper,可用于多种场景,如请求日志记录、数据修改等,通过OncePerRequestFilter确保过滤器单次执行。

🔍OncePerRequestFilter是Spring框架提供的过滤器基类,具有单次执行、内置支持、简化代码、易于扩展等特点,适用于多种场景。

🎁AOP三件套AopContext、AopUtils和ReflectionUtils,AopContext用于获取代理对象信息,AopUtils处理AOP相关操作,ReflectionUtils提供反射操作便捷方法。

江南一点雨 2024-12-14 09:03 重庆

点击关注公众号,“技术干货” 及时达!

在 Spring Boot 框架中,内置了许多实用的功能,这些功能可以帮助开发者高效地开发和维护应用程序。

松哥来和大家列举几个。

一 请求数据记录

Spring Boot提供了一个内置的日志记录解决方案,通过 AbstractRequestLoggingFilter 可以记录请求的详细信息。

AbstractRequestLoggingFilter 有两个不同的实现类,我们常用的是 CommonsRequestLoggingFilter

通过 CommonsRequestLoggingFilter 开发者可以自定义记录请求的参数、请求体、请求头和客户端信息。

启用方式很简单,加个配置就行了:

@Configurationpublic class RequestLoggingConfig {    @Bean    public CommonsRequestLoggingFilter logFilter() {        CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();        filter.setIncludeQueryString(true);        filter.setIncludePayload(true);        filter.setIncludeHeaders(true);        filter.setIncludeClientInfo(true);        filter.setAfterMessagePrefix("REQUEST DATA-");        return filter;    }}

接下来需要配置日志级别为 DEBUG,就可以详细记录请求信息:

logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG

二 请求/响应包装器

什么是请求和响应包装器

在 Spring Boot 中,请求和响应包装器是用于增强原生 HttpServletRequestHttpServletResponse 对象的功能。这些包装器允许开发者在请求处理过程中拦截和修改请求和响应数据,从而实现一些特定的功能,如请求内容的缓存、修改、日志记录,以及响应内容的修改和增强。

请求包装器

响应包装器

使用场景

    「请求日志记录」:在处理请求之前和之后记录请求的详细信息,包括请求头、请求参数和请求体。

    「修改请求数据」:在请求到达控制器之前修改请求数据,例如添加或修改请求头。

    「响应内容修改」:在响应发送给客户端之前修改响应内容,例如添加或修改响应头,或者对响应体进行签名。

    「性能测试」:通过缓存请求和响应数据,可以进行性能测试,而不影响实际的网络 I/O 操作。

具体用法

请求包装器的使用

import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;
@Componentpublic class RequestWrapperFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request); // 可以在这里处理请求数据 byte[] body = requestWrapper.getContentAsByteArray(); // 处理body,例如记录日志 //。。。 filterChain.doFilter(requestWrapper, response); }}

响应包装器的使用

import org.springframework.web.filter.OncePerRequestFilter;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;
@Componentpublic class ResponseWrapperFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); filterChain.doFilter(request, responseWrapper);
// 可以在这里处理响应数据 byte[] body = responseWrapper.getContentAsByteArray(); // 处理body,例如添加签名 responseWrapper.setHeader("X-Signature", "some-signature");
// 必须调用此方法以将响应数据发送到客户端 responseWrapper.copyBodyToResponse(); }}

在上面的案例中,OncePerRequestFilter 确保过滤器在一次请求的生命周期中只被调用一次,这对于处理请求和响应数据尤为重要,因为它避免了在请求转发或包含时重复处理数据。

通过使用请求和响应包装器,开发者可以在不改变原有业务逻辑的情况下,灵活地添加或修改请求和响应的处理逻辑。

三 单次过滤器

OncePerRequestFilter

OncePerRequestFilter 是 Spring 框架提供的一个过滤器基类,它继承自 Filter 接口。这个过滤器具有以下特点:

    「单次执行」OncePerRequestFilter 确保在一次请求的生命周期内,无论请求如何转发(forwarding)或包含(including),过滤器逻辑只执行一次。这对于避免重复处理请求或响应非常有用。

    「内置支持」:它内置了对请求和响应包装器的支持,使得开发者可以方便地对请求和响应进行包装和处理。

    「简化代码」:通过继承 OncePerRequestFilter,开发者可以减少重复代码,因为过滤器的执行逻辑已经由基类管理。

    「易于扩展」:开发者可以通过重写 doFilterInternal 方法来实现自己的过滤逻辑,而不需要关心过滤器的注册和执行次数。

OncePerRequestFilter 使用场景

    「请求日志记录」:在请求处理之前和之后记录请求的详细信息,如请求头、请求参数和请求体,而不希望在请求转发时重复记录。

    「请求数据修改」:在请求到达控制器之前,对请求数据进行预处理或修改,例如添加或修改请求头,而不希望这些修改在请求转发时被重复应用。

    「响应数据修改」:在响应发送给客户端之前,对响应数据进行后处理或修改,例如添加或修改响应头,而不希望这些修改在请求包含时被重复应用。

    「安全控制」:实现安全控制逻辑,如身份验证、授权检查等,确保这些逻辑在一次请求的生命周期内只执行一次。

    「请求和响应的包装」:使用 ContentCachingRequestWrapperContentCachingResponseWrapper 等包装器来缓存请求和响应数据,以便在请求处理过程中多次读取或修改数据。

    「性能监控」:在请求处理前后进行性能监控,如记录处理时间,而不希望这些监控逻辑在请求转发时被重复执行。

    「异常处理」:在请求处理过程中捕获和处理异常,确保异常处理逻辑只执行一次,即使请求被转发到其他处理器。

通过使用 OncePerRequestFilter,开发者可以确保过滤器逻辑在一次请求的生命周期内只执行一次,从而避免重复处理和潜在的性能问题。这使得 OncePerRequestFilter 成为处理复杂请求和响应逻辑时的一个非常有用的工具。

OncePerRequestFilter 的具体用法松哥就不举例了,第二小节已经介绍过了。

四 AOP 三件套

在 Spring 框架中,AOP(面向切面编程)是一个强大的功能,它允许开发者在不修改源代码的情况下,对程序的特定部分进行横向切入。AopContextAopUtilsReflectionUtils 是 Spring AOP 中提供的几个实用类。

我们一起来看下。

AopContext

AopContext 是 Spring 框架中的一个类,它提供了对当前 AOP 代理对象的访问,以及对目标对象的引用。

AopContext 主要用于获取当前代理对象的相关信息,以及在 AOP 代理中进行一些特定的操作。

「常见方法有两个:」

其中第二个方法,在防止同一个类中注解失效的时候,可以通过该方法获取当前类的代理对象。

「举个栗子:」

public void noTransactionTask(String keyword){    // 注意这里 调用了代理类的方法    ((YourClass) AopContext.currentProxy()).transactionTask(keyword);}
@Transactionalvoid transactionTask(String keyword) { try { Thread.sleep(5000); } catch (InterruptedException e) { //logger //error tracking } System.out.println(keyword);}

同一个类中两个方法,noTransactionTask 方法调用 transactionTask 方法,为了使事务注解不失效,就可以使用 AopContext.currentProxy() 去获取当前代理对象。

AopUtils

AopUtils 提供了一些静态方法来处理与 AOP 相关的操作,如获取代理对象、获取目标对象、判断代理类型等。

「常见方法有三个:」

「举个栗子:」

import org.springframework.aop.framework.AopProxyUtils;import org.springframework.aop.support.AopUtils;
public class AopUtilsExample { public static void main(String[] args) { MyService myService = ... // 假设 myService 已经被代理 if (AopUtils.isCglibProxy(myService)) { System.out.println("这是一个 CGLIB 代理对象"); } }}

ReflectionUtils

ReflectionUtils 提供了一系列反射操作的便捷方法,如设置字段值、获取字段值、调用方法等。这些方法封装了 Java 反射 API 的复杂性,使得反射操作更加简单和安全。

「常见方法:」

「举个栗子:」

import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;import java.util.Map;
public class ReflectionUtilsExample { public static void main(String[] args) throws Exception { ExampleBean bean = new ExampleBean(); bean.setMapAttribute(new HashMap<>());
Field field = ReflectionUtils.findField(ExampleBean.class, "mapAttribute"); ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, bean); System.out.println(value); }
static class ExampleBean { private Map<String, String> mapAttribute;
public void setMapAttribute(Map<String, String> mapAttribute) { this.mapAttribute = mapAttribute; } }}

还有哪些实用内置类呢?欢迎小伙伴们留言~

点击关注公众号,“技术干货” 及时达!

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Spring Boot 请求数据记录 请求/响应包装器 OncePerRequestFilter AOP三件套
相关文章