web-dev-qa-db-ja.com

リクエストスコープのBeanを別のBeanに注入します

リクエストのライフサイクルで一意のUUIDを作成したいと思います。これを行うには、@ Scope( "request")アノテーションを使用してUUIDBeanを作成します。

@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";
    }
}

コントローラは複数のサービスを呼び出します。すべてのサービスはRestTemplateBeanを使用します。このRestTemplateBeanでは、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の作成中にエラーが発生しました:自動配線された依存関係の挿入に失敗しました。ネストされた例外はorg.springframework.beans.factory.BeanCreationExceptionです:フィールドを自動配線できませんでした:private Java.util.UUID com.geodis.rt.zenith.framework.webui.service.ZenithRestTemplate.uuid;ネストされた例外はorg.springframework.beans.factory.BeanCreationExceptionです:「requestUUID」という名前のBeanの作成中にエラーが発生しました:スコープ「request」は現在のスレッドに対してアクティブではありません。シングルトンから参照する場合は、このBeanのスコープ付きプロキシを定義することを検討してください。ネストされた例外はJava.lang.IllegalStateExceptionです:スレッドにバインドされたリクエストが見つかりません:実際のWebリクエストの外部でリクエスト属性を参照していますか、それとも最初に受信したスレッドの外部でリクエストを処理していますか?実際にWebリクエスト内で操作しているのにこのメッセージが表示される場合は、コードがDispatcherServlet/DispatcherPortletの外部で実行されている可能性があります。この場合、RequestContextListenerまたはRequestContextFilterを使用して現在のリクエストを公開します。

RestTemplate Bean内のUUIDBeanにアクセスするにはどうすればよいですか?

私のプロジェクトでは、Spring-MVC、Spring-bootをJava構成で使用しています。

すでにRequestContextListenerを追加しようとしましたが、問題は解決しません。

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

UUIDリクエストスコープのBeanを次のようにマークする必要があると思います。

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

コントローラがsingletonスコープのBeanである場合、その中にrequestスコープのBeanを注入します。シングルトンBeanは、その存続期間ごとに1回だけ注入されるため、スコープ付きBeanをプロキシとして提供する必要があります。

別のオプションは、代わりに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@Scopeのメタ注釈であり、1)scope"request"に設定し、2)proxyModeScopedProxyMode.TARGET_CLASSに設定します。したがって、リクエストスコープのBeanを定義するたびにそれを行う必要はありません。

編集:

メインの構成クラスに@EnableAspectJAutoProxyを追加する必要がある場合があることに注意してください。

18
Jan Zyka