Build a Custom Java RPC Framework with Netty, Zookeeper, and Spring
This article explains the fundamentals of RPC, walks through a complete Java implementation using Spring, Netty, and Zookeeper, and provides step‑by‑step code for both the service provider and consumer, including registration, dynamic proxy generation, network communication, and testing.
Introduction
Remote Procedure Call (RPC) is a protocol that allows a program on one machine to invoke a method on a program running on another machine as if it were a local call, abstracting away the underlying network communication.
What a Basic RPC Call Involves
A typical RPC call includes interface‑based remote method invocation, dynamic proxy generation on the client side, serialization/deserialization of request and response objects, service registration in a registry, service discovery, and network communication handled by a high‑performance framework such as Netty.
Basic Implementation
Server (Provider)
Service Interface
/**
* @author Sun Hao
* @description Service interface
*/
public interface HelloService {
String sayHello(String somebody);
}Service Implementation
/**
* @author Sun Hao
* @description Service implementation
*/
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String somebody) {
return "hello " + somebody + "!";
}
}Service Registration
The service is registered to a Zookeeper‑based registry using custom Spring XML configuration and a namespace handler that maps the service element to a ProviderFactoryBean. The bean loads the implementation, creates a Netty server, and writes metadata (interface, host, port, weight, etc.) to Zookeeper.
public class ProviderFactoryBean implements FactoryBean, InitializingBean {
private Class<?> serviceItf;
private Object serviceObject;
private String serverPort;
private long timeout;
private String appKey;
private String groupName = "default";
private int weight = 1;
private int workerThreads = 10;
@Override
public Object getObject() throws Exception {
return serviceProxyObject;
}
@Override
public Class<?> getObjectType() {
return serviceItf;
}
@Override
public void afterPropertiesSet() throws Exception {
NettyServer.singleton().start(Integer.parseInt(serverPort));
RegisterCenter.singleton().registerProvider(buildProviderServiceInfos());
}
}Client (Consumer)
Dynamic Proxy Generation
public Object getProxy() {
return Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class<?>[]{targetInterface},
this);
}Service Discovery
The client obtains the list of provider nodes from Zookeeper and selects one according to a load‑balancing strategy.
String serviceKey = targetInterface.getName();
List<ProviderService> providerServices = RegisterCenter.singleton()
.getServiceMetaDataMap4Consume().get(serviceKey);
ClusterStrategy strategy = ClusterEngine.queryClusterStrategy(clusterStrategy);
ProviderService provider = strategy.select(providerServices);Remote Invocation via Netty
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
StormRequest request = new StormRequest();
request.setUniqueKey(UUID.randomUUID().toString() + "-" + Thread.currentThread().getId());
request.setProviderService(provider.copy());
request.setInvokedMethodName(method.getName());
request.setArgs(args);
Future<StormResponse> future = threadPool.submit(
RevokerServiceCallable.of(new InetSocketAddress(ip, port), request));
StormResponse response = future.get(request.getInvokeTimeout(), TimeUnit.MILLISECONDS);
return response != null ? response.getResult() : null;
}Testing
Server startup:
public class MainServer {
public static void main(String[] args) throws Exception {
new ClassPathXmlApplicationContext("storm-server.xml");
System.out.println("Service published");
}
}Client usage:
public class Client {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("storm-client.xml");
HelloService hello = (HelloService) ctx.getBean("helloService");
System.out.println(hello.sayHello("World"));
}
}Conclusion
The article demonstrates a complete RPC workflow: the provider loads and registers the service, starts a Netty server, and handles requests via reflection; the consumer creates a dynamic proxy, discovers services through Zookeeper, and performs remote calls with Netty, illustrating the core concepts of RPC in Java.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
