Skip to content

Commit

Permalink
feat:feign接口支持mock
Browse files Browse the repository at this point in the history
  • Loading branch information
yinjihuan committed May 25, 2022
1 parent 28d6505 commit c128779
Show file tree
Hide file tree
Showing 16 changed files with 221 additions and 6 deletions.
11 changes: 9 additions & 2 deletions fox-mock-agent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<groupId>com.cxytiandi</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<version>6.0</version>
<version>7.0</version>
<modelVersion>4.0.0</modelVersion>

<artifactId>fox-mock-agent</artifactId>
Expand Down Expand Up @@ -69,7 +69,14 @@
<artifactId>dubbo</artifactId>
<scope>provided</scope>
<optional>true</optional>
<version>2.7.3</version>
</dependency>

<!-- Feign -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,5 @@ private static void preLoadClass() {
} catch (ClassNotFoundException e) {
LOG.warn("{} ClassNotFoundException", FoxMockConstant.IBATIS_CACHING_EXECUTOR);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public static Set<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
}
}
54 changes: 54 additions & 0 deletions fox-mock-agent/src/main/java/feign/FeignInvokeFilter.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
Expand Down
18 changes: 18 additions & 0 deletions fox-mock-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down Expand Up @@ -68,5 +75,16 @@
<artifactId>nacos-client</artifactId>
<version>1.1.4</version>
</dependency>

<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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<String, UserDetail.UserAddress> addressMap = userDetail1.getAddressMap();
addressMap.forEach((k,v) -> {
System.out.println(k + "\t" + v.getAddress());
});
}

System.out.println("----------------------------------------");
Thread.sleep(5000);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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<UserDetail> getUserDetail();

}
Original file line number Diff line number Diff line change
@@ -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<UserDetail> getUserDetail() {
return new Result<>();
}
}
Original file line number Diff line number Diff line change
@@ -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<UserDetail> getUserDetail() {
return feignApi.getUserDetail();
}
}
4 changes: 3 additions & 1 deletion fox-mock-example/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
dubbo.protocol.port=20880

feign.sentinel.enabled=true
9 changes: 9 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<ognl.version>3.1.19</ognl.version>
<mybatis.version>3.5.6</mybatis.version>
<dubbo.version>2.7.3</dubbo.version>
<feign.version>10.2.3</feign.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -72,12 +73,20 @@
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>

<!-- Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>

<!-- Feign -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>${feign.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

0 comments on commit c128779

Please sign in to comment.