Easy-Dubbo——简单的Dubbo框架实现
实现原理
- 服务提供者端将将接口注册到注册中心,并指明对应的实现类。通过tomcat、netty等实现网络通信,将服务暴露出去。内部使用servlet等实现路由在收到消费端请求时找到对应的实现类。
- 服务消费者使用从注册中心获取url列表,使用随机数等算法找到一个url,将参数、方法名当做http等协议的请求请求参数发起调用。
源码解析
服务端
- 服务端启动。
- 将url注册到远程服务器上
- 将本地实现缓存
- 根据协议启动服务,协议有dubbo和http
public class Provider {
public static void main(String[] args) {
LocalRegister.register(HelloService.class.getName(),"1.0", HelloServiceImpl.class);
LocalRegister.register(HelloService.class.getName(),"2.0", HelloServiceImpl2.class);
//注册中心
URL u1 = new URL("localhost", 9999);
URL u2 = new URL("localhost", 9998);
RemoteMapRegister.regist(HelloService.class.getName(),"1.0", u1);
RemoteMapRegister.regist(HelloService.class.getName(),"2.0", u1);
// RemoteMapRegister.regist(HelloService.class.getName(),"2.0", u2);
// HttpServer httpServer = new HttpServer();
Protocol protocol = ProtocolFactory.getProtocol();
protocol.start(u1);
//protocol.start(u2);
}
}
客户端
- 获取代理对象
public class Consumer {
public static void main(String[] args) {
HelloService helloService = ProxyFactory.getProxy(HelloService.class,"1.0");
String cgm = helloService.say("CGM");
System.out.println(cgm);
}
}
- 根据协议获取对应的服务,进行发送消息。
public class ProxyFactory {
public static <T> T getProxy(Class interFaceClass,String version) {
return (T) Proxy.newProxyInstance(interFaceClass.getClassLoader(), new Class[]{interFaceClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Invocation invocation = new Invocation();
invocation.setInterfaceName(interFaceClass.getName());
invocation.setMethodName(method.getName());
invocation.setParamTypes(method.getParameterTypes());
invocation.setParams(args);
invocation.setVersion(version);
//HttpClient httpClient = new HttpClient();
//NettyClient httpClient = new NettyClient<>();
Protocol protocol = ProtocolFactory.getProtocol();
List<URL> urls = RemoteMapRegister.get(interFaceClass.getName()+version);
//负载均衡
URL url = LoadBalance.
getUrl(urls);
String result = protocol.send(url, invocation);
return result;
}
});
}
}
Netty的启动服务器
netty启动服务
public class NettyServer {
public void start(String hostName, int port) {
try {
final ServerBootstrap bootstrap = new ServerBootstrap();
NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();
bootstrap.group(eventLoopGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers
.weakCachingConcurrentResolver(this.getClass()
.getClassLoader())));
pipeline.addLast("encoder", new ObjectEncoder());
pipeline.addLast("handler", new NettyServerHandler());
}
});
bootstrap.bind(hostName, port).sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void close() {
}
}
// netty服务器接收消息处理:NettyServerHandler
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Invocation invocation = (Invocation) msg;
Class serviceImpl = LocalRegister.get(invocation.getInterfaceName() + invocation.getVersion());
Method method = serviceImpl.getMethod(invocation.getMethodName(), invocation.getParamTypes());
Object result = method.invoke(serviceImpl.newInstance(), invocation.getParams());
System.out.println("Netty-------------" + result.toString());
ctx.writeAndFlush("Netty:" + result);
}
}
netty客户端发消息
public class NettyClient<T> {
public NettyClientHandler client = null;
private static ExecutorService executorService = Executors.newCachedThreadPool();
public void start(String hostName, Integer port) {
client = new NettyClientHandler();
Bootstrap b = new Bootstrap();
EventLoopGroup group = new NioEventLoopGroup();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers
.weakCachingConcurrentResolver(this.getClass()
.getClassLoader())));
pipeline.addLast("encoder", new ObjectEncoder());
pipeline.addLast("handler", client);
}
});
try {
b.connect(hostName, port).sync();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String send(String hostName, Integer port, Invocation invocation) {
if (client == null) {
start(hostName, port);
}
client.setInvocation(invocation);
try {
return (String) executorService.submit(client).get();
} catch (InterruptedException e) {
// e.printStackTrace();
} catch (ExecutionException e) {
// e.printStackTrace();
}
return null;
}
}
// netty客户端接收消息处理:NettyClientHandler
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {
private ChannelHandlerContext context;
private Invocation invocation;
private String result;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
context = ctx;
}
@Override
public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
result = msg.toString();
notify();
}
public synchronized Object call() throws Exception {
context.writeAndFlush(this.invocation);
wait();
return result;
}
public void setInvocation(Invocation invocation) {
this.invocation = invocation;
}
}
项目地址
- https://gitee.com/charles_ruan/easy-dubbo