iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >springboot有哪些实现拦截器的方式及异步执行是什么
  • 269
分享到

springboot有哪些实现拦截器的方式及异步执行是什么

2023-06-20 14:06:05 269人浏览 泡泡鱼
摘要

这篇文章主要讲解了“SpringBoot有哪些实现拦截器的方式及异步执行是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot有哪些实现拦截器的方式及异步执行是什么”吧!目

这篇文章主要讲解了“SpringBoot有哪些实现拦截器的方式及异步执行是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot有哪些实现拦截器的方式及异步执行是什么”吧!

目录
  • springboot 拦截器

  • springboot 入门案例

    • Maven 引入

    • 启动类

    • 定义 Controller

  • 拦截器定义

    • 基于 Aspect

  • 基于 HandlerInterceptor

    • 基于 ResponseBodyAdvice

    • 异步执行

      • 定义异步线程池

      • 异步执行的 Controller

      • 思考

      • 测试

    • 反思

      springboot 拦截器

      实际项目中,我们经常需要输出请求参数,响应结果,方法耗时,统一的权限校验等。

      本文首先为大家介绍 Http 请求中三种常见的拦截实现,并且比较一下其中的差异。
      (1)基于 Aspect 的拦截器
      (2)基于 HandlerInterceptor 的拦截器
      (3)基于 ResponseBodyAdvice 的拦截器

      推荐阅读:

      统一日志框架: https://GitHub.com/houbb/auto-log

      springboot有哪些实现拦截器的方式及异步执行是什么

      springboot 入门案例

      为了便于大家学习,我们首先从最基本的 springboot 例子讲起。

      maven 引入

      引入必须的 jar 包。

      <parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>1.5.9.RELEASE</version></parent><dependencies>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-WEB</artifactId>    </dependency>    <dependency>        <groupId>org.aspectj</groupId>        <artifactId>aspectjrt</artifactId>        <version>1.8.10</version>    </dependency>    <dependency>        <groupId>org.aspectj</groupId>        <artifactId>aspectjweaver</artifactId>        <version>1.8.10</version>    </dependency></dependencies><!-- Package as an executable jar --><build>    <plugins>        <plugin>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-maven-plugin</artifactId>        </plugin>    </plugins></build>

      启动类

      实现最简单的启动类。

      @SpringBootApplicationpublic class Application {    public static void main(String[] args) {        SpringApplication.run(Application.class, args);    }}

      定义 Controller

      为了演示方便,我们首先实现一个简单的 controller。

      @RestControllerpublic class IndexController {    @RequestMapping("/index")    public AsyncResp index() {        AsyncResp asyncResp = new AsyncResp();        asyncResp.setResult("ok");        asyncResp.setRespCode("00");        asyncResp.setRespDesc("成功");        System.out.println("IndexController#index:" + asyncResp);        return asyncResp;    }}

      其中 AsyncResp 的定义如下:

      public class AsyncResp {    private String respCode;    private String respDesc;    private String result;    // getter & setter & toString()}

      拦截器定义

      基于 Aspect

      import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.annotation.EnableAspectJAutoProxy;import org.springframework.stereotype.Component;import java.util.Arrays;@Aspect@Component@EnableAspectJAutoProxypublic class AspectLogInterceptor {        private static final Logger LOG = LoggerFactory.getLogger(AspectLogInterceptor.class);        @Pointcut("execution(public * com.github.houbb.springboot.learn.aspect.controller..*(..))")    public void pointCut() {        //    }        @Around("pointCut()")    public Object around(ProceedingJoinPoint point) throws Throwable {        try {            //1. 设置 MDC            // 获取当前拦截的方法签名            String signatureShortStr = point.getSignature().toShortString();            //2. 打印入参信息            Object[] args = point.getArgs();            LOG.info("{} 参数: {}", signatureShortStr, Arrays.toString(args));            //3. 打印结果            Object result = point.proceed();            LOG.info("{} 结果: {}", signatureShortStr, result);            return result;        } finally {            // 移除 mdc        }    }}

      这种实现的优点是比较通用,可以结合注解实现更加灵活强大的功能。

      是个人非常喜欢的一种方式。
      主要用途:
      (1)日志的出参/入参
      (2)统一设置 TraceId
      (3)方法的调用耗时统计

      基于 HandlerInterceptor

      import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.DispatcherType;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@Componentpublic class LogHandlerInterceptor implements HandlerInterceptor {    private Logger logger = LoggerFactory.getLogger(LogHandlerInterceptor.class);    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        // 统一的权限校验、路由等        logger.info("LogHandlerInterceptor#preHandle 请求地址:{}", request.getRequestURI());        if (request.getDispatcherType().equals(DispatcherType.ASYNC)) {            return true;        }        return true;    }    @Override    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {        logger.info("LogHandlerInterceptor#postHandle 调用");    }    @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {    }}

      然后需要指定对应的 url 和拦截器之间的关系才会生效:

      import com.github.houbb.springboot.learn.aspect.aspect.LogHandlerInterceptor;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorReGIStry;import org.springframework.web.servlet.config.annotation.WebmvcConfigurerAdapter;@Configurationpublic class springMVCConfig extends WebMvcConfigurerAdapter {    @Autowired    private LogHandlerInterceptor logHandlerInterceptor;    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(logHandlerInterceptor)                .addPathPatterns("@ControllerAdvicepublic class MyResponseBodyAdvice implements ResponseBodyAdvice<Object> {        private static final Logger LOG = LoggerFactory.getLogger(MyResponseBodyAdvice.class);    @Override    public boolean supports(MethodParameter methodParameter, Class aClass) {        //这个地方如果返回false, 不会执行 beforeBodyWrite 方法        return true;    }    @Override    public Object beforeBodyWrite(Object resp, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {        String uri = serverHttpRequest.getURI().getPath();        LOG.info("MyResponseBodyAdvice#beforeBodyWrite 请求地址:{}", uri);        ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) serverHttpRequest;        HttpServletRequest servletRequest = servletServerHttpRequest.getServletRequest();        // 可以做统一的拦截器处理        // 可以对结果做动态修改等        LOG.info("MyResponseBodyAdvice#beforeBodyWrite 响应结果:{}", resp);        return resp;    }}

      测试

      我们启动应用,页面访问:
      http://localhost:18080/index
      页面响应:
      {"respCode":"00","respDesc":"成功","result":"ok"}

      后端日志:

      c.g.h.s.l.a.a.LogHandlerInterceptor      : LogHandlerInterceptor#preHandle 请求地址:/index
      c.g.h.s.l.a.aspect.AspectLogInterceptor  : IndexController.index() 参数: []
      IndexController#index:AsyncResp{respCode='00', respDesc='成功', result='ok'}
      c.g.h.s.l.a.aspect.AspectLogInterceptor  : IndexController.index() 结果: AsyncResp{respCode='00', respDesc='成功', result='ok'}
      c.g.h.s.l.a.aspect.MyResponseBodyAdvice  : MyResponseBodyAdvice#beforeBodyWrite 请求地址:/index
      c.g.h.s.l.a.aspect.MyResponseBodyAdvice  : MyResponseBodyAdvice#beforeBodyWrite 响应结果:AsyncResp{respCode='00', respDesc='成功', result='ok'}
      c.g.h.s.l.a.a.LogHandlerInterceptor      : LogHandlerInterceptor#postHandle 调用

      这里执行的先后顺序也比较明确,此处不再赘述。

      异步执行

      当然,如果只是上面这些内容,并不是本篇文章的重点。
      接下来,我们一起来看下,如果引入了异步执行会怎么样。

      定义异步线程

      springboot 中定义异步线程池,非常简单。

      import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.task.AsyncTaskExecutor;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configuration@EnableAsyncpublic class SpringAsyncConfig {    @Bean(name = "asyncPoolTaskExecutor")    public AsyncTaskExecutor taskExecutor() {        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();        executor.setMaxPoolSize(10);        executor.setQueueCapacity(10);        executor.setCorePoolSize(10);        executor.setWaitForTasksToCompleteOnShutdown(true);        return executor;    }}

      异步执行的 Controller

      @RestControllerpublic class MyAsyncController extends BaseAsyncController<String> {    @Override    protected String process(HttpServletRequest request) {        return "ok";    }    @RequestMapping("/async")    public AsyncResp hello(HttpServletRequest request) {        AsyncResp resp = super.execute(request);        System.out.println("Controller#async 结果:" + resp);        return resp;    }}

      其中 BaseAsyncController 的实现如下:

      @RestControllerpublic abstract class BaseAsyncController<T> {    protected abstract T process(HttpServletRequest request);    @Autowired    private AsyncTaskExecutor taskExecutor;    protected AsyncResp execute(HttpServletRequest request) {        // 异步响应结果        AsyncResp resp = new AsyncResp();        try {            taskExecutor.execute(new Runnable() {                @Override                public void run() {                    try {                        T result = process(request);                        resp.setRespCode("00");                        resp.setRespDesc("成功");                        resp.setResult(result.toString());                    } catch (Exception exception) {                        resp.setRespCode("98");                        resp.setRespDesc("任务异常");                    }                }            });        } catch (TaskRejectedException e) {            resp.setRespCode("99");            resp.setRespDesc("任务拒绝");        }        return resp;    }}

      execute 的实现也比较简单:
      (1)主线程创建一个 AsyncResp,用于返回。
      (2)线程池异步执行具体的子类方法,并且设置对应的值。

      思考

      接下来,问大家一个问题。
      如果我们请求 http://localhost:18080/async,那么:
      (1)页面得到的返回值是什么?
      (2)Aspect 日志输出的返回值是?
      (3)ResponseBodyAdvice 日志输出的返回值是什么?
      你可以在这里稍微停一下,记录下你的答案。

      测试

      我们页面请求 http://localhost:18080/async。

      页面响应如下:

      {"respCode":"00","respDesc":"成功","result":"ok"}

      后端的日志:

      c.g.h.s.l.a.a.LogHandlerInterceptor      : LogHandlerInterceptor#preHandle 请求地址:/async
      c.g.h.s.l.a.aspect.AspectLogInterceptor  : MyAsyncController.hello(..) 参数: [org.apache.catalina.connector.RequestFacade@7e931750]
      Controller#async 结果:AsyncResp{respCode='null', respDesc='null', result='null'}
      c.g.h.s.l.a.aspect.AspectLogInterceptor  : MyAsyncController.hello(..) 结果: AsyncResp{respCode='null', respDesc='null', result='null'}
      c.g.h.s.l.a.aspect.MyResponseBodyAdvice  : MyResponseBodyAdvice#beforeBodyWrite 请求地址:/async
      c.g.h.s.l.a.aspect.MyResponseBodyAdvice  : MyResponseBodyAdvice#beforeBodyWrite 响应结果:AsyncResp{respCode='00', respDesc='成功', result='ok'}
      c.g.h.s.l.a.a.LogHandlerInterceptor      : LogHandlerInterceptor#postHandle 调用

      对比一下,可以发现我们上面问题的答案:
      (1)页面得到的返回值是什么?

      {"respCode":"00","respDesc":"成功","result":"ok"}

      可以获取到异步执行完成的结果。
      (2)Aspect 日志输出的返回值是?

      AsyncResp{respCode='null', respDesc='null', result='null'}

      无法获取异步结果。
      (3)ResponseBodyAdvice 日志输出的返回值是什么?

      AsyncResp{respCode='00', respDesc='成功', result='ok'}

      可以获取到异步执行完成的结果。

      反思

      可以发现,spring 对于页面的响应也许和我们想的有些不一样,并不是直接获取同步结果。
      写到这里,发现自己对于 mvc 的理解一直只是停留在表面,没有真正理解整个流程。
      Aspect 的形式在很多框架中都会使用,不过这里会发现无法获取异步的执行结果,存在一定问题。

      感谢各位的阅读,以上就是“springboot有哪些实现拦截器的方式及异步执行是什么”的内容了,经过本文的学习后,相信大家对springboot有哪些实现拦截器的方式及异步执行是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

      --结束END--

      本文标题: springboot有哪些实现拦截器的方式及异步执行是什么

      本文链接: https://www.lsjlt.com/news/297630.html(转载时请注明来源链接)

      有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

      本篇文章演示代码以及资料文档资料下载

      下载Word文档到电脑,方便收藏和打印~

      下载Word文档
      猜你喜欢
      • springboot有哪些实现拦截器的方式及异步执行是什么
        这篇文章主要讲解了“springboot有哪些实现拦截器的方式及异步执行是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot有哪些实现拦截器的方式及异步执行是什么”吧!目...
        99+
        2023-06-20
      • springboot实现拦截器的3种方式及异步执行的思考
        目录springboot 拦截器springboot 入门案例maven 引入启动类定义 Controller拦截器定义基于 Aspect基于 HandlerInterceptor基...
        99+
        2024-04-02
      • Java实现拦截器Interceptor的拦截功能方式是怎么样的
        本篇文章为大家展示了Java实现拦截器Interceptor的拦截功能方式是怎么样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java 里的拦截器是动态拦截 action 调用的对象,它提供了一...
        99+
        2023-06-25
      • java异步编程的实现方式有哪些
        这篇文章主要介绍“java异步编程的实现方式有哪些”,在日常操作中,相信很多人在java异步编程的实现方式有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java异步编程的实现方式有哪些”的疑惑有所帮助!...
        99+
        2023-07-05
      • 异步编程中索引重定向的实现方式有哪些?
        异步编程是现代编程语言中的热门话题,它可以提高应用程序的性能和响应能力。但是,异步编程也带来了一些问题,其中之一就是索引重定向。当我们在执行异步操作时,可能会需要对一个索引进行操作,但是由于异步操作的特性,索引可能会在操作完成前发生变化,...
        99+
        2023-11-13
        索引 重定向 异步编程
      • mybatis-plus拦截器敏感字段加解密的实现方法是什么
        本篇内容主要讲解“mybatis-plus拦截器敏感字段加解密的实现方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mybatis-plus拦截器敏感字段加解密的实现方法是什么”吧!背景...
        99+
        2023-06-25
      • 文件操作:PHP和NumPy的异步编程实现方式有哪些?
        在当今的计算机科学领域中,异步编程已经成为一个非常重要的话题。异步编程是一种编程方式,它允许程序在等待某些操作完成的同时,可以继续执行其他任务。这种编程方式可以提高程序的并发性和响应速度,特别是在文件操作等I/O密集型任务中。在本文中,我...
        99+
        2023-10-05
        numpy 异步编程 文件
      • 异步编程在Go语言中的实现方式是什么?
        随着互联网的不断发展,越来越多的应用程序需要处理大量的并发请求。在这种情况下,传统的同步编程方式已经无法满足需求。异步编程是一种解决并发问题的有效方式,它能够充分利用系统资源,提高程序的并发能力。本文将介绍异步编程在Go语言中的实现方式,...
        99+
        2023-09-28
        对象 自然语言处理 异步编程
      • vue-router传参的方式有哪些及怎么实现
        这篇文章主要介绍“vue-router传参的方式有哪些及怎么实现”,在日常操作中,相信很多人在vue-router传参的方式有哪些及怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”vue-router传...
        99+
        2023-07-04
      • Python编程框架中异步编程的实现方式是什么?
        在Python编程中,异步编程是一种非常重要的编程方式。它可以让我们编写高效的、可扩展的应用程序,同时又能保持代码的简洁性和可读性。本文将介绍Python中异步编程的实现方式。 Python中的异步编程模型 Python中的异步编程模...
        99+
        2023-06-18
        编程算法 框架 异步编程
      • mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么
        本篇内容主要讲解“mybatis/mybatis-plus模糊查询语句特殊字符转义拦截器的实现方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“mybatis/mybatis-plus模糊...
        99+
        2023-06-25
      • 云服务器cvm实例的计费模式有哪些类型及其特点是什么
        云服务器cvm实例的计费模式通常分为以下几种类型: 按容量计费:这种计费模式下,购买云服务器cvm实例的容量不仅取决于服务器的CPU、内存、硬盘等资源使用情况,还受到服务器所在的云服务器集群规模和可用性等因素的影响。 按服务类型计费:这...
        99+
        2023-10-26
        实例 类型 模式
      • 多线程和异步编程的调试方法有哪些?常见的错误和陷阱是什么?
        多线程和异步编程调试方法:使用现代调试器设置断点、检查变量和逐步执行代码;添加日志记录语句跟踪线程执行;使用可视化工具分析线程交互和识别瓶颈。 多线程和异步编程的调试方法 多线程和异步...
        99+
        2024-05-07
        多线程 异步编程 python 同步机制
      • PHP中的数组有哪些常用操作方式?与NumPy的相同点和差异是什么?
        PHP中的数组是一种非常常见的数据类型,可以存储多个值,并且可以通过索引访问和操作数组中的元素。在本文中,我们将介绍PHP中的数组常用操作方式,并将其与NumPy进行比较,以便更好地理解它们之间的相同点和差异。 一、PHP中的数组常用操作方...
        99+
        2023-08-26
        数组 numpy spring
      • 云服务器实际作用有哪些方面的应用场景是什么
        存储服务:云服务器提供了高可靠性和可扩展的存储服务,可以将数据备份到云端,用户可以随时随地访问这些数据,并且可以轻松地将其恢复到本地。 计算服务:云服务器可以为用户提供高性能的计算服务,支持弹性扩容、按需计费等灵活的计算模式,为用户提供更...
        99+
        2023-10-27
        场景 作用 服务器
      • 云服务器实际作用有哪些方面的特点和优势是什么
        一、云服务器的实际作用 高可用性:云服务器可以提供高可用性的服务,当云服务器出现故障时,可以自动切换到备用云服务器,保证业务不中断。 弹性扩展:云服务器可以根据用户需求自动调整资源的大小,以适应业务需求的变化。 快速部署:云服务器可以快...
        99+
        2023-10-28
        作用 优势 服务器
      软考高级职称资格查询
      编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
      • 官方手机版

      • 微信公众号

      • 商务合作