1

我需要动态创建和销毁HttpClient对象,以与客户在我的 Micronaut 应用程序中注册/注销自己相对应。作为其中的一部分,我想将它们作为 bean 添加到应用程序上下文中,以便它们HttpFilter在项目中也自动使用自定义 s。

ApplicationContext我认为使用带有名称的 bean 方法来管理这些 beanQualifier以跟踪它们会相当简单,但是这些 API 的行为方式似乎让我感到莫名其妙:

  1. applicationContext.createBean(HttpClient.class, Qualifiers.byName("myLabel"), myUrl)失败:
io.micronaut.context.exceptions.NoSuchBeanException: No bean of type 
[io.micronaut.http.client.HttpClient] exists. Make sure the bean is not disabled by bean 
requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the 
bean is enabled then ensure the class is declared a bean and annotation processing is 
enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as 
an annotation processor).

为什么 bean 是否存在很重要?我正在努力创造它!

  1. applicationContext.findBean(HttpClient.class)失败:
io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [io.micronaut.http.client.DefaultHttpClient]

Message: Missing bean argument [LoadBalancer loadBalancer] for type: io.micronaut.http.client.DefaultHttpClient. Required arguments: LoadBalancer loadBalancer,HttpClientConfiguration configuration,String contextPath,HttpClientFilterResolver filterResolver

为什么要尝试创建它?我只是想找到它!

注意applicationContext.getBean(HttpClient.class, Qualifiers.byName("myLabel"))可能在这里工作,但因为我无法解决第一点,我无法验证这一点)

  1. applicationContext.destroyBean(HttpClient.class)不允许Qualifier在方法中指定 a ,这意味着我不能使用它从上下文中删除 bean。它还在没有限定符 ( applicationContext.createBean(HttpClient.class, myUrl)) 的 bean 创建后返回 null ,这表明它无论如何都找不到创建的 bean ......

我假设我在这里使用了错误的 API,但正确的 API 是什么?

总而言之,我非常困惑 - 欢迎任何有关正确使用这些 API 的帮助。

4

1 回答 1

0

HttpClient是旨在定义 http-client 但不是 bean 的接口(请注意,MicronautDefaultHttpClient提供的默认 ~~ 实现不是 bean)。因此,对上述上下文查找或实例化方法的任何调用都将导致错误:ApplicationContext

  • ApplicationContext#createBean
  • ApplicationContext#findBean
  • ApplicationContext#getBean
  • ... // 其他实例化方法

请注意,这是有意设计的,因为HttpClientAPI 旨在自动注入并通过 AOP 建议进行操作。

您可以注入原始(使用默认方法)HttpClient

@Singleton
public class MyBeanIml implements MyBean {

  @Client
  HttpClient client;

  // ...
}

或者对于自定义方法,生成实现,您可以使用HttpClient声明性实现:

@Client("endpoint-uri")
public interface MyHttpClient {

  @Get
  String query();

  // ...
}

在不指定创建自定义的确切要求(顺便说一下,动态在这种情况下太模糊HttpClient)的情况下,您可以采用的方式是让自定义@Prototyped bean 包装一个可以用您的自定义参数实例化的注入 HttpClient以及您委托的位置您的方法来包装HttpClient或实现您的自定义方法:

@Prototype
public class CustomHttpClientImpl implements CustomHttpClientImpl.CustomHttpClient {

    @Inject
    @Client
    private final HttpClient httpClient;

    private final String endpoint;

    public CustomHttpClientImpl(@Parameter String endpoint, HttpClient httpClient) {
        this.httpClient = httpClient;
        this.endpoint = endpoint;
    }

        @Override
    public String query() {
        return this.httpClient.toBlocking()
                .exchange(HttpRequest.GET(URI.create(this.endpoint)), String.class)
                .body();
    }
    
    // delegate to the `httpClient` bean or implement your custom API querying methods

    public interface CustomHttpClient {

        String query();
    }
}

然后您可以Prototype使用以下命令创建您的 d bean 实例ApplicationContext

applicationContext.createBean(CustomHttpClient.class, "som-uri-for-custom-client");
于 2021-03-20T14:22:53.250 回答