netty 实现rpc框架
基本介绍
annotation:自定义注解标识接口实现类
protocol:自定义注册协议、消费协议
registry:注册中心,注册服务元数据
provider:生产端,向注册中心注册服务,提供接口实现类
conusmer:消费端,从注册中心拉取元数据,并向provider发起服务调用
Registry:自定义注解,标识接口实现类
@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Registry {
}
RegistryInfo:服务注册元数据
@Data
public class RegistryInfo implements Serializable {
private List<RegistryProtocol> registryProtocols;
}
RpcResult:远程服务调用结果
@Data
public class RpcResult implements Serializable {
private boolean hasError;
private String errorMessage;
private Object value;
}
Person
@Data
public class Person implements Serializable {
private String name;
private Integer age;
}
自定义协议
RegistryProtocol:服务注册协议
@Data
public class RegistryProtocol implements Serializable {
private String interfaceName;
private String implClassName;
private Integer providerPort;
}
ConsumerProtocol:消费协议
@Data
public class ConsumerProtocol implements Serializable {
private String interfaceName;
private String implClassName;
private String methodName;
private Class<?>[] params;
private Object[] values;
}
注册中心
RegistryVariables:存储接口对应的元数据
public class RegistryVariables {
public static final Map<String, RegistryProtocol> interfaceProviderPortMap = new HashMap<>();
public static RegistryProtocol getInterfaceProviderPortMap(String interfaceName) {
return interfaceProviderPortMap.get(interfaceName);
}
}
CustomRegistryProviderHandler:处理服务端服务注册
public class CustomRegistryProviderHandler extends SimpleChannelInboundHandler<List<RegistryProtocol>> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, List<RegistryProtocol> registryProtocols) throws Exception {
if (registryProtocols.size() != 0){
registryProtocols.forEach(item -> RegistryVariables.interfaceProviderPortMap.put(item.getInterfaceName(), item));
}
}
}
CustomRegistryConsumerHandler:处理消费端服务元数据拉取
public class CustomRegistryConsumerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
if ("fetch registry infos".equalsIgnoreCase(s)){
RegistryInfo registryInfo = new RegistryInfo();
registryInfo.setRegistryProtocols(new ArrayList<>(RegistryVariables.interfaceProviderPortMap.values()));
channelHandlerContext.channel().writeAndFlush(registryInfo);
}
}
}
RegistryServer:注册中心服务器
public class RegistryServer {
public static void startServer(int port){
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
channelPipeline.addLast(new LengthFieldPrepender(4));
channelPipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(RegistryServer.class.getClassLoader())));
channelPipeline.addLast(new ObjectEncoder());
channelPipeline.addLast(new CustomRegistryProviderHandler());
channelPipeline.addLast(new CustomRegistryConsumerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
startServer(8000);
}
}
服务端
HelloService
public interface HelloService {
Person hello(String name, Integer age);
}
HelloService2
public interface HelloService2 {
String hello();
}
HelloServiceImpl
@Registry
public class HelloServiceImpl implements HelloService{
@Override
public Person hello(String name, Integer age) {
Person person = new Person();
person.setName(name);
person.setAge(age);
return person;
}
}
HelloService2Impl
@Registry
public class HelloService2Impl implements HelloService2{
@Override
public String hello() {
return "瓜田李下";
}
}
ProviderVariables:存储接口、实现类实例
public class ProviderVariables {
public static final Integer providerServerPort = 8001;
public static Map<String, Object> instanceMap = new HashMap<>();
public static Map<String, Object> getInstanceMap() {
return instanceMap;
}
public static void putInstance(String interfaceName, Object instance){
instanceMap.put(interfaceName, instance);
}
}
CustomProviderRegistryHandler:向注册中心注册服务
public class CustomProviderRegistryHandler extends ChannelInboundHandlerAdapter {
private final static Set<String> existInterfaceNames = new HashSet<>();
private final Integer providerServerPort;
public CustomProviderRegistryHandler(Integer providerServerPort){
this.providerServerPort = providerServerPort;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.executor().scheduleAtFixedRate(()->{
Set<String> newInterfaceClassNames = new HashSet<>();
doScan("com.example.demo.rpc.provider.service", newInterfaceClassNames);
if (newInterfaceClassNames.size() != 0){
List<RegistryProtocol> registryProtocols = new ArrayList<>();
for (String item : newInterfaceClassNames){
RegistryProtocol registryProtocol = new RegistryProtocol();
try {
Class<?> implClass = Class.forName(item);
registryProtocol.setInterfaceName((implClass.getInterfaces()[0]).getName());
registryProtocol.setProviderPort(providerServerPort);
registryProtocol.setImplClassName(item);
registryProtocols.add(registryProtocol);
}catch (Exception e){
e.printStackTrace();
}
}
ctx.channel().writeAndFlush(registryProtocols);
}
},0,10, TimeUnit.SECONDS);
}
private void doScan(String path, Set<String> newInterfaceClassNames){
File file = new File(ProviderRegistryClient.class.getClassLoader().getResource(path.replaceAll("\\.","/")).getPath());
for (File item : Objects.requireNonNull(file.listFiles())){
if (item.isDirectory()){
doScan(path+item.getName(), newInterfaceClassNames);
}else {
String fileName = path+"."+item.getName();
String className = fileName.substring(0,fileName.indexOf(".class"));
try {
Class<?> providerClass = Class.forName(className);
if (providerClass.isAnnotationPresent(Registry.class)){
if (!existInterfaceNames.contains(className)){
newInterfaceClassNames.add(className);
existInterfaceNames.add(className);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
CustomProviderConsumerHandler:处理消费端的远程调用
public class CustomProviderConsumerHandler extends SimpleChannelInboundHandler<ConsumerProtocol> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, ConsumerProtocol consumerProtocol) throws Exception {
System.out.println("收到客户端请求信息:"+consumerProtocol);
RpcResult result = new RpcResult();
String interfaceName = consumerProtocol.getInterfaceName();
String implClassName = consumerProtocol.getImplClassName();
Class<?>[] params = consumerProtocol.getParams();
Object[] values = consumerProtocol.getValues();
Object instance = null;
System.out.println(ProviderVariables.getInstanceMap());
if (ProviderVariables.getInstanceMap().containsKey(interfaceName)){
instance = ProviderVariables.getInstanceMap().get(interfaceName);
}else {
try {
instance = Class.forName(implClassName).newInstance();
ProviderVariables.getInstanceMap().put(interfaceName,instance);
}catch (Exception e){
e.printStackTrace();
}
}
if (instance != null){
Method method = instance.getClass().getMethod(consumerProtocol.getMethodName(), params);
try {
result.setValue(method.invoke(instance, values));
}catch (Exception e){
result.setHasError(true);
result.setErrorMessage(e.getMessage());
}
}
System.out.println(result);
channelHandlerContext.channel().writeAndFlush(result);
}
}
ProviderRegistryClient:服务注册客户端
public class ProviderRegistryClient {
public static void provide(String host, int port){
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(new LengthFieldPrepender(4));
channelPipeline.addLast(new ObjectEncoder());
channelPipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
channelPipeline.addLast(new CustomProviderRegistryHandler(ProviderVariables.providerServerPort));
}
});
ChannelFuture channelFuture = bootstrap.connect(host,port).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
eventLoopGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
String host = "localhost";
int port = 8000;
provide(host, port);
}
}
ProviderConsumerServer:服务端处理消费端请求的服务器
public class ProviderConsumerServer {
public static void startServer(int port){
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0,4,0,4));
channelPipeline.addLast(new LengthFieldPrepender(4));
channelPipeline.addLast(new ObjectEncoder());
channelPipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(ProviderConsumerServer.class.getClassLoader())));
channelPipeline.addLast(new CustomProviderConsumerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
startServer(ProviderVariables.providerServerPort);
}
}
消费端
ConsumerVariables:存储注册中心拉取的元数据
public class ConsumerVariables {
public static final Set<RegistryProtocol> registryProtocolSet = new HashSet<>();
public static void addRegistryProtocols(Collection<RegistryProtocol> registryProtocols){
registryProtocolSet.addAll(registryProtocols);
}
public static Set<RegistryProtocol> getRegistryProtocolSet(){
return registryProtocolSet;
}
}
RpcProxy:创建代理服务
public class RpcProxy {
@SuppressWarnings("all")
public static <T> T createProxy(Class<?> clz){
return (T)Proxy.newProxyInstance(RpcProxy.class.getClassLoader(),
new Class[]{clz},new InterfaceProxy(clz));
}
}
InterfaceProxy:拉取元数据、执行远程调用
public class InterfaceProxy implements InvocationHandler {
private final Class<?> clz;
public InterfaceProxy(Class<?> clz) {
this.clz = clz;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
boolean fetch = true;
for (RegistryProtocol protocol : ConsumerVariables.getRegistryProtocolSet()){
if (protocol.getInterfaceName().equalsIgnoreCase(clz.getName())) {
fetch = false;
break;
}
}
if (fetch){
System.out.println("开始拉取注册信息");
fetchInfos();
System.out.println(ConsumerVariables.getRegistryProtocolSet());
}
RpcResult result = getResult(method, args);
if (result.isHasError()){
throw new RuntimeException(result.getErrorMessage());
}
return result.getValue();
}
private void fetchInfos(){
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
channelPipeline.addLast(new LengthFieldPrepender(4));
channelPipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(InterfaceProxy.class.getClassLoader())));
channelPipeline.addLast(new ObjectEncoder());
channelPipeline.addLast(new CustomConsumerInfosHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect("localhost",8000).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
eventLoopGroup.shutdownGracefully();
}
}
private RpcResult getResult(Method method, Object[] args){
int port=0;
ConsumerProtocol protocol = new ConsumerProtocol();
protocol.setInterfaceName(clz.getName());
protocol.setMethodName(method.getName());
protocol.setParams(method.getParameterTypes());
protocol.setValues(args);
for (RegistryProtocol item : ConsumerVariables.getRegistryProtocolSet()){
if (item.getInterfaceName().equalsIgnoreCase(clz.getName())){
System.out.println(item);
port = item.getProviderPort();
protocol.setImplClassName(item.getImplClassName());
}
}
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
CustomConsumerResultHandler customConsumerResultHandler = new CustomConsumerResultHandler();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
channelPipeline.addLast(new LengthFieldPrepender(4));
channelPipeline.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(InterfaceProxy.class.getClassLoader())));
channelPipeline.addLast(new ObjectEncoder());
channelPipeline.addLast(customConsumerResultHandler);
}
});
ChannelFuture channelFuture = bootstrap.connect("localhost",port).sync();
channelFuture.channel().writeAndFlush(protocol);
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
eventLoopGroup.shutdownGracefully();
}
return customConsumerResultHandler.getResult();
}
}
CustomConsumerInfosHandler:拉取元数据
public class CustomConsumerInfosHandler extends SimpleChannelInboundHandler<RegistryInfo> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.channel().writeAndFlush("fetch registry infos");
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, RegistryInfo registryInfo) throws Exception {
ConsumerVariables.addRegistryProtocols(registryInfo.getRegistryProtocols());
channelHandlerContext.channel().close();
}
}
CustomConsumerResultHandler:执行远程调用
public class CustomConsumerResultHandler extends SimpleChannelInboundHandler<RpcResult> {
private RpcResult result;
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcResult rpcResult) throws Exception {
System.out.println("rpcResult:"+rpcResult);
result = rpcResult;
channelHandlerContext.channel().close();
}
public RpcResult getResult(){
return result;
}
}
Test:消费端发起远程调用
public class Test {
public static void main(String[] args) {
HelloService helloService = RpcProxy.createProxy(HelloService.class);
System.out.println(helloService.hello("瓜田李下",20));
HelloService2 helloService2 = RpcProxy.createProxy(HelloService2.class);
System.out.println(helloService2.hello());
}
}
使用测试
依次启动注册中心、服务端、消费端,test控制台输出:
# helloService.hello("瓜田李下",20)
RpcResult(hasError=false, errorMessage=null, value=Person(name=瓜田李下, age=20))
Person(name=瓜田李下, age=20)
# helloService2.hello()
rpcResult:RpcResult(hasError=false, errorMessage=null, value=瓜田李下)
RpcResult(hasError=false, errorMessage=null, value=瓜田李下)
瓜田李下