分佈式網絡通信框架Netty_基於Netty+Zookeeper手寫RPC遠程調用框架_2 Dubbo框架完整實現

                                      分佈式網絡通信框架Netty

                              基於Netty+Zookeeper純手寫RPC遠程調用框架

                                                     2 Dubbo框架完整實現

                                                                                            學習總結

                                                                                                                                                                                  田超凡

                                                                                                                                                                                  2019年11月4日

1 創建生產者(Provider)和消費者(Consumer)

生產者:netty-zookeeper-dubbo-user-service-api 用戶服務-接口

netty-zookeeper-dubbo-user-service-provider 用戶服務-接口實現類

 

package com.tcf.netty.zookeeper.dubbo.user.service;

 

/***

 * TODO TCF 用戶接口-生產者

 * @author Hasee

 *

 */

public interface UserService {

 

//TODO TCF 根據用戶id查詢用戶信息

public String getUserById(String id);

 

}

 

package com.tcf.netty.zookeeper.dubbo.user.service.impl;

 

import com.tcf.netty.zookeeper.dubbo.common.annotation.RpcRegistration;

import com.tcf.netty.zookeeper.dubbo.user.service.UserService;

 

/***

 * TODO TCF 用戶接口實現類-生產者

 * @author Hasee

 *

 */

@RpcRegistration(UserService.class)

public class UserServiceImpl implements UserService {

 

//TODO TCF 根據用戶id查詢用戶信息

public String getUserById(String id)

{

return "張三";

}

 

}

 

消費者:netty-zookeeper-dubbo-order-service-api 訂單服務-接口

netty-zookeeper-dubbo-order-service-consumer 訂單服務-接口實現類

 

package com.tcf.netty.zookeeper.dubbo.order.service;

 

/***

 * TODO TCF 訂單業務接口-消費者

 * @author Hasee

 *

 */

public interface OrderService {

 

//TODO TCF 根據用戶id查詢用戶訂單

public String getOrderByUserId(String id);

 

}

 

package com.tcf.netty.zookeeper.dubbo.order.service.impl;

 

import com.tcf.netty.zookeeper.dubbo.order.service.OrderService;

import com.tcf.netty.zookeeper.dubbo.order.util.DubboClientUtil;

import com.tcf.netty.zookeeper.dubbo.user.service.UserService;

 

/***

 * TODO TCF 訂單服務-消費者

 * @author Hasee

 *

 */

public class OrderServiceImpl implements OrderService {

 

//TODO TCF 需要遠程調用的用戶服務接口

private UserService userService;

 

//TODO TCF 構造柱入

public OrderServiceImpl()

{

this.userService=DubboClientUtil.getDubboClient().createService(UserService.class);

}

 

//TODO TCF 根據用戶id獲取訂單信息,遠程調用用戶服務接口

public String getOrderByUserId(String id)

{

//TODO TCF 根據用戶id獲取用戶信息,遠程服務調用

String userInfo=userService.getUserById(id);

 

return userInfo;

}

}

 

 

2 創建Zookeeper註冊中心服務註冊接口ServerRegistration和實現類ServerRegistry

package com.tcf.netty.zookeeper.dubbo.server.registry;

 

/***

 * TODO TCF Zookeeper註冊中心服務註冊接口,定義服務註冊類需要註冊的規範

 * @author Hasee

 *

 */

public interface ServerRegistration {

 

//TODO TCF 註冊服務到Zookeeper註冊中心

public void registry(String serverName,String serverClassAddr);

 

}

 

package com.tcf.netty.zookeeper.dubbo.server.registry.impl;

 

import java.net.URLEncoder;

 

import org.I0Itec.zkclient.ZkClient;

 

import com.tcf.netty.zookeeper.dubbo.server.registry.ServerRegistration;

 

/***

 * TODO TCF Zookeeper註冊中心服務註冊工具類

 * @author Hasee

 *

 */

public class ServerRegistry implements ServerRegistration {

 

//TODO TCF Zookeeper註冊中心ip地址

private String host;

 

//TODO TCF Zookeeper註冊中心客戶端

private ZkClient zkClient;

 

//TODO TCF Zookeeper註冊中心連接超時時長

private int connectTimeout=5000;

 

//TODO TCF 服務註冊根目錄

private String rootPath="/netty-zookeeper-dubbo-user-service-api-v1.1";

 

//TODO TCF 註冊服務類型:生產者

private String serverSuffix="/providers";

 

//TODO TCF 構造柱入

public ServerRegistry(String host)

{

this.host=host;

this.zkClient=new ZkClient(host,connectTimeout);

}

 

//TODO TCF 註冊服務到Zookeeper註冊中心

public void registry(String serverName, String serverClassAddr)

{

try

{

//TODO TCF Zookeeper服務根目錄/rootPath

if(!zkClient.exists(rootPath))

{

zkClient.createPersistent(rootPath);

}

 

//TODO TCF Zookeeper服務二級目錄/rootPath/serverName

String secondLevelPath=rootPath+"/"+serverName;

if(!zkClient.exists(secondLevelPath))

{

zkClient.createPersistent(secondLevelPath);

}

 

//TODO TCF Zookeeper服務三級目錄/rootPath/serverName/serverSuffix

String thirdLevelPath=secondLevelPath+serverSuffix;

if(!zkClient.exists(thirdLevelPath))

{

zkClient.createPersistent(thirdLevelPath);

}

 

//TODO TCF Zookeeper服務四級目錄/rootPath/serverName/serverSuffix/serverClassPath

String nodePath=thirdLevelPath+"/"+URLEncoder.encode(serverClassAddr,"UTF-8");

if(zkClient.exists(nodePath))

{

//TODO TCF 服務節點已存在,先刪除該服務節點

zkClient.delete(nodePath);

}

 

//TODO TCF 創建服務節點,註冊服務

zkClient.createEphemeral(nodePath);

System.out.println("Zookeeper服務註冊成功,服務地址===>"+nodePath);

}

catch(Exception e)

{

e.printStackTrace();

}

}

}

 

3 創建Dubbo服務器:DubboServer

  1. .基於反射獲取需要註冊到Zookeeper註冊中心的服務並實現服務註冊,存入已註冊服務容器
  2. .初始化Netty服務器、通道,綁定事件驅動處理器、MarShalling編碼解碼器
  3. .創建DubboServerEventHandle事件驅動處理器,監聽通訊事件並處理

 

package com.tcf.netty.zookeeper.dubbo.server.core;

 

import java.util.HashMap;

import java.util.Map;

 

import com.tcf.netty.zookeeper.dubbo.common.annotation.RpcRegistration;

import com.tcf.netty.zookeeper.dubbo.common.coder.MarShallingCoderFactory;

import com.tcf.netty.zookeeper.dubbo.server.core.event.DubboServerEventHandle;

import com.tcf.netty.zookeeper.dubbo.server.registry.ServerRegistration;

import com.tcf.netty.zookeeper.dubbo.server.registry.impl.ServerRegistry;

 

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.nio.NioEventLoopGroup;

import io.netty.channel.socket.SocketChannel;

import io.netty.channel.socket.nio.NioServerSocketChannel;

 

/***

 * TODO TCF Dubbo服務器,基於Netty服務器端實現

 * @author Hasee

 *

 */

public class DubboServer {

 

//TODO TCF 已經註冊到Zookeeper註冊中心的服務

private Map<String,Object> registryMap=new HashMap<String,Object>();

 

//TODO TCF Zookeeper註冊中心和Dubbo服務器ip地址

private String host="";

 

//TODO TCF 服務啓動端口號:20880(Dubbo默認)

private int port=20880;

 

//TODO TCF Zookeeper註冊中心註冊服務協議類型

private String protocol="tcf://";

 

//TODO TCF Zookeeper服務註冊工具類

private ServerRegistration serverRegistration=null;

 

//TODO TCF 構造柱入

public DubboServer(String host)

{

this.host=host;

this.serverRegistration=new ServerRegistry(host);

}

 

//TODO TCF 初始化Dubbo服務器,註冊服務到Zookeeper註冊中心

public void start(Object service)

{

//TODO TCF 基於反射獲取需要註冊到Zookeeper註冊中心的服務,註冊到Zookeeper註冊中心

serviceRegistry(service);

 

//TODO TCF 初始化Netty服務器

initServer();

}

 

//TODO TCF 基於反射獲取需要註冊到Zookeeper註冊中心的服務並進行服務註冊

public void serviceRegistry(Object service)

{

//TODO TCF 獲取需要註冊到Zookeeper註冊中心的服務上方標註的RPC註解

if(service.getClass().isAnnotationPresent(RpcRegistration.class))

{

RpcRegistration rpcRegistration=service.getClass().getAnnotation(RpcRegistration.class);

if(rpcRegistration!=null)

{

//TODO TCF 需要註冊到Zookeeper註冊中心的服務接口

Class<?> interfaceClass=rpcRegistration.value();

 

if(interfaceClass!=null)

{

//TODO TCF 需要註冊的服務名稱

String serviceName=interfaceClass.getName().replace("interface ","");

 

//TODO TCF 拼裝服務註冊二級地址(唯一標識需要註冊的服務)

String serviceClassAddr=protocol+host+":"+port+"//";

 

//TODO TCF 把服務註冊到Zookeeper註冊中心

serverRegistration.registry(serviceName,serviceClassAddr);

 

//TODO TCF 註冊成功的服務

registryMap.put(serviceName,service);

}

}

}

}

 

//TODO TCF 初始化Dubbo服務器端,使用Netty服務器

public void initServer()

{

//TODO TCF Boss線程組和工作線程組

NioEventLoopGroup bossGroup=new NioEventLoopGroup();

    NioEventLoopGroup workGroup=new NioEventLoopGroup();

    

    //TODO TCF Netty服務器初始化,綁定事件驅動處理器、編碼解碼器,初始化Netty通道

    ServerBootstrap serverBootstrap=new ServerBootstrap();

    serverBootstrap.group(bossGroup,workGroup)

                   .channel(NioServerSocketChannel.class)

                   .childHandler(new ChannelInitializer<SocketChannel>() {

                    

                    //TODO TCF Netty服務器加載通道時綁定編碼解碼器、事件驅動處理器

                    @Override

                    protected void initChannel(SocketChannel socketChannel) throws Exception

                    {

                    //TODO TCF Netty-RPC請求編碼解碼器MarSharlling

                    socketChannel.pipeline().addLast(MarShallingCoderFactory.buildMarshallingEncoder());

                    socketChannel.pipeline().addLast(MarShallingCoderFactory.buildMarshallingDecoder());

                    

                    //TODO TCF 綁定事件驅動處理器-事件監聽

                    socketChannel.pipeline().addLast(new DubboServerEventHandle(registryMap));

                    }

                   });

    

    try

    {

     //TODO TCF 初始化Netty通道

     ChannelFuture channelFuture=serverBootstrap.bind(port).sync();

    

     System.out.println("====Dubbo 服務器啓動成功===="+port);

    

     //TODO TCF 當斷開和客戶端的連接時,關閉通道,釋放資源,未斷開連接時,此次調用會產生阻塞

     channelFuture.channel().closeFuture().sync();

    }

    catch(Exception e)

    {

     e.printStackTrace();

    }

    finally

    {

     //TODO TCF 關閉Netty線程組,釋放資源

     bossGroup.shutdownGracefully();

     workGroup.shutdownGracefully();

    }

}

}

 

DubboSeverEventHandle事件驅動處理器

package com.tcf.netty.zookeeper.dubbo.server.core.event;

 

import java.lang.reflect.Method;

import java.util.HashMap;

import java.util.Map;

 

import com.tcf.netty.zookeeper.dubbo.common.model.RpcRequest;

 

import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.ChannelInboundHandlerAdapter;

 

/***

 * TODO TCF Dubbo服務器事件驅動處理器-實現事件監聽和處理

 * @author Hasee

 *

 */

public class DubboServerEventHandle extends ChannelInboundHandlerAdapter {

 

//TODO TCF 已經註冊到Zookeeper註冊中心的服務

private Map<String,Object> registryMap=new HashMap<String,Object>();

 

//TODO TCF 構造柱入

public DubboServerEventHandle(Map<String,Object> registryMap)

{

this.registryMap=registryMap;

}

 

//TODO TCF 監聽客戶端發送的消息

@Override

public void channelRead(ChannelHandlerContext ctx,Object msg) throws Exception

{

//TODO TCF 將數據解析爲客戶端發送的RPCRequest請求參數模型

if(msg!=null)

{

if(msg instanceof RpcRequest)

{

RpcRequest rpcRequest=(RpcRequest)msg;

 

System.out.println("====接收到客戶端發送的服務調用請求:"+rpcRequest.toString());

 

//TODO TCF 根據需要調用的服務名稱獲取對應的服務

Object serviceInstance=registryMap.get(rpcRequest.getServiceClass().getName());

 

if(serviceInstance!=null)

{

//TODO TCF 基於反射獲取對應服務需要調用的方法

Method method=serviceInstance.getClass().getMethod(rpcRequest.getMethodName(),rpcRequest.getParameterTypes());

 

//TODO TCF 執行對應方法,實現服務調用

Object invokeResult=method.invoke(serviceInstance,rpcRequest.getParameterValues());

 

//TODO TCF 返回調用方法執行結果給客戶端

ctx.writeAndFlush(invokeResult);

ctx.close();

}

}

}

}

 

}

 

4 創建Zookeeper註冊中心服務發現接口和實現類ZkFoundService、ZkFoundServiceImpl

 

package com.tcf.netty.zookeeper.dubbo.client.service.handle;

 

import java.util.List;

 

/***

 * TODO TCF Zookeeper註冊中心服務發現接口

 * @author Hasee

 *

 */

public interface ZkFoundService {

 

//TODO TCF 根據服務名稱獲取註冊到Zookeeper註冊中心的服務訪問地址

public List<String> getServiceAddressList(String serviceName);

 

}

 

 

package com.tcf.netty.zookeeper.dubbo.client.service.handle.impl;

 

import java.util.List;

 

import org.I0Itec.zkclient.ZkClient;

 

import com.tcf.netty.zookeeper.dubbo.client.service.handle.ZkFoundService;

 

/***

 * TODO TCF 根據服務名稱獲取Zookeeper註冊中心的服務訪問地址

 * @author Hasee

 *

 */

public class ZkFoundServiceImpl implements ZkFoundService {

 

//TODO TCF Zookeeper註冊中心地址

private String host="";

 

//TODO TCF Zookeeper註冊中心連接超時時長

private int connectTimeout=5000;

 

//TODO TCF Zookeeper服務節點根目錄

private String rootPath="/netty-zookeeper-dubbo-user-service-api-v1.1";

 

//TODO TCF Zookeeper服務註冊角色:生產者

private String serviceSuffix="/providers";

 

//TODO TCF Zookeeper客戶端

private ZkClient zkClient;

 

//TODO TCF 構造柱入,初始化Zookeeper客戶端

public ZkFoundServiceImpl(String host)

{

this.host=host;

this.zkClient=new ZkClient(host,connectTimeout);

}

 

//TODO TCF 根據服務名稱獲取註冊到Zookeeper註冊中心的服務訪問地址

public List<String> getServiceAddressList(String serviceName)

{

    //TODO TCF 服務節點路由

String serviceNodePath=rootPath+"/"+serviceName+serviceSuffix;

List<String> addressList=zkClient.getChildren(serviceNodePath);

return addressList;

}

 

}

 

5 基於策略模式實現Dubbo負載均衡處理器DubboLoadBalance

  1. .提供隨機負載均衡策略實現類RandomLoadBalanceService
  2. .提供索引負載均衡策略實現類

IndexLoadBalanceService

(3).注意考慮多線程併發的情況

 

package com.tcf.netty.zookeeper.dubbo.client.loadbalance;

 

import java.util.List;

 

/***

 * TODO TCF 基於策略模式實現Dubbo負載均衡處理器業務接口

 * @author Hasee

 *

 */

public interface DubboLoadBalanceService {

 

//TODO TCF 根據訪問服務地址進行負載均衡策略實現,返回最終需要調用的服務訪問地址

public String loadBalance(List<String> serviceAddressList);

 

}

 

 

package com.tcf.netty.zookeeper.dubbo.client.loadbalance.impl;

 

import java.util.List;

import java.util.Random;

import com.tcf.netty.zookeeper.dubbo.client.loadbalance.DubboLoadBalanceService;

 

/***

 * TODO TCF 隨機負載均衡策略實現類

 * @author Hasee

 *

 */

public class RandomLoadBalanceService implements DubboLoadBalanceService {

 

//TODO TCF 隨機獲取服務調用地址中的某一個服務地址,實現隨機負載均衡策略

public String loadBalance(List<String> serviceAddressList)

{

String address=serviceAddressList.get(new Random().nextInt(serviceAddressList.size()));

return address;

}

 

}

 

 

package com.tcf.netty.zookeeper.dubbo.client.loadbalance.impl;

 

import java.util.List;

 

import com.tcf.netty.zookeeper.dubbo.client.loadbalance.DubboLoadBalanceService;

 

/***

 * TODO TCF 基於索引的負載均衡處理器

 * @author Hasee

 *

 */

public class IndexLoadBalanceService implements DubboLoadBalanceService {

 

//TODO TCF 當前加載到第幾個服務訪問地址

private int index=0;

 

//TODO TCF 實現索引負載均衡策略

public synchronized String loadBalance(List<String> serviceAddressList)

{

String resultAddress="";

 

if(serviceAddressList!=null && serviceAddressList.size()>0)

{

if(index>=serviceAddressList.size())

{

index=0;

}

 

resultAddress=serviceAddressList.get(index++);

System.out.println("負載均衡處理後,服務調用地址===>"+resultAddress);

}

 

return resultAddress;

}

}

 

 

6 實現Dubbo客戶端DubboClient

  1. .根據需要調用的服務接口類型創建JDK動態代理實例,實現代理方法
  2. .在代理方法中實現服務發現和遠程調用具體邏輯實現,滿足開閉原則
  3. .創建DubboClientEventHandle事件驅動處理器實現Dubbo客戶端網絡通訊事件監聽和處理

package com.tcf.netty.zookeeper.dubbo.client.core;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.net.InetSocketAddress;

import java.net.URLDecoder;

import java.util.List;

import com.tcf.netty.zookeeper.dubbo.client.core.event.DubboClientEventHandle;

import com.tcf.netty.zookeeper.dubbo.client.loadbalance.DubboLoadBalanceService;

import com.tcf.netty.zookeeper.dubbo.client.loadbalance.impl.IndexLoadBalanceService;

import com.tcf.netty.zookeeper.dubbo.client.service.handle.ZkFoundService;

import com.tcf.netty.zookeeper.dubbo.client.service.handle.impl.ZkFoundServiceImpl;

import com.tcf.netty.zookeeper.dubbo.common.coder.MarShallingCoderFactory;

import com.tcf.netty.zookeeper.dubbo.common.model.RpcRequest;

import io.netty.bootstrap.Bootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.nio.NioEventLoopGroup;

import io.netty.channel.socket.SocketChannel;

import io.netty.channel.socket.nio.NioSocketChannel;

 

/***

 * TODO TCF Dubbo客戶端,創建需要調用的服務接口的JDK動態代理實例並調用代理方法,具體的服務發現和調用實現邏輯在代理方法中

 * @author Hasee

 *

 */

public class DubboClient {

 

//TODO TCF Zookeeper註冊服務發現類

private ZkFoundService zkFoundService;

 

//TODO TCF Dubbo負載均衡處理器

private DubboLoadBalanceService dubboLoadBalanceService;

 

//TODO TCF 構造注入

public DubboClient(String host)

{

this.zkFoundService=new ZkFoundServiceImpl(host);

 

//TODO TCF 默認採用索引負載均衡策略

this.dubboLoadBalanceService=new IndexLoadBalanceService();

}

 

//TODO TCF 創建需要調用的服務接口的JDK動態代理實例,實現Zookeeper服務發現和調用

@SuppressWarnings("unchecked")

public <T> T createService(final Class<T> interfaceClass)

{

return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(),

new Class[]{interfaceClass},

new InvocationHandler() {

 

public Object invoke(Object proxy,Method method,Object[] args) throws Throwable

{

//TODO TCF 遠程服務調用後方法執行結果

Object invokeResult=null;

 

//TODO TCF 獲取需要調用的服務名稱

String serviceName=interfaceClass.getName();

 

//TODO TCF 根據服務名稱獲取已經註冊到Zookeeper註冊中心的服務訪問地址

List<String> addressList=zkFoundService.getServiceAddressList(serviceName);

 

if(addressList!=null && addressList.size()>0)

{

//TODO TCF 基於負載均衡策略獲取最終需要調用的服務地址

String address=dubboLoadBalanceService.loadBalance(addressList);

 

address=URLDecoder.decode(address,"UTF-8");

 

//TODO TCF 獲取ip地址和端口號

address=address.replace("//","").replace("/","");

 

String[] arrays=address.split(":");

 

//TODO TCF tcf://host:port//serviceName

String host=arrays[1];

Integer port=Integer.parseInt(arrays[2]);

 

//TODO TCF 封裝RPC遠程調用請求參數模型

final RpcRequest rpcRequest=new RpcRequest(interfaceClass,method.getName(),method.getParameterTypes(),args);

 

//TODO TCF 初始化Netty客戶端,連接遠程Netty服務器,傳遞RPC遠程調用請求參數,實現服務遠程調用

//TODO TCF 工作線程組

NioEventLoopGroup workGroup=new NioEventLoopGroup();

 

//TODO TCF Netty客戶端事件驅動處理器

final DubboClientEventHandle dubboClientEventHandle=new DubboClientEventHandle(rpcRequest);

 

//TODO TCF Netty客戶端初始化,綁定事件驅動處理器、MarShalling編碼解碼器,初始化Netty通道

Bootstrap client=new Bootstrap();

client.group(workGroup)

      .channel(NioSocketChannel.class)

      .remoteAddress(new InetSocketAddress(host,port.intValue()))

      .handler(new ChannelInitializer<SocketChannel>() {

    

       //TODO TCF Netty通道初始化

       @Override

       protected void initChannel(SocketChannel socketChannel) throws Exception

       {

       //TODO TCF 綁定MarShalling編碼解碼器

       socketChannel.pipeline().addLast(MarShallingCoderFactory.buildMarshallingEncoder());

       socketChannel.pipeline().addLast(MarShallingCoderFactory.buildMarshallingDecoder());

       

       //TODO TCF 綁定事件驅動處理器,實現事件監聽

       socketChannel.pipeline().addLast(dubboClientEventHandle);

       }

});

 

try

{

//TODO TCF 初始化Netty通道

ChannelFuture channelFuture=client.connect().sync();

 

//TODO TCF 斷開客戶端連接時關閉Netty通道,釋放資源

channelFuture.channel().closeFuture().sync();

 

System.out.println(serviceName+"服務的"+method.getName()+"方法遠程調用成功......");

 

//TODO TCF 服務調用之後,方法執行返回結果

    invokeResult=dubboClientEventHandle.getResponseMessage();

}

catch(Exception e)

{

e.printStackTrace();

}

finally

{

//TODO TCF 關閉線程組,釋放線程佔用資源

workGroup.shutdownGracefully();

}

}

 

return invokeResult;

}

});

}

 

}

 

Dubbo客戶端事件驅動處理器DubboClientEventHandle,發送RPC服務遠程調用請求到對應的Netty服務器並接收服務器返回的方法執行響應結果

package com.tcf.netty.zookeeper.dubbo.client.core.event;

 

import com.tcf.netty.zookeeper.dubbo.common.model.RpcRequest;

 

import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.ChannelInboundHandlerAdapter;

 

/***

 * TODO TCF Dubbo客戶端事件驅動處理器-監聽事件

 * @author Hasee

 *

 */

public class DubboClientEventHandle extends ChannelInboundHandlerAdapter {

 

//TODO TCF 服務遠程調用請求參數

private RpcRequest rpcRequest;

 

//TODO TCF Netty服務器返回的服務調用執行結果

private Object responseMessage;

 

//TODO TCF 構造柱入

public DubboClientEventHandle(RpcRequest rpcRequest)

{

this.rpcRequest=rpcRequest;

}

 

public Object getResponseMessage() {

return responseMessage;

}

public void setResponseMessage(Object responseMessage) {

this.responseMessage = responseMessage;

}

 

//TODO TCF 接收到服務器返回的響應信息

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception

{

if(msg!=null)

{

this.responseMessage=msg;

System.out.println("接收到服務器返回的響應信息(方法執行結果):"+msg);

ctx.close();

}

}

 

//TODO TCF 發送RPC服務遠程調用請求到Netty服務器端

@Override

public void channelActive(ChannelHandlerContext ctx) throws Exception

{

ctx.writeAndFlush(rpcRequest);

}

 

}

 

 

 

7 創建自定義RPC服務註冊註解RpcRegistration

package com.tcf.netty.zookeeper.dubbo.common.annotation;

 

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

/***

 * TODO TCF 標註需要註冊到Zookeeper註冊中心的服務接口實現類

 * @author Hasee

 *

 */

@Documented

@Inherited

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface RpcRegistration {

 

//TODO TCF 需要註冊到Zookeeper註冊中心的服務接口類型

Class<?> value();

 

}

 

8 創建RPC遠程服務調用-數據傳輸載體RpcRequest模型類

 

package com.tcf.netty.zookeeper.dubbo.common.model;

 

import java.io.Serializable;

 

/***

 * TODO TCF RPC遠程調用請求數據模型類

 * @author Hasee

 *

 */

public class RpcRequest implements Serializable {

 

 

/**

 *

 */

private static final long serialVersionUID = 1L;

 

//TODO TCF 需要調用的服務接口

private Class<?> serviceClass;

 

//TODO TCF 需要調用的服務接口方法名

private String methodName;

 

//TODO TCF 需要調用的服務接口方法參數類型

private Class<?>[] parameterTypes;

 

//TODO TCF 需要調用的服務接口方法參數列表

private Object[] parameterValues;

 

//TODO TCF 構造柱入

public RpcRequest(Class<?> serviceClass,String methodName,Class<?>[] parameterTypes,Object[] parameterValues)

{

this.serviceClass=serviceClass;

this.methodName=methodName;

this.parameterTypes=parameterTypes;

this.parameterValues=parameterValues;

}

 

public Class<?> getServiceClass() {

return serviceClass;

}

public void setServiceClass(Class<?> serviceClass) {

this.serviceClass = serviceClass;

}

public String getMethodName() {

return methodName;

}

public void setMethodName(String methodName) {

this.methodName = methodName;

}

public Class<?>[] getParameterTypes() {

return parameterTypes;

}

public void setParameterTypes(Class<?>[] parameterTypes) {

this.parameterTypes = parameterTypes;

}

public Object[] getParameterValues() {

return parameterValues;

}

public void setParameterValues(Object[] parameterValues) {

this.parameterValues = parameterValues;

}

 

}

9 創建Netty編碼器和解碼器工廠MarShallingCoderFactory,創建MarShalling編碼器Encoder和解碼器Decoder,實現RpcRequest請求數據傳輸時的序列化和反序列化

 

package com.tcf.netty.zookeeper.dubbo.common.coder;

 

import org.jboss.marshalling.MarshallerFactory;

import org.jboss.marshalling.Marshalling;

import org.jboss.marshalling.MarshallingConfiguration;

import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;

import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;

import io.netty.handler.codec.marshalling.MarshallerProvider;

import io.netty.handler.codec.marshalling.MarshallingDecoder;

import io.netty.handler.codec.marshalling.MarshallingEncoder;

import io.netty.handler.codec.marshalling.UnmarshallerProvider;

 

public class MarShallingCoderFactory {

 

/**

     * 創建Jboss Marshalling解碼器MarshallingDecoder

     * @return MarshallingDecoder

     */

    public static MarshallingDecoder buildMarshallingDecoder()

    {

        //首先通過Marshalling工具類的精通方法獲取Marshalling實例對象 參數serial標識創建的是java序列化工廠對象。

        final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");

        //創建了MarshallingConfiguration對象,配置了版本號爲5

        final MarshallingConfiguration configuration = new MarshallingConfiguration();

        configuration.setVersion(5);

        //根據marshallerFactory和configuration創建provider

        UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration);

        //構建Netty的MarshallingDecoder對象,倆個參數分別爲provider和單個消息序列化後的最大長度

        MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024 * 1024 * 1);

        return decoder;

    }

 

    /**

     * 創建Jboss Marshalling編碼器MarshallingEncoder

     * @return MarshallingEncoder

     */

    public static MarshallingEncoder buildMarshallingEncoder()

    {

        final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial");

        final MarshallingConfiguration configuration = new MarshallingConfiguration();

        configuration.setVersion(5);

        MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, configuration);

        //構建Netty的MarshallingEncoder對象,MarshallingEncoder用於實現序列化接口的POJO對象序列化爲二進制數組

        MarshallingEncoder encoder = new MarshallingEncoder(provider);

        return encoder;

    }

    

}

 

 

10 創建啓動類,查看運行效果

Dubbo客戶端工具類:DubboClientUtil

生成並獲取單例的Dubbo客戶端實例

 

生產者ProviderApplication:

註冊服務到Zookeeper註冊中心,初始化並啓動Dubbo服務器

 

package com.tcf.netty.zookeeper.dubbo.core;

 

import com.tcf.netty.zookeeper.dubbo.server.core.DubboServer;

import com.tcf.netty.zookeeper.dubbo.user.service.impl.UserServiceImpl;

 

/***

 * TODO TCF 用戶服務-生產者,應用啓動類,實現服務註冊

 * @author Hasee

 *

 */

public class ProviderApplication {

 

public static void main(String[] args)

{

//TODO TCF 初始化Dubbo服務器,基於反射獲取需要註冊到Zookeeper註冊中心的服務並實現服務註冊,初始化Netty服務器(Dubbo服務器)

DubboServer dubboServer=new DubboServer("127.0.0.1");

dubboServer.start(new UserServiceImpl());

}

 

}

 

消費者ConsumerApplication:

RPC遠程調用指定服務的指定方法,獲取方法執行返回結果

 

package com.tcf.netty.zookeeper.dubbo.order.core;

 

import com.tcf.netty.zookeeper.dubbo.order.service.OrderService;

import com.tcf.netty.zookeeper.dubbo.order.service.impl.OrderServiceImpl;

 

/***

 * TODO TCF 訂單服務-消費者,應用啓動,發起遠程調用服務請求

 * @author Hasee

 *

 */

public class ConsumerApplication {

 

public static void main(String[] args)

{

OrderService orderService=new OrderServiceImpl();

String userInfo=orderService.getOrderByUserId("1");

System.out.println("UserInfo ===> "+userInfo);

}

}

 

 

maven相關依賴

<dependencies>


    <!-- - ZK客戶端工具 -->
    <dependency>
        <groupId>com.101tec</groupId>
        <artifactId>zkclient</artifactId>
        <version>0.10</version>
    </dependency>


    <dependency>

<groupId>com.tcf.netty.zookeeper.dubbo.common</groupId>
        <artifactId>netty-zookeeper-dubbo-common</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>


    <dependency>
        <groupId>io.netty</groupId>
        <artifactId>netty-all</artifactId>
        <version>4.1.42.Final</version>
    </dependency>


    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.9</version>
    </dependency>


    <dependency>
        <groupId>org.jboss.marshalling</groupId>
        <artifactId>jboss-marshalling</artifactId>
        <version>1.4.10.Final</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.marshalling</groupId>
        <artifactId>jboss-marshalling-serial</artifactId>
        <version>1.4.10.Final</version>
    </dependency>
</dependencies>

 

轉載請註明原作者

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章