将请求范围的 Bean 注入到另一个 Bean 中

2022-09-03 00:06:39

我想创建一个在请求生命周期中唯一的 UUID。为此,我创建了一个带有@Scope(“request”)注释的UUID bean。

@Bean
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST)
public UUID requestUUID() {
    return UUID.randomUUID();
}

我想在我的控制器中访问此 Bean。所以我给它注射了@Autowired。这工作正常。

@Controller
public class DashboardController {

    @Autowired
    UUID uuid;

    @Autowired
    WelcomeMessageService welcomeMessageService;

    @Autowired
    IssueNotificationService issueNotificationService;

    @RequestMapping("/")
    public String index(Model model) throws InterruptedException, ExecutionException {
        System.out.println(uuid);
        PortalUserDetails userLog = getPortalUserDetails();

        BusinessObjectCollection<WelcomeMessage> welcomeMessages = welcomeMessageService.findWelcomeMessages(
                20,
                0,
                userLog.getZenithUser(),
                userLog.getConnectionGroup().getConnectionGroupCode(),
                "FR");
        if(welcomeMessages!=null) {
            model.addAttribute("welcomeMessages", welcomeMessages.getItems());
        }

        BusinessObjectCollection<IssueNotification> issueNotifications =
                issueNotificationService.findIssueNotifications(userLog.getZenithUser());

        if(welcomeMessages!=null) {
            model.addAttribute("welcomeMessages", welcomeMessages.getItems());
        }
        model.addAttribute("issueNotifications", issueNotifications);

        return "index";
    }
}

控制器调用多个服务。每个服务都使用 RestTemplate bean。在这个 RestTemplate bean 中,我想获取 UUID。

@Component
public class ZenithRestTemplate extends RestTemplate {   
    @Autowired
    private UUID uuid;

    public void buildRestTemplate() {
        List restTemplateInterceptors = new ArrayList();
        restTemplateInterceptors.add(new HeaderHttpRequestInterceptor("UUID", uuid.toString()));
        this.setInterceptors(restTemplateInterceptors);
    }
}

当我尝试在此处注入UUID时,我遇到了一个错误:

创建名为“zenithRestTemplate”的bean时出错:注入自动连接的依赖项失败;nested exception is org.springframework.beans.factory.BeanCreationException: Can not autowire field: private java.util.UUID com.geodis.rt.zenith.framework.webui.service.ZenithRestTemplate.uuid;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为 'requestUUID' 的 bean 时出错:范围 'request' 对于当前线程不处于活动状态;如果您打算从单例引用此 Bean,请考虑为此 Bean 定义作用域代理;嵌套的异常是 java.lang.IllegalStateException:未找到线程绑定请求:您指的是实际 Web 请求之外的请求属性,还是在原始接收线程之外处理请求?如果您实际上在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下,请使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。

我该怎么做才能在 RestTemplate bean 中访问我的 UUID Bean?

我的项目使用Spring-MVC,Spring-boot和java配置。

我已经尝试添加一个 RequestContextListener,但它不能解决问题。

@Bean public RequestContextListener requestContextListener(){
    return new RequestContextListener();
}

答案 1

我认为您需要像这样标记您的请求范围bean:UUID

@Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)

如果控制器是作用域 Bean,则在其中注入作用域 Bean。由于单例bean在其生命周期中仅注入一次,因此您需要提供作用域bean作为代理来处理这个问题。singletonrequest

另一种选择是改用注释:org.springframework.web.context.annotation.RequestScope

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Scope(WebApplicationContext.SCOPE_REQUEST)
public @interface RequestScope {

    @AliasFor(annotation = Scope.class)
    ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

@RequestScope是一个元注释,1) 将 to 和 2) 设置为 to,这样你就不必每次都定义一个请求范围的 Bean 时都这样做。@Scopescope"request"proxyModeScopedProxyMode.TARGET_CLASS

编辑:

请注意,您可能需要添加主配置类。@EnableAspectJAutoProxy


答案 2

推荐