diff --git a/fox-mock-agent/pom.xml b/fox-mock-agent/pom.xml
index 4fde946..a33da51 100644
--- a/fox-mock-agent/pom.xml
+++ b/fox-mock-agent/pom.xml
@@ -7,7 +7,7 @@
com.cxytiandi
1.0-SNAPSHOT
- 6.0
+ 7.0
4.0.0
fox-mock-agent
@@ -69,7 +69,14 @@
dubbo
provided
true
- 2.7.3
+
+
+
+
+ io.github.openfeign
+ feign-core
+ provided
+ true
diff --git a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/FoxMockAgent.java b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/FoxMockAgent.java
index 08ea746..77e1103 100644
--- a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/FoxMockAgent.java
+++ b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/FoxMockAgent.java
@@ -129,6 +129,5 @@ private static void preLoadClass() {
} catch (ClassNotFoundException e) {
LOG.warn("{} ClassNotFoundException", FoxMockConstant.IBATIS_CACHING_EXECUTOR);
}
-
}
}
diff --git a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/constant/FoxMockConstant.java b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/constant/FoxMockConstant.java
index d32b0ad..90a8533 100644
--- a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/constant/FoxMockConstant.java
+++ b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/constant/FoxMockConstant.java
@@ -13,6 +13,7 @@ public class FoxMockConstant {
public static final String IBATIS_BASE_EXECUTOR = "org.apache.ibatis.executor.BaseExecutor";
public static final String IBATIS_CACHING_EXECUTOR = "org.apache.ibatis.executor.CachingExecutor";
public static final String DUBBO_CONSUMER_FILTER = "org.apache.dubbo.rpc.filter.ConsumerContextFilter";
+ public static final String FEIGN_METHOD_HANDLER = "feign.SynchronousMethodHandler";
public static final String IBATIS_MOCK_QUERY_METHOD = "query";
public static final String IBATIS_MOCK_UPDATE_METHOD = "update";
diff --git a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/storage/StorageHelper.java b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/storage/StorageHelper.java
index 6b9d16d..9f85f36 100644
--- a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/storage/StorageHelper.java
+++ b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/storage/StorageHelper.java
@@ -71,6 +71,7 @@ public static Set getMockClassNames() {
allMockClassNames.add(FoxMockConstant.IBATIS_BASE_EXECUTOR);
allMockClassNames.add(FoxMockConstant.IBATIS_CACHING_EXECUTOR);
allMockClassNames.add(FoxMockConstant.DUBBO_CONSUMER_FILTER);
+ allMockClassNames.add(FoxMockConstant.FEIGN_METHOD_HANDLER);
return allMockClassNames;
}
}
diff --git a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/transformer/MethodInvokeFilter.java b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/transformer/MethodInvokeFilter.java
index 56f4ca0..c99eef6 100644
--- a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/transformer/MethodInvokeFilter.java
+++ b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/transformer/MethodInvokeFilter.java
@@ -37,7 +37,7 @@ public class MethodInvokeFilter {
private static final Logger LOG = LoggerFactory.getLogger(MethodInvokeFilter.class);
public static boolean filter(Object[] args, String express) {
- if (args.length == 0 || StringUtils.isBlank(express)) {
+ if (args == null || args.length == 0 || StringUtils.isBlank(express)) {
return true;
}
diff --git a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/transformer/MockClassFileTransformer.java b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/transformer/MockClassFileTransformer.java
index bf480e0..24226ca 100644
--- a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/transformer/MockClassFileTransformer.java
+++ b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/transformer/MockClassFileTransformer.java
@@ -107,6 +107,17 @@ public byte[] transform(ClassLoader loader, String className, Class> classBein
}
}
+ if (FoxMockConstant.FEIGN_METHOD_HANDLER.equals(classInfo.getClassName())) {
+ for (CtMethod method : declaredMethods) {
+ String methodName = method.getName();
+ if ("invoke".equals(methodName)) {
+ LOG.info("mock feign FeignInvocationHandler invoke method");
+ method.insertBefore("Object data = feign.FeignInvokeFilter.invoke($args,this);if(java.util.Objects.nonNull(data)){return ($r)data;}");
+ }
+ }
+ }
+
+
// 缓存没有增强之前的类的信息
if (match && !CLASS_INFO.containsKey(className)) {
CLASS_INFO.put(className, new ClassInfo(className, classfileBuffer, loader));
diff --git a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/utils/ReflectionUtils.java b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/utils/ReflectionUtils.java
index d641eff..26056e1 100644
--- a/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/utils/ReflectionUtils.java
+++ b/fox-mock-agent/src/main/java/com/cxytiandi/foxmock/agent/utils/ReflectionUtils.java
@@ -1,5 +1,6 @@
package com.cxytiandi.foxmock.agent.utils;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Objects;
@@ -32,4 +33,10 @@ public static Type getGenericReturnType(String className, String methodName) {
return genericReturnType;
}
+
+ public static Object getFieldValue(String fieldName, Class> clz, Object target) throws Throwable {
+ Field field = clz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return field.get(target);
+ }
}
diff --git a/fox-mock-agent/src/main/java/feign/FeignInvokeFilter.java b/fox-mock-agent/src/main/java/feign/FeignInvokeFilter.java
new file mode 100644
index 0000000..f8f392a
--- /dev/null
+++ b/fox-mock-agent/src/main/java/feign/FeignInvokeFilter.java
@@ -0,0 +1,54 @@
+package feign;
+
+import com.alibaba.arthas.deps.org.slf4j.Logger;
+import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
+import com.cxytiandi.foxmock.agent.factory.MockInfoFactory;
+import com.cxytiandi.foxmock.agent.model.MockInfo;
+import com.cxytiandi.foxmock.agent.storage.StorageHelper;
+import com.cxytiandi.foxmock.agent.transformer.MethodInvokeFilter;
+import com.cxytiandi.foxmock.agent.utils.JsonUtils;
+import com.cxytiandi.foxmock.agent.utils.ReflectionUtils;
+import java.lang.reflect.Type;
+import java.util.Objects;
+
+/**
+ * @作者 尹吉欢
+ * @个人微信 jihuan900
+ * @微信公众号 猿天地
+ * @GitHub https://github.com/yinjihuan
+ * @作者介绍 http://cxytiandi.com/about
+ * @时间 2022-05-24 23:07
+ */
+public class FeignInvokeFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(FeignInvokeFilter.class);
+
+ public static Object invoke(Object[] argsArray, Object methodHandler) throws Throwable {
+ Object[] args = (Object[]) argsArray[0];
+ SynchronousMethodHandler handler = (SynchronousMethodHandler) methodHandler;
+ Class extends SynchronousMethodHandler> handlerClass = handler.getClass();
+
+ MethodMetadata methodMetadata = (MethodMetadata) ReflectionUtils.getFieldValue("metadata", handlerClass, handler);
+ Target> target = (Target>) ReflectionUtils.getFieldValue("target", handlerClass, handler);;
+
+ String className = target.type().getName();
+ String ms = methodMetadata.configKey().split("#")[1];
+ String methodName = ms.substring(0, ms.indexOf("("));
+
+ String key = String.format("%s#%s", className, methodName);
+ String data = StorageHelper.get(key);
+
+ if (Objects.nonNull(data)) {
+ MockInfo mockInfo = MockInfoFactory.create(data);
+ boolean filter = MethodInvokeFilter.filter(args, mockInfo.getOgnlExpress());
+ if (filter) {
+ LOG.info(String.format("mock methods %s, mock data is %s", key, data));
+ Type genericReturnType = methodMetadata.returnType();
+ Object value = JsonUtils.parseByType(mockInfo.getMockData(), genericReturnType);
+ return value;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/fox-mock-boot/src/main/java/com/cxytiandi/foxmock/boot/Bootstrap.java b/fox-mock-boot/src/main/java/com/cxytiandi/foxmock/boot/Bootstrap.java
index 020bb6c..fd0b85b 100644
--- a/fox-mock-boot/src/main/java/com/cxytiandi/foxmock/boot/Bootstrap.java
+++ b/fox-mock-boot/src/main/java/com/cxytiandi/foxmock/boot/Bootstrap.java
@@ -31,7 +31,7 @@ public static void main(String[] args) {
String mockDataHttpUrl = config.getProperty("mockDataHttpUrl", "");
if (Objects.isNull(foxMockAgentJarPath)) {
- foxMockAgentJarPath = PathUtils.getAgentPath() + File.separator + "fox-mock-agent-6.0.jar";
+ foxMockAgentJarPath = PathUtils.getAgentPath() + File.separator + "fox-mock-agent-7.0.jar";
}
VirtualMachine attach = VirtualMachine.attach(String.valueOf(getPid()));
diff --git a/fox-mock-example/pom.xml b/fox-mock-example/pom.xml
index c9493d1..64e2c50 100644
--- a/fox-mock-example/pom.xml
+++ b/fox-mock-example/pom.xml
@@ -20,6 +20,13 @@
pom
import
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ Greenwich.SR2
+ pom
+ import
+
@@ -68,5 +75,16 @@
nacos-client
1.1.4
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+ 2.1.0.RELEASE
+
\ No newline at end of file
diff --git a/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/FoxMockApp.java b/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/FoxMockApp.java
index a9a6173..2a61fce 100644
--- a/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/FoxMockApp.java
+++ b/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/FoxMockApp.java
@@ -1,11 +1,13 @@
package com.cxytiandi.foxmock.example;
import com.cxytiandi.foxmock.example.dubbo.DubboApiTestService;
+import com.cxytiandi.foxmock.example.feign.FeignApiTestService;
import com.cxytiandi.foxmock.example.mybatis.UserMapper;
import com.cxytiandi.foxmock.example.mybatis.UserQuery;
import com.google.gson.Gson;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.Map;
@@ -19,6 +21,7 @@
* @作者介绍 http://cxytiandi.com/about
* @时间 2022-04-18 22:11
*/
+@EnableFeignClients(basePackages = "com.cxytiandi.foxmock.example.feign")
@EnableTransactionManagement
@SpringBootApplication
public class FoxMockApp {
@@ -70,6 +73,18 @@ public static void main(String[] args) throws Exception {
});
}
+ FeignApiTestService feignApiTestService = ApplicationContextHelper.getBean(FeignApiTestService.class);
+ System.out.println("feign getUserInfo:" + new Gson().toJson(feignApiTestService.getUserInfo(1L)));
+ userDetailResult1 = feignApiTestService.getUserDetail();
+ System.out.println("feign getUserDetail:" + new Gson().toJson(userDetailResult1));
+ userDetail1 = userDetailResult1.getData();
+ if (Objects.nonNull(userDetail1)) {
+ Map addressMap = userDetail1.getAddressMap();
+ addressMap.forEach((k,v) -> {
+ System.out.println(k + "\t" + v.getAddress());
+ });
+ }
+
System.out.println("----------------------------------------");
Thread.sleep(5000);
}
diff --git a/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApi.java b/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApi.java
new file mode 100644
index 0000000..d3673bc
--- /dev/null
+++ b/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApi.java
@@ -0,0 +1,30 @@
+package com.cxytiandi.foxmock.example.feign;
+
+import com.cxytiandi.foxmock.example.Result;
+import com.cxytiandi.foxmock.example.UserDetail;
+import com.cxytiandi.foxmock.example.UserInfo;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * @作者 尹吉欢
+ * @个人微信 jihuan900
+ * @微信公众号 猿天地
+ * @GitHub https://github.com/yinjihuan
+ * @作者介绍 http://cxytiandi.com/about
+ * @时间 2022-05-24 22:59
+ */
+@FeignClient(name = "fox-mock-example", url = "http://localhost:8080")
+public interface FeignApi {
+
+ @RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)
+ UserInfo getUserInfo(@RequestParam("id")Long id);
+
+ @RequestMapping(value = "/getUserDetail", method = RequestMethod.GET)
+ Result getUserDetail();
+
+}
diff --git a/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApiImpl.java b/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApiImpl.java
new file mode 100644
index 0000000..9ca46b4
--- /dev/null
+++ b/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApiImpl.java
@@ -0,0 +1,28 @@
+package com.cxytiandi.foxmock.example.feign;
+
+import com.cxytiandi.foxmock.example.Result;
+import com.cxytiandi.foxmock.example.UserDetail;
+import com.cxytiandi.foxmock.example.UserInfo;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @作者 尹吉欢
+ * @个人微信 jihuan900
+ * @微信公众号 猿天地
+ * @GitHub https://github.com/yinjihuan
+ * @作者介绍 http://cxytiandi.com/about
+ * @时间 2022-05-24 22:59
+ */
+@RestController
+public class FeignApiImpl {
+
+ @RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)
+ public UserInfo getUserInfo(@RequestParam("id")Long id) {
+ return new UserInfo();
+ }
+
+ @RequestMapping(value = "/getUserDetail", method = RequestMethod.GET)
+ public Result getUserDetail() {
+ return new Result<>();
+ }
+}
diff --git a/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApiTestService.java b/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApiTestService.java
new file mode 100644
index 0000000..16856c6
--- /dev/null
+++ b/fox-mock-example/src/main/java/com/cxytiandi/foxmock/example/feign/FeignApiTestService.java
@@ -0,0 +1,33 @@
+package com.cxytiandi.foxmock.example.feign;
+
+import com.cxytiandi.foxmock.example.Result;
+import com.cxytiandi.foxmock.example.UserDetail;
+import com.cxytiandi.foxmock.example.UserInfo;
+import com.cxytiandi.foxmock.example.dubbo.DubboApi;
+import org.apache.dubbo.config.annotation.Reference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.bind.annotation.RequestParam;
+
+/**
+ * @作者 尹吉欢
+ * @个人微信 jihuan900
+ * @微信公众号 猿天地
+ * @GitHub https://github.com/yinjihuan
+ * @作者介绍 http://cxytiandi.com/about
+ * @时间 2022-05-18 23:00
+ */
+@Service
+public class FeignApiTestService {
+
+ @Autowired
+ private FeignApi feignApi;
+
+ public UserInfo getUserInfo(Long id) {
+ return feignApi.getUserInfo(id);
+ }
+
+ public Result getUserDetail() {
+ return feignApi.getUserDetail();
+ }
+}
diff --git a/fox-mock-example/src/main/resources/application.properties b/fox-mock-example/src/main/resources/application.properties
index 1fee8f1..805e12e 100644
--- a/fox-mock-example/src/main/resources/application.properties
+++ b/fox-mock-example/src/main/resources/application.properties
@@ -11,4 +11,6 @@ dubbo.application.name=foxmock-example
dubbo.registry.address=47.105.66.210:8848
dubbo.registry.protocol=nacos
dubbo.protocol.name=dubbo
-dubbo.protocol.port=20880
\ No newline at end of file
+dubbo.protocol.port=20880
+
+feign.sentinel.enabled=true
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 5b616b3..23662ee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,6 +25,7 @@
3.1.19
3.5.6
2.7.3
+ 10.2.3
@@ -72,12 +73,20 @@
mybatis
${mybatis.version}
+
org.apache.dubbo
dubbo
${dubbo.version}
+
+
+
+ io.github.openfeign
+ feign-core
+ ${feign.version}
+
\ No newline at end of file