2026/6/20 8:20:40
网站建设
项目流程
邯郸网站建设联系电话,广州手机软件开发制作,软件开发有哪些岗位,网站迁移建设方案在 Spring Boot 框架中#xff0c;内置了许多实用的功能#xff0c;这些功能可以帮助开发者高效地开发和维护应用程序。
一 请求数据记录
Spring Boot提供了一个内置的日志记录解决方案#xff0c;通过 AbstractRequestLoggingFilter 可以记录请求的详细信息。
AbstractR…在 Spring Boot 框架中内置了许多实用的功能这些功能可以帮助开发者高效地开发和维护应用程序。一 请求数据记录Spring Boot提供了一个内置的日志记录解决方案通过 AbstractRequestLoggingFilter 可以记录请求的详细信息。AbstractRequestLoggingFilter 有两个不同的实现类我们常用的是 CommonsRequestLoggingFilter。通过 CommonsRequestLoggingFilter 开发者可以自定义记录请求的参数、请求体、请求头和客户端信息。启用方式很简单加个配置就行了Configuration public 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.CommonsRequestLoggingFilterDEBUG二 请求/响应包装器2.1 什么是请求和响应包装器在 Spring Boot 中请求和响应包装器是用于增强原生 HttpServletRequest 和 HttpServletResponse 对象的功能。这些包装器允许开发者在请求处理过程中拦截和修改请求和响应数据从而实现一些特定的功能如请求内容的缓存、修改、日志记录以及响应内容的修改和增强。请求包装器ContentCachingRequestWrapper这是 Spring 提供的一个请求包装器用于缓存请求的输入流。它允许多次读取请求体这在需要多次处理请求数据如日志记录和业务处理时非常有用。响应包装器ContentCachingResponseWrapper这是 Spring 提供的一个响应包装器用于缓存响应的输出流。它允许开发者在响应提交给客户端之前修改响应体这在需要对响应内容进行后处理如添加额外的头部信息、修改响应体时非常有用。2.2 使用场景请求日志记录在处理请求之前和之后记录请求的详细信息包括请求头、请求参数和请求体。修改请求数据在请求到达控制器之前修改请求数据例如添加或修改请求头。响应内容修改在响应发送给客户端之前修改响应内容例如添加或修改响应头或者对响应体进行签名。性能测试通过缓存请求和响应数据可以进行性能测试而不影响实际的网络 I/O 操作。2.3 具体用法请求包装器的使用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; Component public 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; Component public 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 确保过滤器在一次请求的生命周期中只被调用一次这对于处理请求和响应数据尤为重要因为它避免了在请求转发或包含时重复处理数据。通过使用请求和响应包装器开发者可以在不改变原有业务逻辑的情况下灵活地添加或修改请求和响应的处理逻辑。三 单次过滤器3.1 OncePerRequestFilterOncePerRequestFilter 是 Spring 框架提供的一个过滤器基类它继承自 Filter 接口。这个过滤器具有以下特点单次执行OncePerRequestFilter 确保在一次请求的生命周期内无论请求如何转发forwarding或包含including过滤器逻辑只执行一次。这对于避免重复处理请求或响应非常有用。内置支持它内置了对请求和响应包装器的支持使得开发者可以方便地对请求和响应进行包装和处理。简化代码通过继承 OncePerRequestFilter开发者可以减少重复代码因为过滤器的执行逻辑已经由基类管理。易于扩展开发者可以通过重写 doFilterInternal 方法来实现自己的过滤逻辑而不需要关心过滤器的注册和执行次数。3.2 OncePerRequestFilter 使用场景请求日志记录在请求处理之前和之后记录请求的详细信息如请求头、请求参数和请求体而不希望在请求转发时重复记录。请求数据修改在请求到达控制器之前对请求数据进行预处理或修改例如添加或修改请求头而不希望这些修改在请求转发时被重复应用。响应数据修改在响应发送给客户端之前对响应数据进行后处理或修改例如添加或修改响应头而不希望这些修改在请求包含时被重复应用。安全控制实现安全控制逻辑如身份验证、授权检查等确保这些逻辑在一次请求的生命周期内只执行一次。请求和响应的包装使用 ContentCachingRequestWrapper 和 ContentCachingResponseWrapper 等包装器来缓存请求和响应数据以便在请求处理过程中多次读取或修改数据性能监控在请求处理前后进行性能监控如记录处理时间而不希望这些监控逻辑在请求转发时被重复执行。异常处理在请求处理过程中捕获和处理异常确保异常处理逻辑只执行一次即使请求被转发到其他处理器。通过使用 OncePerRequestFilter开发者可以确保过滤器逻辑在一次请求的生命周期内只执行一次从而避免重复处理和潜在的性能问题。这使得 OncePerRequestFilter 成为处理复杂请求和响应逻辑时的一个非常有用的工具。OncePerRequestFilter 的具体用法松哥就不举例了第二小节已经介绍过了四 AOP 三件套在 Spring 框架中AOP面向切面编程是一个强大的功能它允许开发者在不修改源代码的情况下对程序的特定部分进行横向切入。AopContext、AopUtils 和 ReflectionUtils 是 Spring AOP 中提供的几个实用类。我们一起来看下。4.1 AopContextAopContext 是 Spring 框架中的一个类它提供了对当前 AOP 代理对象的访问以及对目标对象的引用。AopContext 主要用于获取当前代理对象的相关信息以及在 AOP 代理中进行一些特定的操作。常见方法有两个getTargetObject(): 获取当前代理的目标对象。currentProxy(): 获取当前的代理对象。其中第二个方法在防止同一个类中注解失效的时候可以通过该方法获取当前类的代理对象。举个栗子public void noTransactionTask(String keyword){ // 注意这里 调用了代理类的方法 ((YourClass) AopContext.currentProxy()).transactionTask(keyword); } Transactional void transactionTask(String keyword) { try { Thread.sleep(5000); } catch (InterruptedException e) { //logger //error tracking } System.out.println(keyword); }同一个类中两个方法noTransactionTask 方法调用 transactionTask 方法为了使事务注解不失效就可以使用 AopContext.currentProxy() 去获取当前代理对象。4.2 AopUtilsAopUtils 提供了一些静态方法来处理与 AOP 相关的操作如获取代理对象、获取目标对象、判断代理类型等。常见方法有三个getTargetObject(): 从代理对象中获取目标对象。isJdkDynamicProxy(Object obj): 判断是否是 JDK 动态代理。isCglibProxy(Object obj): 判断是否是 CGLIB 代理。举个栗子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 代理对象); } } }4.3 ReflectionUtilsReflectionUtils 提供了一系列反射操作的便捷方法如设置字段值、获取字段值、调用方法等。这些方法封装了 Java 反射 API 的复杂性使得反射操作更加简单和安全。常见方法makeAccessible(Field field): 使私有字段可访问。getField(Field field, Object target): 获取对象的字段值。invokeMethod(Method method, Object target, Object... args): 调用对象的方法。举个栗子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 MapString, String mapAttribute; public void setMapAttribute(MapString, String mapAttribute) { this.mapAttribute mapAttribute; } } }还有哪些实用内置类呢欢迎小伙伴们留言