iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >SpringBoot ApplicationListener事件监听接口使用问题怎么解决
  • 418
分享到

SpringBoot ApplicationListener事件监听接口使用问题怎么解决

2023-07-05 20:07:10 418人浏览 独家记忆
摘要

这篇文章主要介绍“SpringBoot ApplicationListener事件监听接口使用问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“springBoot Ap

这篇文章主要介绍“SpringBoot ApplicationListener事件监听接口使用问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“springBoot ApplicationListener事件监听接口使用问题怎么解决”文章能帮助大家解决问题。

问题复现一下,大家看下面的代码,观察是否有问题,又该如何解决这个问题:

@RequestMapping("verify")@RestController@DependsOn({"DingAppInfoService","CloudChatAppInfoService"})public class LoginAction {    @Qualifier("ElderSonService")    @Autowired    private ElderSonService elderSonService;    @Qualifier("EmployeeService")    @Autowired    private EmployeeService employeeService;    @Qualifier("UserThreadPoolTaskExecutor")    @Autowired    private ThreadPoolTaskExecutor userThreadPoolTaskExecutor;    private static AuthRequest ding_request = null;    private static RonGCloud cloud_chat = null;    private static TokenResult reGISter = null;    private static final ThreadLocal<String> USER_TYPE = new ThreadLocal<>();        @PostConstruct    public void beforeVerifySetContext() {        AppContext.fillLoginContext();        Assert.hasText(AppContext.getAppLoginDingId(), "初始化app_login_ding_id错误");        Assert.hasText(AppContext.getAppLoginDingSecret(), "初始化app_login_ding_secret错误");        Assert.hasText(AppContext.getAppLoginReturnUrl(), "初始化app_login_return_url错误");        Assert.hasText(AppContext.getCloudChaTKEy(), "初始化cloud_chat_key错误");        Assert.hasText(AppContext.getCloudChatSecret(), "初始化cloud_chat_secret错误");        if (!(StringUtils.hasText(AppContext.getCloudNetUri()) || StringUtils.hasText(AppContext.getCloudNetUriReserve()))) {            throw new IllegalArgumentException("初始化cloud_net_uri与cloud_net_uri_reserve错误");        }        ding_request = new AuthDingTalkRequest(                AuthConfig.builder().                        clientId(AppContext.getAppLoginDingId()).                        clientSecret(AppContext.getAppLoginDingSecret()).                        redirectUri(AppContext.getAppLoginReturnUrl()).build());        cloud_chat = RongCloud.getInstance(AppContext.getCloudChatKey(), AppContext.getCloudChatSecret());    }.....以下api方法无所影响......}

其中可能令人不解的是controller组件里初始化方法的代码:

    public static void fillLoginContext() {        DingAppInfo appInfo = SpringContextHolder.getBean(DingAppInfoService.class).findAppInfo(APP_CODE);        setDingVerifyInfo(appInfo);        CloudChatAppInfo cloudChatAppInfo = SpringContextHolder.getBean(CloudChatAppInfoService.class).findAppInfo(APP_CODE);        setCloudChatInfo(cloudChatAppInfo);    }   public static void setDingVerifyInfo(DingAppInfo dingAppInfo){        if (dingAppInfo.checkKeyWordIsNotNull(dingAppInfo)) {            put(APP_LOGIN_DING_ID, dingAppInfo.getApp_id());            put(APP_LOGIN_DING_SECRET, dingAppInfo.getApp_secret());            put(APP_LOGIN_RETURN_URL, dingAppInfo.getApp_return_url());        }    }    public static void setCloudChatInfo(CloudChatAppInfo cloudChatAppInfo){        if (cloudChatAppInfo.checkKeyWordIsNotNull(cloudChatAppInfo)){            put(CLOUD_CHAT_KEY,cloudChatAppInfo.getCloud_key());            put(CLOUD_CHAT_SECRET,cloudChatAppInfo.getCloud_secret());            put(CLOUD_NET_URI,cloudChatAppInfo.getCloud_net_uri());            put(CLOUD_NET_URI_RESERVE,cloudChatAppInfo.getCloud_net_uri_reserve());        }    }

这里可以发现其实就是将一些项目定制的数据灌入我们的静态自定义上下文AppContext的本地线程ThreadLocal<Map<String,String>>对象中去,但是我们知道这个类型可是线程隔离的,不同的线程数据都不同,而我们的每一个请求都是一个线程,势必会导致数据的丢失,所以我们就算是在组件初始化时将数据给进去,下一个请求给进来也是会报出异常的。

解决思路(实际上不是这么解决的,但是也可以这么做,代价是性能耗费高):

设计一个监听者,一个发布者,在请求进入的方法上进行切面处理,切面检查AppContext对象数据,若为空则发布事件,不为空则进入方法:

事件原型:

public class AppContextStatusEvent extends ApplicationEvent {    public AppContextStatusEvent(Object source) {        super(source);    }    public AppContextStatusEvent(Object source, Clock clock) {        super(source, clock);    }}

监听者:

@Componentpublic class AppContextListener implements ApplicationListener<AppContextStatusEvent> {    @Override    public void onApplicationEvent(AppContextStatusEvent event) {        if ("FillAppContext".equals(event.getSource())) {            AppContext.fillLoginContext();        } else if ("CheckAppContextLogin".equals(event.getSource())) {            boolean checkContext = AppContext.checkLoginContext();            if (!checkContext) {                AppContext.fillLoginContext();            }        }    }}

发布者(切面类):

@Aspect@Component("AppContextaopAutoSetting")public class AppContextAopAutoSetting {    @Before("@annotation(com.lww.live.ApplicationListener.CheckAppContextLogin)")    public void CheckContextIsNull(JoinPoint joinPoint){        System.out.println("-----------aop---------CheckAppContextLogin---------start-----");        MethodSignature signature = (MethodSignature) joinPoint.getSignature();        boolean value = signature.getMethod().getAnnotation(CheckAppContextLogin.class).value();        if (value){            boolean checkContext = AppContext.checkLoginContext();            if (!checkContext){                SpringContextHolder.pushEvent(new AppContextStatusEvent("FillAppContext"));            }        }    }    @After("@annotation(com.lww.live.ApplicationListener.CheckAppContextLogin)")    public void CheckContextIsNull(){        System.out.println("-----------aop---------CheckAppContextLogin---------end-----");        SpringContextHolder.pushEvent(new AppContextStatusEvent("CheckAppContextLogin"));    }}

那么AOP切面类捕获的是注解:

@Inherited@Documented@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface CheckAppContextLogin {    boolean value() default false;    String info() default "";}

这里不难发现我们在切面的前置与后置增强方法里都是先检查AppContext数据的完整性,再进行填充数据。这样如果我们每一个请求方法都打上注解@CheckAppContextLogin也可以实现,但是问题是除填充的方法外其他的数据太难维护且切面劫持代理的代价太高,检查数据的频率太高。

正确的解决方案:

根据数据的业务功能划分,因为主要是实现两个对象的填充,哪怕这几个数据丢失了,但是同一个controller组件的成员变量都是同一个对象,且都在初始化的时候进行了初始化,故后续切换请求了也不影响它们实现业务的能力:

 private static AuthRequest ding_request = null; private static RongCloud cloud_chat = null;

我们可以在拦截器中要求前端给我们传递当前用户的用户类型与唯一标识,来进行每一次请求的用户定制数据的封装(减少请求内调用方法链查库操作):

public boolean preHandle(httpservletRequest request, HttpServletResponse response, Object handler) throws Exception {        String token = (String) request.getSession().getAttribute("token");        String user_type = (String) request.getSession().getAttribute("user_type");        if (StringUtils.hasText(token) && StringUtils.hasText(user_type)) {            Context context = new Context();            if (Objects.equals(user_type, "elder_son")) {                ElderSon elderSon = elderSonService.getElderSonByElderSonId(token);                context.setContextByElderSon(elderSon);                return true;            } else if (Objects.equals(user_type, "employee")) {                Employee employee = employeeService.getEmployeeById(token);                context.setContextByEmployee(employee);                return true;            }        } else if (StringUtils.hasText(user_type)) {            response.sendRedirect("/verify/login?user_type=" + user_type);            return false;        }        return false;    }

最后千万不要忘记remove一下ThreadLocal的引用:

 @Override    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {        AppContext.clear();        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);    }

所以实际场景实际解决,核心是业务,代码简洁只是附带的要求。

关于“SpringBoot ApplicationListener事件监听接口使用问题怎么解决”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: SpringBoot ApplicationListener事件监听接口使用问题怎么解决

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

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

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

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

下载Word文档
猜你喜欢
  • SpringBoot ApplicationListener事件监听接口使用问题怎么解决
    这篇文章主要介绍“SpringBoot ApplicationListener事件监听接口使用问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SpringBoot Ap...
    99+
    2023-07-05
  • SpringBootApplicationListener事件监听接口使用问题探究
    终日惶惶,不知归路;一日写起代码,突发奇想,若是在运行时发现自定义上下文的数据丢失,我们该如何解决处理数据丢失的问题? 问题复现一下,大家看下面的代码,观察是否有问题,又该如何解决这...
    99+
    2023-05-14
    SpringBoot ApplicationListener SpringBoot事件监听接口
  • springboot事件监听器怎么使用
    本篇内容介绍了“springboot事件监听器怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!引导案例下面看一个简单的案例,@Conf...
    99+
    2023-07-02
  • 使用Spring怎么监听事件
    使用Spring怎么监听事件?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、观察者模式先来看下观察者模式,举个例子警察和军人是观察者,犯罪嫌疑人是被观察者代码实现:定义被观察...
    99+
    2023-06-15
  • vue中监听scroll事件失效的问题及解决
    目录vue监听scroll事件失效问题下面附实现成功的代码vue监听scroll事件vue监听scroll事件失效问题 vue项目中遇到需要监听页面某个元素距顶部距离实现吸顶效果,正...
    99+
    2024-04-02
  • Vue的addEventListener()监听事件怎么使用
    本篇内容介绍了“Vue的addEventListener()监听事件怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、语法eleme...
    99+
    2023-07-04
  • uniapp监听不到上拉事件怎么解决
    在uniapp中,我们可以通过监听页面滚动事件来实现上拉加载更多的功能。但有时候会发现即使页面已经滑动到底部,也无法监听到上拉事件,这该如何解决呢?首先要明确的是,uniapp是基于Vue框架开发的,因此我们可以借鉴Vue的思路来解决这个问...
    99+
    2023-05-14
  • springboot应用服务启动事件的监听怎么实现
    本篇内容主要讲解“springboot应用服务启动事件的监听怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“springboot应用服务启动事件的监听怎么实现”吧!一、简介Spring B...
    99+
    2023-06-29
  • vue中对监听esc事件和退出全屏问题的解决方案
    目录对监听esc事件和退出全屏问题的解决下面是全屏的完整代码element+vue全屏与退出全屏(监听ESC改样式)一、效果二、代码对监听esc事件和退出全屏问题的解决 vue 的项...
    99+
    2022-11-13
    vue监听 监听esc事件 vue退出全屏
  • 怎么使用springboot暴露oracle数据接口的问题
    这篇文章给大家分享的是有关怎么使用springboot暴露oracle数据接口的问题的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。springboot是什么springboot一种全新的编程规范,其设计目的是用来...
    99+
    2023-06-14
  • 使用layui监听器监听select下拉框,事件绑定不成功怎么办
    这篇文章主要为大家展示了“使用layui监听器监听select下拉框,事件绑定不成功怎么办”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“使用layui监听器监听...
    99+
    2024-04-02
  • vue中provide inject的响应式监听问题怎么解决
    这篇文章主要介绍“vue中provide inject的响应式监听问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue中provide inject的响应式监听问题怎...
    99+
    2023-06-30
  • thinkphp的事件绑定、监听和订阅怎么使用
    这篇文章主要介绍了thinkphp的事件绑定、监听和订阅怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇thinkphp的事件绑定、监听和订阅怎么使用文章都会有所收获,下面我们一起来看看吧。事件是什么事件...
    99+
    2023-06-30
  • Java怎么解决接口并发问题
    在Java中,可以通过以下几种方法来解决接口并发问题:1. 同步方法:可以在接口的实现类中使用synchronized关键字来修饰方...
    99+
    2023-09-12
    Java
  • SpringBoot接口调用之后报404问题的解决方案
    我的接口是这样的: TestCase测试Impl类的方法没有问题,但是Swgger和前端调用接口就会报404错误: 在网上查了很多资料,都说是地址的问题,我参照了上下文 serv...
    99+
    2024-04-02
  • SpringBoot异步与事务一起使用的问题解决
    最近遇到的一个场景,在一个被 @Transactional 注解的方法A中中调用了一个被 @Async 注解标记的方法B,由于方法B 在执行时方法A 的事务没有提交,但是方法B在执行...
    99+
    2023-05-18
    SpringBoot异步与事务一起使用 SpringBoot 异步 事务
  • golang接口性能低问题怎么解决
    要解决Golang接口性能低的问题,可以尝试以下几种方法: 使用具体类型而非接口类型:接口类型在运行时需要进行类型断言,会增加一...
    99+
    2023-10-23
    golang
  • windows问题事件名称BlueScreen怎么解决
    本文小编为大家详细介绍“windows问题事件名称BlueScreen怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“windows问题事件名称BlueScreen怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来...
    99+
    2023-07-01
  • springboot项目事务标签验证问题怎么解决
    这篇文章主要讲解了“springboot项目事务标签验证问题怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“springboot项目事务标签验证问题怎么解决”吧!1、问题描述sprin...
    99+
    2023-06-08
  • Springboot Retry组件@Recover失效问题怎么解决
    这篇文章主要介绍“Springboot Retry组件@Recover失效问题怎么解决”,在日常操作中,相信很多人在Springboot Retry组件@Recover失效问题怎么解决问题上存在疑惑,小编查阅了各式资料,...
    99+
    2023-06-21
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作