java 将请求范围的 bean 注入另一个 bean

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34090750/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:28:48  来源:igfitidea点击:

Inject request scoped bean into another bean

javaspring-mvcspring-bootautowired

提问by YLombardi

I want to create a UUID that is unique in a request life cycle. To do this, I create a UUID bean with the @Scope("request") annotation.

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

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

I want to access this bean in my controller. So I inject it with @Autowired. This works fine.

我想在我的控制器中访问这个 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";
    }
}

The controller call multiple services. Every service use a RestTemplate bean. In this RestTemplate bean, I want to get the UUID.

控制器调用多个服务。每个服务都使用 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);
    }
}

When I try to inject the UUID here, I have an error :

当我尝试在此处注入 UUID 时,出现错误:

Error creating bean with name 'zenithRestTemplate': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.util.UUID com.geodis.rt.zenith.framework.webui.service.ZenithRestTemplate.uuid; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestUUID': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

创建名为“zenithRestTemplate”的 bean 时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:私有 java.util.UUID com.geodis.rt.zenith.framework.webui.service.ZenithRestTemplate.uuid; 嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为 'requestUUID' 的 bean 时出错:当前线程的作用域 'request' 未激活;如果您打算从单例中引用它,请考虑为此 bean 定义范围代理;嵌套异常是 java.lang.IllegalStateException: No thread-bound request found: 您是否指的是实际 Web 请求之外的请求属性,或处理原始接收线程之外的请求?如果您实际上是在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet/DispatcherPortlet 之外运行:在这种情况下,使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。

What can I do to access my UUID bean inside the RestTemplate bean ?

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

My project use Spring-MVC, Spring-boot with java configuration.

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

I already tried to add a RequestContextListener but it doesn't solve the problem.

我已经尝试添加 RequestContextListener 但它没有解决问题。

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

回答by Jan Zyka

I think you need to mark your UUIDrequest scoped bean like:

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

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

Where controller is singletonscoped bean you are injecting requestscoped bean in it. As singleton beans are injected only once per their lifetime you need to provide scoped beans as proxies which takes care of that.

如果控制器是singleton作用域 bean,您将request在其中注入作用域 bean。由于单例 bean 在它们的生命周期中只注入一次,因此您需要提供作用域 bean 作为代理来处理这个问题。

Another option is to instead use the org.springframework.web.context.annotation.RequestScopeannotation:

另一种选择是改用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;

}

@RequestScopeis a meta-annotation on @Scopethat 1) sets the scopeto "request"and 2) sets the proxyModeto ScopedProxyMode.TARGET_CLASSso you don't have to do it every time you want to define a request-scoped bean.

@RequestScope是关于@Scope1) 设置scopeto"request"和 2) 设置proxyModeto的元注释,ScopedProxyMode.TARGET_CLASS因此您不必每次要定义请求范围的 bean 时都这样做。

Edit:

编辑:

Note that you may need to add @EnableAspectJAutoProxyon your main configuration class.

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