Java 的动态代理简单实现对某个接口的 mock

开发 前端
使用 Java 的动态代理来实现对某个接口的 mock,并将传递给该接口的参数、类名和方法名等信息传递给指定的第三方接口,模拟第三方接口返回的结果和指定响应的时间。

使用 Java 的动态代理来实现对某个接口的 mock,并将传递给该接口的参数、类名和方法名等信息传递给指定的第三方接口,模拟第三方接口返回的结果和指定响应的时间。

可以通过在动态代理类 ApiMock 中实现 InvocationHandler 接口的 invoke 方法,在该方法中模拟第三方接口返回的结果,并指定返回结果的时间。具体实现方法如下:

package com.myfunnel.mock;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class ApiMock implements InvocationHandler {

private Object target;
private String thirdPartyUrl;

public ApiMock(Object target, String thirdPartyUrl) {
this.target = target;
this.thirdPartyUrl = thirdPartyUrl;
}

public static Object mock(Object target, String thirdPartyUrl, Class<?>... interfaces) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
interfaces,
new ApiMock(target, thirdPartyUrl));
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String className = target.getClass().getName();
String methodName = method.getName();
String parameterTypes = Arrays.toString(method.getParameterTypes());
String arguments = Arrays.toString(args);

// 构造需要传递给第三方系统的请求参数
Map<String, Object> thirdPartyParams = new HashMap<>();
thirdPartyParams.put("className", className);
thirdPartyParams.put("methodName", methodName);
thirdPartyParams.put("parameterTypes", parameterTypes);
thirdPartyParams.put("arguments", arguments);

// 同步调用第三方系统接口
long start = System.nanoTime();
String response = ThirdPartyApi.call(thirdPartyUrl, thirdPartyParams);
long elapsed = System.nanoTime() - start;

// 模拟第三方系统返回的结果和响应时间
int delay = getDelay(className, methodName, parameterTypes, arguments);
TimeUnit.MILLISECONDS.sleep(delay);

// 打印模拟结果和响应时间
System.out.printf("%s.%s(%s) => %s (in %d ms)%n",
className, methodName, arguments, response, elapsed / 1000000);

// 返回模拟结果
return getResponse(className, methodName, parameterTypes, arguments);
}

/**
* 返回模拟结果
*/
private Object getResponse(String className, String methodName, String parameterTypes, String arguments) {
if (className.equals("com.example.SomeApi") && methodName.equals("someMethod")) {
// 返回模拟数据
return "mock result";
}
// 其他方法返回 null
return null;
}

/**
* 返回模拟响应时间
*/
private int getDelay(String className, String methodName, String parameterTypes, String arguments) {
if (className.equals("com.example.SomeApi") && methodName.equals("someMethod")) {
// 模拟 500~1000 毫秒的延迟
return (int) (500 + Math.random() * 500);
}
// 其他方法不延迟
return 0;
}

}

在这段代码中,我们实现了一个带有模拟功能的动态代理类 ApiMock,并在 invoke 方法中对传递给被代理接口的参数、类名和方法名等信息进行记录,并将这些信息作为请求参数传递给第三方接口 ThirdPartyApi.call。同时,在模拟响应结果和响应时间时,我们实现了两个私有方法 getResponse 和 getDelay,可以根据接口名、方法名、参数类型和参数值等条件来指定模拟的结果和延迟的时间,以模拟不同情况下的返回结果和响应时间。

在实际使用时,需要将被代理接口的实现类作为 target 参数传入 ApiMock 构造函数中,同时将需要模拟的第三方接口的 URL 作为 thirdPartyUrl 参数传入。

ThirdPartyApi 是一个自定义的类,其中 call 方法用于调用第三方接口。你需要自己实现这个类,并根据实际的需求调用指定的第三方接口。

下面是一个简单的示例代码:

package com.myfunnel.mock;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

public class ThirdPartyApi {
public static String call(String url, Map<String, Object> params) {
// 将 params 拼接成 GET 请求参数格式,并拼接到 url 上
String queryString = encodeParams(params);
String requestUrl = url + "?" + queryString;
StringBuffer result = new StringBuffer();
try {
// 发送 GET 请求
HttpURLConnection conn = (HttpURLConnection) new URL(requestUrl).openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);

// 读取响应结果
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;

while ((line = in.readLine()) != null) {
System.out.println(line);
result.append(line);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}

/**
* 将请求参数拼接成 GET 参数格式
*/
private static String encodeParams(Map<String, Object> params) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, Object> entry : params.entrySet()) {
if (sb.length() > 0) {
sb.append("&");
}
sb.append(entry.getKey()).append("=").append(entry.getValue());
}
return sb.toString();
}
}

这个 ThirdPartyApi 类定义了一个 call 方法,接受一个 url 和一个参数映射,将参数映射转换成 GET 请求的参数格式,并将其拼接到 url 上,然后发送 GET 请求,并读取响应结果打印到控制台中。在实际使用时,需要将 call 方法中的代码替换成实际的调用目标第三方接口的代码。

测试代码:

下面是一个示例代码,展示了如何使用 ApiMock 对 SomeApi 接口进行 mock,并将传递给该接口的参数、类名和方法名等信息传递给指定的第三方接口 http://example.com/api:

// 创建被代理接口实例
SomeApi someApi = new SomeApiImpl();

// 创建代理类实例
SomeApi api = (SomeApi) ApiMock.mock(someApi, "http://example.com/api");

// 调用 api 接口,就会被转发到 ApiMock 中的 invoke 方法中进行处理
String result = api.someMethod(arg1, arg2, ...);

这段代码中的 SomeApi 接口定义如下:

public interface SomeApi {
String someMethod(String arg1, int arg2, boolean arg3);
}

其中,someMethod 方法接收三个参数,返回一个字符串结果。在实际使用中,根据业务需求,你需要实现 getResponse 和 getDelay 方法,以模拟不同的情况,并指定不同方法的返回结果和响应时间。

责任编辑:华轩 来源: 今日头条
相关推荐

2015-09-28 15:59:00

Java动态代理机制

2022-11-15 09:57:51

Java接口

2020-12-28 07:47:35

动态代理AOP

2012-02-08 10:12:19

Java反射

2017-05-11 21:30:01

Android动态代理ServiceHook

2015-09-22 11:09:47

Java 8动态代理

2021-07-06 06:39:22

Java静态代理动态代理

2020-12-29 05:34:00

动态代理

2011-04-06 11:41:25

Java动态代理

2012-08-28 10:59:26

JavaJava动态代理Proxy

2021-07-20 10:30:46

Golanghttp语言

2023-07-05 08:17:38

JDK动态代理接口

2009-06-22 15:10:00

java 编程AOP

2022-04-02 07:52:47

DubboRPC调用动态代理

2017-10-12 14:56:11

2011-03-23 10:40:51

java代理模式

2022-02-22 22:44:46

接口源码对象

2023-12-06 08:23:44

代理模式设计模式

2011-11-17 14:32:45

Java静态代理动态代理

2023-02-24 07:42:30

Java动态代理
点赞
收藏

51CTO技术栈公众号