Spring Apache的AOP监控HttpClient.execute

Spring AOP monitoring of Apache HttpClient.execute

我想监控传出请求的时间以跟踪我的应用程序中的 HTTP 集成。所有这些的公共代码路径是 HttpClient.execute 所以这似乎是 AOP 的自然目标:

@Around("execution(* org.apache.http.client.HttpClient.execute(..)) && args(httpUriRequest)")
public Object timeApacheRequest(ProceedingJoinPoint proceedingJoinPoint, HttpUriRequest httpUriRequest) throws Throwable {
    // etc.
}

但是,当我使用我的代理时,交互 Spring HttpComponentsClientHttpRequestFactory 代码爆炸了 instanceof 检查传入的代理。

Caused by: java.lang.IllegalArgumentException: 'httpClient' is not of type CloseableHttpClient Object of class [com.sun.proxy.$Proxy22] must be an instance of class org.apache.http.impl.client.CloseableHttpClient

HttpComponentsClientHttpRequestFactory中的操作检查:

public HttpComponentsClientHttpRequestFactory(HttpClient httpClient) {
    Assert.notNull(httpClient, "'httpClient' must not be null");
    Assert.isInstanceOf(CloseableHttpClient.class, httpClient, "'httpClient' is not of type CloseableHttpClient");
    this.httpClient = (CloseableHttpClient) httpClient;
}

我有没有更好的方法来构建我的代理来避免这个问题?

澄清一下,目前我在声明 bean 的配置 class 上使用 @EnableAspectJAutoProxy 注释建立当前代理。

默认情况下,@EnableAspectJAutoProxy(以及大多数生成代理的配置,@EnableTransactionManagementEnableAsync 等)使用 JDK proxies.

JDK代理只支持超级接口。 newProxyInstance 返回的实例(创建 JDK 代理的入口点)将具有超类型 Proxy

为了支持您的方面和建议,Spring 必须代理任何与您的连接点匹配的实例。由于默认配置,这些代理只维护真实对象的超级接口。 CloseableHttpClient 是一个摘要 class。那是迷路了。代理没有该类型,因此 instanceof 将失败。

相反,您可以将 @EnableAspectJAutoProxy#proxyTargetClass() 配置为 true,以便 Spring 使用 CGLIB 来代理您的对象。 CGLIB 比 JDK 代理更强大。 CGLIB 可以子class 目标对象的class(除非它的class 是final 或者有一个private 构造函数)。

代理将是 CloseableHttpClient 的子类型并且 instanceof 可以工作。