MockRpc Platform: Zero‑Intrusion Mocking for Front‑Middle‑End Decoupling in JD Retail

The article introduces the MockRpc platform, which uses Spring‑based extensions and a mock server to fully decouple front‑end services from middle‑end services in a micro‑service architecture, enabling zero‑intrusion testing, configurable mock data, and improved development efficiency for JD Retail.

JD Retail Technology
JD Retail Technology
JD Retail Technology
MockRpc Platform: Zero‑Intrusion Mocking for Front‑Middle‑End Decoupling in JD Retail

Background Introduction Modern internet applications increasingly adopt micro‑service architectures to achieve rapid response and scalability; JD Retail also uses micro‑services, which improve iteration speed and resource utilization, but incomplete decoupling and network isolation can reduce development efficiency. MockRpc was created to fully decouple the front‑end and middle‑end, eliminating network isolation and boosting developer productivity.

MockRpc Platform Position The platform sits between the front‑end service and the middle‑end, as shown in the diagram below:

In the front‑end, a mockClient hooks the JSF interface, sends the request (with parameters) to a mockServer, which decides whether to forward the request to the real middle‑end or return mock data. When the mock switch is off, the client calls the real JSF service; when on, it uses the mock data, achieving complete decoupling without code changes.

Principle JSF is an RPC protocol similar to Dubbo; both front‑end and middle‑end services are Spring‑based, and the mock mechanism is implemented using Spring extensions.

JSF Consumer Injection Example

<jsf:consumer id="qa*Service" interface="com.jd.*.*.*.QService" protocol="jsf" alias="TEST" timeout="2000" retries="1">
    <jsf:parameter key="token" value="f1*******c" hide="true"/>
</jsf:consumer>

To hook the service, a custom proxy class is injected with the original ID, while the JSF‑generated proxy is renamed (e.g., qa*Service_jsf), allowing the mock client to intercept calls.

Custom Proxy Injection Configuration

<jsf:consumer id="qa*Service_jsf" interface="com.jd.*.*.*.QService" protocol="jsf" alias="TEST" timeout="2000" retries="1">
    <jsf:parameter key="token" value="f1*******c" hide="true"/>
</jsf:consumer>
<mdc:consumer id="qa*Service" interface="com.jd.*.*.*.QService" token="f1*******c" />

The mdc tag is a custom Spring schema that injects a proxy implementing mock logic; the token uniquely identifies mock data for a given user and interface.

mockClient Core Functions The client extends the Spring schema to inject the custom proxy and implements two main capabilities: (1) request mock data from the mock server, and (2) when the mock switch is off, fall back to the real JSF service.

Key Extension Files

1. MdcNamespaceHandler registers the "consumer" element:

public class MdcNamespaceHandler extends NamespaceHandlerSupport {
    public void init() {
        registerBeanDefinitionParser("consumer", new MdcBeanDefinitionParser(ConsumerBean.class));
    }
}

2. ConsumerBean creates the custom proxy instance:

public class ConsumerBean<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
    /** Returns the custom proxy */
    public T getObject() {
        Object bean = null;
        try { bean = applicationContext.getBean(id + "_jsf"); } catch (Exception e) { log.error("mock_rpc_client get jsf bean exception:{}", e); }
        Object proxyInstance = Proxy.newProxyInstance(ClassLoaderUtils.getClassLoader(getInterfaceClass()), new Class[]{getInterfaceClass()}, new InvokerInvocationHandler(getInterface(), getToken(), bean, getAddress()));
        return (T) proxyInstance;
    }
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }
}

3. InvokerInvocationHandler handles method invocation, contacting the mock server and falling back to the real JSF bean when necessary:

public class InvokerInvocationHandler implements InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        Param param = new Param();
        param.setClassName(className);
        param.setMethodName(methodName);
        param.setToken(token);
        String mockResponse = HttpClientUtil.sendHttpRequest(address, param);
        if (StringUtils.isNotBlank(mockResponse)) {
            try {
                JSONObject jsonObject = JSON.parseObject(mockResponse);
                if (jsonObject != null && "0".equals(jsonObject.getString("code")) && "0".equals(jsonObject.getString("resultCode"))) {
                    String mockData = jsonObject.getString("mockData");
                    if (StringUtils.isNotBlank(mockData)) {
                        Type genericReturnType = method.getGenericReturnType();
                        return JSON.parseObject(mockData, genericReturnType);
                    }
                }
            } catch (Exception e) { log.error("mock_rpc_client exception:{} ", e); }
        }
        if (bean != null) {
            try {
                Method realMethod = bean.getClass().getMethod(methodName, parameterTypes);
                return realMethod.invoke(bean, args);
            } catch (Exception e) { log.error("mock_rpc_client mock_real_invoke_exception:{} ", e); }
            return null;
        } else {
            return null;
        }
    }
}

mockServer Overview The mockServer module provides mock data configuration, switch control, and a getMockData API. Its management UI includes interface list, method list, mock data list, and individual mock data details (see images below).

Conclusion Although the JSF platform itself supports mocking, network isolation and high entry barriers limit its adoption; MockRpc overcomes these issues, delivering significant debugging efficiency gains, complete front‑middle decoupling, and zero‑intrusion code changes. The approach is also applicable to other RPC frameworks such as Dubbo, allowing custom mock strategies in the mockServer.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MicroservicesRPCDevOpsspringMocking
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.