当前位置: 首页 > 知识库问答 >
问题:

在多线程上下文中使用OAuth2RestTemplate

童琪
2023-03-14

我在我的Spring boot应用程序中使用OAuth2RestTemplate,并通过它使用一些资源,因为它封装了所有身份验证信息,所以我可以只发送请求,而不用担心令牌和其他身份验证内容。

在我并行发送请求之前,一切都很好。

由于OAuth2RestTemplate有一个会话作用域(它是本地的,因为它包含用户的会话相关信息),当我试图在多线程环境中使用它时,我得到以下异常

组织。springframework。豆。工厂BeanCreationException:创建名为“scopedTarget”的bean时出错。oauth2ClientContext”:作用域“会话”对于当前线程不是活动的;如果您想从一个单体引用它,请考虑为这个bean定义一个作用域代理;嵌套的例外是java。lang.IllegalStateException:未找到线程绑定请求:您是指实际web请求之外的请求属性,还是在最初接收线程之外处理请求?如果您实际上是在web请求中操作,并且仍然收到此消息,那么您的代码可能是在DispatcherServlet/DispatcherPortlet之外运行的:在这种情况下,请使用RequestContextListener或RequestContextFilter公开当前请求。

据我所知,之所以会发生这种情况,是因为执行代码的这些独立线程没有连接到会话。

我现在找到的唯一解决方案是在代码中手动绑定新线程的会话,但我不喜欢它。

    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

    Stream.of(1, 2, 3).parallel().forEach(it -> {
        RequestContextHolder.setRequestAttributes(requestAttributes);
        //do something
        RequestContextHolder.resetRequestAttributes();
    });

    RequestContextHolder.setRequestAttributes(requestAttributes);

Spring Jira上也有类似的讨论,但我仍然希望有一些与OAuth2RestTemplate相关的解决方案。

所以我想知道是否有人遇到这个问题,你是如何解决的。

共有2个答案

柴英锐
2023-03-14

在我创建了自己的bean之后,我能够轻松地在多个线程中使用OAuth2RestTemplate,并确保它是正确自动连接的。

在我收到完全相同的错误消息之前,我没有得到我之前创建的OAuth2RestTemplate

@Bean
@Autowired
public OAuth2RestTemplate oAuth2RestTemplate(
    OAuth2ProtectedResourceDetails resourceDetails,
    SpringClientFactory clientFactory) {

    OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails);
    restTemplate.setRequestFactory(new RibbonClientHttpRequestFactory(clientFactory));

    return restTemplate;
}

特别是,请求工厂不存在于自动生成的RestTemboard中,实际上它是null。此外,我实际上有多个不同的OAuth2RestTemboardbean,但是@autowled为所有这些返回了完全相同的实例。

关键原来是在OAuth2RestoperationsConfiguration中:

@Bean
@Primary
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
        OAuth2ProtectedResourceDetails details) {
    OAuth2RestTemplate template = new OAuth2RestTemplate(details,
            oauth2ClientContext);
    return template;
}

由于使用了@主注释,所有的@autowed实例显然都会得到这个。在这种情况下,通过参数名指定要获取的bean,这通常是以前有效的方法。

添加@Qualifer注释解决了此问题:

@Autowired
@Qualifier("myOwnOAuth2RestTemplate")
OAuth2RestTemplate oAuth2RestTemplate;

现在,返回正确的实例,并在发出请求时,调用auth服务器以获取OAuth2令牌,如安全中的应用程序配置中所配置的。oauth2。客户端

但是,我没有尝试从新线程中自动连接restemplate。相反,我把它作为一个论点来传递。我不完全确定这是否会产生影响,但由于getAccessToken()是在请求执行期间由RestTemplate调用的,所以我认为它在自动连接到新线程时也应该工作。

宦博雅
2023-03-14

要使用会话或请求作用域,需要在@Configuration类中将RequestContextListener作为bean公开。例如,看看这个帖子。

 类似资料:
  • 我正在学习核心java,并学习了多线程。 我已经阅读了标准文档和这个问题,所以。。。但是在线程上下文中找不到合适的解决方案。 用书中的话说: 在两次启动线程时引发。 我不明白它说什么...甚至没有给出例子... 当它发生在线程上下文中时?有人能举个例子吗?

  • 问题内容: 我正在尝试使用线程下载多个与模式匹配的文件。该模式可以匹配1或5或10个差异大小的文件。 为了简单起见,可以说下载文件的实际代码在downloadFile()方法中,而fileNames是与模式匹配的文件名列表。我该如何使用线程。每个线程将仅下载一个文件。建议在for循环内创建一个新线程。 问题答案: 您确实想使用ExecutorService而不是单个线程,它更干净,性能可能更高,并

  • 我想创建一个可以从不同线程调用的RabbitMQ发布服务器。 基于RabbitMQ最佳实践,我不应该允许在不同线程中使用同一通道,因此在发布服务器的多个实例中共享此通道将会导致问题。 我能想到的唯一解决方案是拥有一个具有内部队列的管理器线程,该队列实现一个内部生产者-消费者,而单个消费者仅存在于该线程中。 有没有更简单的方法?由于显而易见的原因,希望尽可能避免同步,但此解决方案不允许这样做。

  • 问题内容: 我一直在使用mgo作为我的API,但我在MongoDB中看到了许多当前连接(同时使用少于5个设备进行测试)。通过在Mongo服务器上执行,我得到:。在下面,我将我的问题记录在mgo的Github中(问题#429): 我在Web服务器中使用mgo的方式是否正确?如果没有,您能举一个完整的例子吗? 此代码不起作用,将其视为几乎伪代码(由于缺少诸如导入的部分或配置来自何处和模型),但这正是我

  • 问题内容: I created a spring boot application with a parent context (services) and child context (spring-webmvc controllers): 现在,我想为ApiTwo.class配置添加另一个客户端上下文(和DispatcherServlet)。我认为我必须做两件事: 将servletContai

  • 我创建了一个带有父上下文(服务)和子上下文(spring-webmvc控制器)的Spring Boot应用程序: 现在,我想为我的配置添加另一个客户端上下文(和DispatcherServlet)。我想我得做两件事: 将(即mainapiapplication.class配置)移出子上下文,并且 添加路径映射和 春靴的方法是什么?