自定义基于netty的rpc框架(2)---服务端的实现
来源:互联网 发布:淘宝网背带裤女装 编辑:程序博客网 时间:2024/05/17 07:05
如(1)所介绍的下面我们来进行服务器端的实现:
1、服务器端
1.1、rpc-server-demo服务端框架的实现
cn.tianjun.rpc.server.RpcService
package cn.tianjun.rpc.server;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import org.springframework.stereotype.Component;/** * RPC 请求注解(标注在服务实现类上) */@Target({ ElementType.TYPE })//注解用在接口上@Retention(RetentionPolicy.RUNTIME)//VM将在运行期也保留注释,因此可以通过过反射机制读取注解的信息@Componentpublic @interface RpcService { Class<?> value();}
cn.tianjun.rpc.server.RpcServer
package cn.tianjun.rpc.server;import cn.tianjun.rpc.utils.RpcDecoder;import cn.tianjun.rpc.utils.RpcEncoder;import cn.tianjun.rpc.utils.RpcRequest;import cn.tianjun.rpc.utils.RpcResponse;import cn.tianjun.zk.ServiceRegistry;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import java.util.HashMap;import java.util.Map;import org.apache.commons.collections4.MapUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.BeansException;import org.springframework.beans.factory.InitializingBean;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;/** * 框架的RPC 服务器(用于将用户系统的业务类发布为 RPC 服务) * 使用时可由用户通过spring-bean的方式注入到用户的业务系统中 * 由于本类实现了ApplicationContextAware InitializingBean * spring构造本对象时会调用setApplicationContext()方法,从而可以在方法中通过自定义注解获得用户的业务接口和实现 * 还会调用afterPropertiesSet()方法,在方法中启动netty服务器 * */public class RpcServer implements ApplicationContextAware, InitializingBean { private static final Logger LOGGER = LoggerFactory .getLogger(RpcServer.class); private String serverAddress; private ServiceRegistry serviceRegistry; //用于存储业务接口和实现类的实例对象(由spring所构造) private Map<String, Object> handlerMap = new HashMap<String, Object>(); public RpcServer(String serverAddress) { this.serverAddress = serverAddress; } //服务器绑定的地址和端口由spring在构造本类时从配置文件中传入 public RpcServer(String serverAddress, ServiceRegistry serviceRegistry) { this.serverAddress = serverAddress; //用于向zookeeper注册名称服务的工具类 this.serviceRegistry = serviceRegistry; } /** * 通过注解,获取标注了rpc服务注解的业务类的----接口及impl对象,将它放到handlerMap中 */ public void setApplicationContext(ApplicationContext ctx) throws BeansException { Map<String, Object> serviceBeanMap = ctx .getBeansWithAnnotation(RpcService.class); if (MapUtils.isNotEmpty(serviceBeanMap)) { for (Object serviceBean : serviceBeanMap.values()) { //从业务实现类上的自定义注解中获取到value,从来获取到业务接口的全名 String interfaceName = serviceBean.getClass() .getAnnotation(RpcService.class).value().getName(); handlerMap.put(interfaceName, serviceBean); } } } /** * 在此启动netty服务,绑定handle流水线: * 1、接收请求数据进行反序列化得到request对象 * 2、根据request中的参数,让RpcHandler从handlerMap中找到对应的业务imple,调用指定方法,获取返回结果 * 3、将业务调用结果封装到response并序列化后发往客户端 * */ public void afterPropertiesSet() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap .group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel channel) throws Exception { channel.pipeline() .addLast(new RpcDecoder(RpcRequest.class))// 注册解码 IN-1 .addLast(new RpcEncoder(RpcResponse.class))// 注册编码 OUT .addLast(new RpcHandler(handlerMap));//注册RpcHandler IN-2 } }).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); String[] array = serverAddress.split(":"); String host = array[0]; int port = Integer.parseInt(array[1]); ChannelFuture future = bootstrap.bind(host, port).sync(); LOGGER.debug("server started on port {}", port); if (serviceRegistry != null) { serviceRegistry.register(serverAddress); } future.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } }}
cn.tianjun.rpc.server.RpcHandler
package cn.tianjun.rpc.server;import cn.tianjun.rpc.utils.RpcRequest;import cn.tianjun.rpc.utils.RpcResponse;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.lang.reflect.Method;import java.util.Map;/** * 处理具体的业务调用 * 通过构造时传入的“业务接口及实现”handlerMap,来调用客户端所请求的业务方法 * 并将业务方法返回值封装成response对象写入下一个handler(即编码handler——RpcEncoder) * Created by Administrator on 2016/12/26 0026. */public class RpcHandler extends SimpleChannelInboundHandler<RpcRequest> { private static final Logger LOGGER = LoggerFactory .getLogger(RpcHandler.class); private final Map<String, Object> handlerMap; public RpcHandler(Map<String, Object> handlerMap) { this.handlerMap = handlerMap; } /** * 接收消息,处理消息,返回结果 */ @Override public void channelRead0(final ChannelHandlerContext ctx, RpcRequest request) throws Exception { RpcResponse response = new RpcResponse(); response.setRequestId(request.getRequestId()); try { //根据request来处理具体的业务调用 Object result = handle(request); response.setResult(result); } catch (Throwable t) { response.setError(t); } //写入 outbundle(即RpcEncoder)进行下一步处理(即编码)后发送到channel中给客户端 ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } /** * 根据request来处理具体的业务调用 * 调用是通过反射的方式来完成 * * @param request * @return * @throws Throwable */ private Object handle(RpcRequest request) throws Throwable { String className = request.getClassName(); //拿到实现类对象 Object serviceBean = handlerMap.get(className); //拿到要调用的方法名、参数类型、参数值 String methodName = request.getMethodName(); Class<?>[] parameterTypes = request.getParameterTypes(); Object[] parameters = request.getParameters(); //拿到接口类 Class<?> forName = Class.forName(className); //调用实现类对象的指定方法并返回结果 Method method = forName.getMethod(methodName, parameterTypes); return method.invoke(serviceBean, parameters); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { LOGGER.error("server caught exception", cause); ctx.close(); }}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <artifactId>rpc.demo</artifactId> <groupId>tj.cmcc.org</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>rpc-server</artifactId> <packaging>jar</packaging> <name>rpc-server Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <!-- SLF4J --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <!-- Apache Commons Collections --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> </dependency> <!-- CGLib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> </dependency> <!--rpc module--> <dependency> <groupId>${project.groupId}</groupId> <artifactId>rpc-utils</artifactId> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>rpc-zk</artifactId> </dependency> </dependencies> <build> <finalName>rpc-server</finalName> </build></project>
1.2、rpc-server-impl-demo服务器端业务的实现
log4j.properties:
log4j.rootLogger=ERROR,consolelog4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.target=System.outlog4j.appender.console.layout=org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=%m%nlog4j.logger.com.xxx.rpc=DEBUG
rpc.properties:
# zookeeper serverregistry.address=mini04:2181,mini05:2181,mini06:2181# rpc serverserver.address=localhost:8000
spring.xml:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="cn.tianjun.rpcServerImpl"/> <context:property-placeholder location="classpath:rpc.properties"/> <bean id="serviceRegistry" class="cn.tianjun.zk.ServiceRegistry"> <constructor-arg name="registryAddress" value="${registry.address}"/> </bean> <bean id="rpcServer" class="cn.tianjun.rpc.server.RpcServer"> <constructor-arg name="serverAddress" value="${server.address}"/> <constructor-arg name="serviceRegistry" ref="serviceRegistry"/> </bean></beans>
cn.tianjun.rpcServerImpl.HelloServiceImpl
package cn.tianjun.rpcServerImpl;import cn.tianjun.rpc.protocol.HelloService;import cn.tianjun.rpc.protocol.Person;import cn.tianjun.rpc.server.RpcService;@RpcService(HelloService.class)public class HelloServiceImpl implements HelloService { public String hello(String name) { System.out.println("已经调用服务端接口实现,业务处理结果为:"); System.out.println("Hello! " + name); return "入门! " + name; } public String hello(Person person) { System.out.println("已经调用服务端接口实现,业务处理为:"); System.out.println("Hello! " + person.getFirstName() + " " + person.getLastName()); return "我靠! " + person.getFirstName() + " " + person.getLastName(); }}
cn.tianjun.rpcServerImpl.RpcBootstrap
package cn.tianjun.rpcServerImpl;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * 用户系统服务端的启动入口 * 其意义是启动springcontext,从而构造框架中的RpcServer * 亦即:将用户系统中所有标注了RpcService注解的业务发布到RpcServer中 * */public class RpcBootstrap { public static void main(String[] args) { new ClassPathXmlApplicationContext("spring.xml"); }}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <artifactId>rpc.demo</artifactId> <groupId>tj.cmcc.org</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>rpc-server-impl</artifactId> <packaging>jar</packaging> <name>rpc-server-impl Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <!-- JUnit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <!--rpc modules--> <dependency> <groupId>tj.cmcc.org</groupId> <artifactId>rpc-server</artifactId> </dependency> <dependency> <groupId>tj.cmcc.org</groupId> <artifactId>rpc-protocol</artifactId> </dependency> <dependency> <groupId>tj.cmcc.org</groupId> <artifactId>rpc-zk</artifactId> </dependency> </dependencies> <build> <finalName>rpc-server-impl</finalName> </build></project>
0 1
- 自定义基于netty的rpc框架(2)---服务端的实现
- 基于Netty的RPC简单框架实现(二):RPC服务端
- 自定义基于netty的rpc框架(1)
- 自定义基于netty的rpc框架(3)---客户端的实现
- 自定义基于netty的rpc框架(4)---zk和utils以及protocol的实现
- 基于netty的rpc框架
- 基于Netty的RPC简单框架实现(四):Netty实现网络传输
- 基于Netty的RPC简单框架实现(一):RPC客户端
- 基于hessian和netty的RPC框架设计和实现
- 基于hessian和netty的RPC框架设计和实现
- 基于netty框架实现的TCP服务端程序
- 基于Netty的分布式 RPC 框架
- 基于Netty的RPC简单框架实现(三):Kryo实现序列化
- 基于Netty的RPC简单框架实现(五):功能测试与性能测试
- netty实现高性能的rpc框架
- 基于Netty和Zookeeper实现RPC框架
- 基于Netty的高性能JAVA的RPC框架
- Netty+Zookeeper实现一个类似Dubbo的RPC框架
- linux和STL 常用头文件及说明
- 新导入项目页面飘红线 报错
- Dropbox OAuth2.0 help for java
- component Intent App之间传值(一) 了解
- 理解interrupt()方法
- 自定义基于netty的rpc框架(2)---服务端的实现
- 带参触发器简单例子测试
- Java经典实例
- RTP协议应用方案
- Git参考文档(转载地址)
- kubernetes/dashboard源码分析
- php 函数运用举例
- 初涉struts2
- mysql如何设置数据库编码为utf-8