从Java 8函数创建请求范围的Bean [英] Create request scoped beans from a Java 8 Function

查看:86
本文介绍了从Java 8函数创建请求范围的Bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基于此答案,我尝试使用 java.util配置请求范围Bean。功能界面。

Based on this answer I try to configure a request scope bean using java.util.Function interface.

我的配置如下:

@Configuration
public class RequestConfig {

    @Bean
    public Function<? extends BaseRequest, RequestWrapper<? extends BaseRequest, ? extends BaseResponse>> requestWrapperFactory() {
        return request -> requestWrapper(request);
    }

    @Bean
    @RequestScope
    public RequestWrapper<? extends BaseRequest, ? extends BaseResponse> requestWrapper(
            BaseRequest request) {
        RequestWrapper<?, ?> requestWrapper = new RequestWrapper<BaseRequest, BaseResponse>(request);
        return requestWrapper;
    }
}

我尝试使用如下所示的bean:

And I try to use the bean like this:

@RestController
public class CheckRequestController {

    private final RequestService<CheckRequest, CheckResponse> checkRequestServiceImpl;

    @Autowired
    private Function<CheckRequest, RequestWrapper<CheckRequest, CheckResponse>> requestWrapperFactory;

    public CheckRequestController(
            RequestService<CheckRequest, CheckResponse> checkRequestServiceImpl) {
        super();
        this.checkRequestServiceImpl = checkRequestServiceImpl;
    }

    @PostMapping(value = "/check", consumes = { MediaType.TEXT_XML_VALUE,
            MediaType.MULTIPART_FORM_DATA_VALUE }, produces = MediaType.TEXT_XML_VALUE)
    public ResponseEntity<CheckResponse> checkRequest(
            @RequestBody(required = true) CheckRequest checkRequest) {

        RequestWrapper<CheckRequest, CheckResponse> requestWrapper = requestWrapperFactory
                .apply(checkRequest);
        checkRequestServiceImpl.getResponse(requestWrapper);

        return new ResponseEntity<CheckResponse>(requestWrapper.getResponse(),
                HttpStatus.OK);
    }
}

在这里:

@RestController
public class CancelRequestController {

private final RequestService<CancelRequest, CancelResponse> cancelRequestServiceImpl;

@Autowired
private Function<CancelRequest, RequestWrapper<CancelRequest, CancelResponse>> requestWrapperFactory;

public CancelRequestController(
        RequestService<CancelRequest, CancelResponse> cancelRequestServiceImpl) {
    super();
    this.cancelRequestServiceImpl = cancelRequestServiceImpl;
}

@PostMapping(value = "/cancel", consumes = { MediaType.TEXT_XML_VALUE,
        MediaType.MULTIPART_FORM_DATA_VALUE }, produces = MediaType.TEXT_XML_VALUE)
public ResponseEntity<CancelResponse> CancelRequest(
        @RequestBody(required = true) CancelRequest cancelRequest) {
    RequestWrapper<CancelRequest, CancelResponse> requestWrapper = requestWrapperFactory
            .apply(cancelRequest);
    cancelRequestServiceImpl.getResponse(requestWrapper);
    return new ResponseEntity<CancelResponse>(requestWrapper.getResponse(),
            HttpStatus.OK);
}
}

但是我得到一个例外,就是没有bean类型 Function 定义。

But I get the exception that there is no bean of type Function defined.

  Field requestWrapperFactory in CheckRequestController required a bean of type 'java.util.Function' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'java.util.Function' in your configuration.

使用泛型类型是否有问题?我怎么了?

Is there a problem by using generic types? What do I wrong?

推荐答案

您引用的答案有所不同:它在声明的bean中使用完全相同的泛型类型

The answer that you refer has a difference : it uses exactly the same generics type in the declared bean and the injected bean :

@Bean
public Function<String, Thing> thingFactory() {
    return name -> thing(name); // or this::thing
} 

and:

@Autowired
private Function<String, Thing> thingFactory;




使用泛型类型是否有问题?我怎么了?

Is there a problem by using generic types? What do I wrong?

是的。您要注入具有此签名的bean:

Yes. You want to inject a bean with this signature :

Function<CheckRequest, RequestWrapper<CheckRequest, CheckResponse>> requestWrapperFactory;

但是您声明了具有此签名的bean:

But you declared a bean with this signature :

Function<? extends BaseRequest, RequestWrapper<? extends BaseRequest, ? extends BaseResponse>>

此处:

@Bean
public Function<? extends BaseRequest, RequestWrapper<? extends BaseRequest, ? extends BaseResponse>> requestWrapperFactory() {
    return request -> requestWrapper(request);
}

bean声明和连接的bean中使用的泛型必须相同在依赖项注入方面进行匹配。

The generics used in the bean declaration and the bean wired have to be the same to match in terms of dependency injections.

因此只需在双方声明相同的类型。

So just declare the same types in both sides.


所以这意味着没有办法使用泛型来配置bean吗?
,因为我也想将bean创建也用于CancelRequest
(更新后的答案)。因此,我必须为所有类型的
BaseRequest创建一个Bean。

so this means there is no way to configure a bean using generics? because I wanted to use the bean creation also for CancelRequest (updated answer). So I have to create a Bean for all types of BaseRequest..

对于 @RequestScope bean,理论上它不应使用泛型创建任何问题,因为该bean是在每次请求时创建的,并且不能重用,但是我认为 @Bean 并没有什么区别,因此请考虑一般情况(单作用域),在这种情况下,必须进行完美匹配才能避免类型安全和一致性问题。 它可能会让您感兴趣

For @RequestScope beans, in theory it should not create any issue to use generics because the bean is created at each request and not reused but I think that the generic features for @Bean doesn't make this difference and so consider the general case (singleton scope) where the perfect matching is necessary to avoid type safe and consistency issues. It could interest you.

编辑后:

我更新了第一部分以与您的更改保持一致。

I updated the first part to be consistent with your changes.

现在,您的要求是声明一个函数,该函数可将具有客户指定的泛型类型的原型bean返回给客户。

这是可能的。但是要使它整洁,您不应该使用两个bean:一个用于工厂(单例),另一个用于创建 RequestWrapper 对象(原型)。

由于工厂bean不允许客户端指定通用类型,因此您将不得不执行不希望的取消广播。

您还应该替换 @RequestScope by @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE),因为请求范围内的bean不允许像配置类中的单例和原型bean一样多地进行配置。 >
例如,使用参数或通配符不能很好地工作。

Now your requirement is declaring a function that returns to the client a prototype bean with a generic type specified by the client.
That is possible. But to make it neat, you should not use two beans : one for the factory (the singleton) and another to create the RequestWrapper object ( the prototype).
As the factory bean doesn't allow clients to specify the generic type, you will have to perform undesirable uncasts.
You should also replace @RequestScope by @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) because request scoped beans don't allow to be as much configurable as singleton and prototype beans in a configuration class.
For example, using parameters or wildcard don't work well.

因此,我们的想法是声明一个原型bean,其返回的泛型类型取决于参数和目标。

About RequestConfig ,现在最好将其命名为 RequestFactory ,因为这是它的作用。

So the idea is declaring a prototype bean which the generic type returned depends on the parameter and the target.
AboutRequestConfig, it would have better now to be named as RequestFactory as that is its role.

@Configuration
public class RequestFactory {

    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public <T extends BaseRequest, U extends BaseResponse> RequestWrapper<T, U> requestWrapper(
            T request) {
        RequestWrapper<T, U> requestWrapper = new RequestWrapper<>(request);
        return requestWrapper;
    }

}

在控制器中注入 @Configuration bean requestFactory

In the controller inject the @Configuration bean requestFactory :

private RequestFactory requestFactory; // Change

public CheckRequestController(
        RequestService<CheckRequest, CheckResponse> checkRequestServiceImpl,
        RequestConfig requestConfig) {
    this.checkRequestServiceImpl = checkRequestServiceImpl;
    this.requestFactory = requestFactory; // Change
}

现在您可以使用所需的<$注入原型bean c $ c> RequestWrapper 何时需要:

And now you can inject a prototype bean with the desired RequestWrapper whenever you need :

@PostMapping(value = "/cancel", consumes = { MediaType.TEXT_XML_VALUE,
        MediaType.MULTIPART_FORM_DATA_VALUE }, produces = MediaType.TEXT_XML_VALUE)
public ResponseEntity<CancelResponse> CancelRequest(
        @RequestBody(required = true) CancelRequest cancelRequest) {
    RequestWrapper<CheckRequest, CheckResponse> requestWrapper = 
               requestFactory.requestWrapper(cancelRequest);
     //...
    return new ResponseEntity<CancelResponse>(requestWrapper.getResponse(),
            HttpStatus.OK);
}

现在测试,它看起来可以工作。

Tested that now, it looks working.

这篇关于从Java 8函数创建请求范围的Bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆