Browse Source

手写RPC,手写Tomcat

huanghuijie 4 years ago
commit
50b8549059
90 changed files with 2746 additions and 0 deletions
  1. 21 0
      netty-tomcat/pom.xml
  2. 140 0
      netty-tomcat/src/main/java/cn/hhj/GPTomcat.java
  3. 44 0
      netty-tomcat/src/main/java/cn/hhj/http/GPRequest.java
  4. 46 0
      netty-tomcat/src/main/java/cn/hhj/http/GPResponse.java
  5. 19 0
      netty-tomcat/src/main/java/cn/hhj/http/GPServlet.java
  6. 18 0
      netty-tomcat/src/main/java/cn/hhj/servlet/FirstServlet.java
  7. 17 0
      netty-tomcat/src/main/java/cn/hhj/servlet/SecondServlet.java
  8. 5 0
      netty-tomcat/src/main/resources/web.properties
  9. 53 0
      pom.xml
  10. 15 0
      rpc-api-v2/pom.xml
  11. 13 0
      rpc-api-v2/src/main/java/cn.hhj/App.java
  12. 20 0
      rpc-api-v2/src/main/java/cn.hhj/IHelloService.java
  13. 5 0
      rpc-api-v2/src/main/java/cn.hhj/IPaymentService.java
  14. 49 0
      rpc-api-v2/src/main/java/cn.hhj/RpcRequest.java
  15. 37 0
      rpc-api-v2/src/main/java/cn.hhj/User.java
  16. 14 0
      rpc-api/pom.xml
  17. 2 0
      rpc-api/rpcapi.iml
  18. 16 0
      rpc-api/src/main/java/cn.hhj/annotation/RpcService.java
  19. 5 0
      rpc-api/src/main/java/cn.hhj/config/ZkConfig.java
  20. 6 0
      rpc-api/src/main/java/cn.hhj/constant/Constant.java
  21. 52 0
      rpc-api/src/main/java/cn.hhj/request/RpcRequest.java
  22. 9 0
      rpc-api/src/main/java/cn.hhj/service/IHelloService.java
  23. 5 0
      rpc-api/src/main/java/cn.hhj/service/IPaymentService.java
  24. 6 0
      rpc-api/src/main/java/cn.hhj/version/Version.java
  25. 25 0
      rpc-api/src/main/java/cn.hhj/vo/User.java
  26. 21 0
      rpc-client-v3/pom.xml
  27. 2 0
      rpc-client-v3/rpcclientv3.iml
  28. 21 0
      rpc-client-v3/src/main/java/cn/hhj/RpcClientStart.java
  29. 20 0
      rpc-client-v3/src/main/java/cn/hhj/balance/AbstractLoadBalance.java
  30. 7 0
      rpc-client-v3/src/main/java/cn/hhj/balance/LoadBalanceStrategy.java
  31. 14 0
      rpc-client-v3/src/main/java/cn/hhj/balance/RandomLoadBalance.java
  32. 18 0
      rpc-client-v3/src/main/java/cn/hhj/config/SpringConfig.java
  33. 8 0
      rpc-client-v3/src/main/java/cn/hhj/disovery/IServiceDiscovery.java
  34. 53 0
      rpc-client-v3/src/main/java/cn/hhj/disovery/impl/ServiceDiscoveryWithZk.java
  35. 15 0
      rpc-client-v3/src/main/java/cn/hhj/proxy/RpcProxyClient.java
  36. 41 0
      rpc-client-v3/src/main/java/cn/hhj/proxy/remote/RemoteInvocationHandler.java
  37. 73 0
      rpc-client-v3/src/main/java/cn/hhj/rpcsend/RpcNetTransport.java
  38. 23 0
      rpc-client/pom.xml
  39. 2 0
      rpc-client/rpcclient.iml
  40. 17 0
      rpc-client/src/main/java/cn/hhj/RpcClientStart.java
  41. 18 0
      rpc-client/src/main/java/cn/hhj/config/SpringConfig.java
  42. 19 0
      rpc-client/src/main/java/cn/hhj/proxy/RpcProxyClient.java
  43. 22 0
      rpc-client/src/main/java/cn/hhj/proxy/remote/RemoteInvocationHandler.java
  44. 19 0
      rpc-client/src/main/java/cn/hhj/rpcsend/RpcNetTransport.java
  45. 21 0
      rpc-server-v2/pom.xml
  46. 2 0
      rpc-server-v2/rpcserverv2.iml
  47. 12 0
      rpc-server-v2/src/main/java/cn/hhj/RpcServerStart.java
  48. 16 0
      rpc-server-v2/src/main/java/cn/hhj/config/SpringConfig.java
  49. 63 0
      rpc-server-v2/src/main/java/cn/hhj/handler/ProcessorHandler.java
  50. 46 0
      rpc-server-v2/src/main/java/cn/hhj/server/RpcServer.java
  51. 20 0
      rpc-server-v2/src/main/java/cn/hhj/service/HelloServiceImpl.java
  52. 21 0
      rpc-server-v3/pom.xml
  53. 12 0
      rpc-server-v3/src/main/java/cn/hhj/RpcServerStart.java
  54. 17 0
      rpc-server-v3/src/main/java/cn/hhj/config/SpringConfig.java
  55. 48 0
      rpc-server-v3/src/main/java/cn/hhj/handler/ProcessorHandler.java
  56. 9 0
      rpc-server-v3/src/main/java/cn/hhj/regiest/IRegistryCenter.java
  57. 35 0
      rpc-server-v3/src/main/java/cn/hhj/regiest/RegistryCenterWithZk.java
  58. 90 0
      rpc-server-v3/src/main/java/cn/hhj/server/RpcServer.java
  59. 21 0
      rpc-server-v3/src/main/java/cn/hhj/service/HelloServiceImpl.java
  60. 21 0
      rpc-server/pom.xml
  61. 13 0
      rpc-server/src/main/java/cn/hhj/RpcServerStart.java
  62. 47 0
      rpc-server/src/main/java/cn/hhj/handler/ProcessorHandler.java
  63. 25 0
      rpc-server/src/main/java/cn/hhj/proxy/RpcProxyServer.java
  64. 17 0
      rpc-server/src/main/java/cn/hhj/service/HelloServiceImpl.java
  65. 15 0
      rpc-tomcatv1/pom.xml
  66. 2 0
      rpc-tomcatv1/rpctomcatv1.iml
  67. 61 0
      rpc-tomcatv1/src/main/java/cn/hhj/aio/AIOClient.java
  68. 83 0
      rpc-tomcatv1/src/main/java/cn/hhj/aio/AIOServer.java
  69. 34 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/BIOClient.java
  70. 61 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/BIOServer.java
  71. 73 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/Tomcat.java
  72. 6 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/constant/ConstantParam.java
  73. 32 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/http/Request.java
  74. 18 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/http/Response.java
  75. 13 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/http/Servlet.java
  76. 16 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/servlet/FirstServlet.java
  77. 18 0
      rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/servlet/SecondServlet.java
  78. 128 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/NIOServerDemo.java
  79. 55 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/BufferDemo.java
  80. 35 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/BufferSlice.java
  81. 17 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/BufferWrap.java
  82. 44 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/DirectBuffer.java
  83. 24 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/IntBufferDemo.java
  84. 26 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/MappedBuffer.java
  85. 33 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/ReadOnlyBuffer.java
  86. 30 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/channel/FileInputDemo.java
  87. 26 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/channel/FileOutputDemo.java
  88. 117 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/chat/NIOChatClient.java
  89. 163 0
      rpc-tomcatv1/src/main/java/cn/hhj/nio/chat/NIOChatServer.java
  90. 5 0
      rpc-tomcatv1/src/main/resources/web.properties

+ 21 - 0
netty-tomcat/pom.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rpc-tomcat</artifactId>
+    <dependencies>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-all</artifactId>
+            <version>4.1.6.Final</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 140 - 0
netty-tomcat/src/main/java/cn/hhj/GPTomcat.java

@@ -0,0 +1,140 @@
+package cn.hhj;
+
+
+import cn.hhj.http.GPRequest;
+import cn.hhj.http.GPResponse;
+import cn.hhj.http.GPServlet;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+
+import java.io.FileInputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+
+//Netty就是一个同时支持多协议的网络通信框架
+public class GPTomcat {
+	//打开Tomcat源码,全局搜索ServerSocket
+
+	private int port = 8080;
+
+	private Map<String, GPServlet> servletMapping = new HashMap<String,GPServlet>();
+
+	private Properties webxml = new Properties();
+
+	private void init(){
+
+		//加载web.xml文件,同时初始化 ServletMapping对象
+		try{
+			String WEB_INF = this.getClass().getResource("/").getPath();
+			FileInputStream fis = new FileInputStream(WEB_INF + "web.properties");
+
+			webxml.load(fis);
+
+			for (Object k : webxml.keySet()) {
+
+				String key = k.toString();
+				if(key.endsWith(".url")){
+					String servletName = key.replaceAll("\\.url$", "");
+					String url = webxml.getProperty(key);
+					String className = webxml.getProperty(servletName + ".className");
+					GPServlet obj = (GPServlet)Class.forName(className).newInstance();
+					servletMapping.put(url, obj);
+				}
+			}
+
+		}catch(Exception e){
+			e.printStackTrace();
+		}
+	}
+
+	public void start(){
+		init();
+
+		//Netty封装了NIO,Reactor模型,Boss,worker
+		// Boss线程
+		EventLoopGroup bossGroup = new NioEventLoopGroup();
+		// Worker线程
+		EventLoopGroup workerGroup = new NioEventLoopGroup();
+		try {
+			// Netty服务
+			//ServetBootstrap   ServerSocketChannel
+			ServerBootstrap server = new ServerBootstrap();
+			// 链路式编程
+			server.group(bossGroup, workerGroup)
+					// 主线程处理类,看到这样的写法,底层就是用反射
+					.channel(NioServerSocketChannel.class)
+					// 子线程处理类 , Handler
+					.childHandler(new ChannelInitializer<SocketChannel>() {
+						// 客户端初始化处理
+						protected void initChannel(SocketChannel client) throws Exception {
+							// 无锁化串行编程
+							//Netty对HTTP协议的封装,顺序有要求
+							// HttpResponseEncoder 编码器
+							client.pipeline().addLast(new HttpResponseEncoder());
+							// HttpRequestDecoder 解码器
+							client.pipeline().addLast(new HttpRequestDecoder());
+							// 业务逻辑处理
+							client.pipeline().addLast(new GPTomcatHandler());
+						}
+
+					})
+					// 针对主线程的配置 分配线程最大数量 128
+					.option(ChannelOption.SO_BACKLOG, 128)
+					// 针对子线程的配置 保持长连接
+					.childOption(ChannelOption.SO_KEEPALIVE, true);
+
+			// 启动服务器
+			ChannelFuture f = server.bind(port).sync();
+			System.out.println("GP Tomcat 已启动,监听的端口是:" + port);
+			f.channel().closeFuture().sync();
+		}catch (Exception e){
+			e.printStackTrace();
+		}finally {
+			// 关闭线程池
+			bossGroup.shutdownGracefully();
+			workerGroup.shutdownGracefully();
+		}
+	}
+
+	public class GPTomcatHandler extends ChannelInboundHandlerAdapter {
+		@Override
+		public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+			if (msg instanceof HttpRequest){
+				HttpRequest req = (HttpRequest) msg;
+
+				// 转交给我们自己的request实现
+				GPRequest request = new GPRequest(ctx,req);
+				// 转交给我们自己的response实现
+				GPResponse response = new GPResponse(ctx,req);
+				// 实际业务处理
+				String url = request.getUrl();
+
+				if(servletMapping.containsKey(url)){
+					servletMapping.get(url).service(request, response);
+				}else{
+					response.write("404 - Not Found");
+				}
+
+			}
+		}
+
+		@Override
+		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+
+		}
+
+	}
+
+	public static void main(String[] args) {
+		new GPTomcat().start();
+	}
+
+}

+ 44 - 0
netty-tomcat/src/main/java/cn/hhj/http/GPRequest.java

@@ -0,0 +1,44 @@
+package cn.hhj.http;
+
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.QueryStringDecoder;
+
+import java.util.List;
+import java.util.Map;
+
+public class GPRequest {
+
+	private ChannelHandlerContext ctx;
+
+	private HttpRequest req;
+
+	public GPRequest(ChannelHandlerContext ctx, HttpRequest req) {
+		this.ctx = ctx;
+		this.req = req;
+	}
+
+	public String getUrl() {
+		return req.uri();
+	}
+
+	public String getMethod() {
+		return req.method().name();
+	}
+
+	public Map<String, List<String>> getParameters() {
+		QueryStringDecoder decoder = new QueryStringDecoder(req.uri());
+		return decoder.parameters();
+	}
+
+	public String getParameter(String name) {
+		Map<String, List<String>> params = getParameters();
+		List<String> param = params.get(name);
+		if (null == param) {
+			return null;
+		} else {
+			return param.get(0);
+		}
+	}
+}

+ 46 - 0
netty-tomcat/src/main/java/cn/hhj/http/GPResponse.java

@@ -0,0 +1,46 @@
+package cn.hhj.http;
+
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.http.*;
+
+
+public class GPResponse {
+
+	//SocketChannel的封装
+	private ChannelHandlerContext ctx;
+
+	private HttpRequest req;
+
+	public GPResponse(ChannelHandlerContext ctx, HttpRequest req) {
+		this.ctx = ctx;
+		this.req = req;
+	}
+
+	public void write(String out) throws Exception {
+		try {
+			if (out == null || out.length() == 0) {
+				return;
+			}
+			// 设置 http协议及请求头信息
+			FullHttpResponse response = new DefaultFullHttpResponse(
+				// 设置http版本为1.1
+				HttpVersion.HTTP_1_1,
+				// 设置响应状态码
+				HttpResponseStatus.OK,
+				// 将输出值写出 编码为UTF-8
+				Unpooled.wrappedBuffer(out.getBytes("UTF-8")));
+
+			response.headers().set("Content-Type", "text/html;");
+			// 当前是否支持长连接
+//            if (HttpUtil.isKeepAlive(r)) {
+//                // 设置连接内容为长连接
+//                response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
+//            }
+			ctx.write(response);
+		} finally {
+			ctx.flush();
+			ctx.close();
+		}
+	}
+}

+ 19 - 0
netty-tomcat/src/main/java/cn/hhj/http/GPServlet.java

@@ -0,0 +1,19 @@
+package cn.hhj.http;
+
+public abstract class GPServlet {
+	
+	public void service(GPRequest request,GPResponse response) throws Exception{
+		
+		//由service方法来决定,是调用doGet或者调用doPost
+		if("GET".equalsIgnoreCase(request.getMethod())){
+			doGet(request, response);
+		}else{
+			doPost(request, response);
+		}
+
+	}
+	
+	public abstract void doGet(GPRequest request,GPResponse response) throws Exception;
+	
+	public abstract void doPost(GPRequest request,GPResponse response) throws Exception;
+}

+ 18 - 0
netty-tomcat/src/main/java/cn/hhj/servlet/FirstServlet.java

@@ -0,0 +1,18 @@
+package cn.hhj.servlet;
+
+
+import cn.hhj.http.GPRequest;
+import cn.hhj.http.GPResponse;
+import cn.hhj.http.GPServlet;
+
+public class FirstServlet extends GPServlet {
+
+	public void doGet(GPRequest request, GPResponse response) throws Exception {
+		this.doPost(request, response);
+	}
+
+	public void doPost(GPRequest request, GPResponse response) throws Exception {
+		response.write("This is First Serlvet");
+	}
+
+}

+ 17 - 0
netty-tomcat/src/main/java/cn/hhj/servlet/SecondServlet.java

@@ -0,0 +1,17 @@
+package cn.hhj.servlet;
+
+import cn.hhj.http.GPRequest;
+import cn.hhj.http.GPResponse;
+import cn.hhj.http.GPServlet;
+
+public class SecondServlet extends GPServlet {
+
+	public void doGet(GPRequest request, GPResponse response) throws Exception {
+		this.doPost(request, response);
+	}
+
+	public void doPost(GPRequest request, GPResponse response) throws Exception {
+		response.write("This is Second Serlvet");
+	}
+
+}

+ 5 - 0
netty-tomcat/src/main/resources/web.properties

@@ -0,0 +1,5 @@
+servlet.one.url=/firstServlet.do
+servlet.one.className=cn.hhj.servlet.FirstServlet
+
+servlet.two.url=/secondServlet.do
+servlet.two.className=cn.hhj.servlet.SecondServlet

+ 53 - 0
pom.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>cn.hhj</groupId>
+    <artifactId>rpc</artifactId>
+    <packaging>pom</packaging>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+    <modules>
+        <module>rpc-client</module>
+        <module>rpc-server</module>
+        <module>rpc-api</module>
+        <module>rpc-server-v2</module>
+        <module>rpc-api-v2</module>
+        <module>netty-tomcat</module>
+        <module>rpc-tomcatv1</module>
+        <module>rpc-server-v3</module>
+        <module>rpc-client-v3</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+            <version>4.3.13.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-framework</artifactId>
+            <version>4.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-recipes</artifactId>
+            <version>4.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-all</artifactId>
+            <version>4.1.20.Final</version>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 15 - 0
rpc-api-v2/pom.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rpc-api-v2</artifactId>
+
+
+</project>

+ 13 - 0
rpc-api-v2/src/main/java/cn.hhj/App.java

@@ -0,0 +1,13 @@
+package cn.hhj;
+
+/**
+ * Hello world!
+ *
+ */
+public class App 
+{
+    public static void main( String[] args )
+    {
+        System.out.println( "Hello World!" );
+    }
+}

+ 20 - 0
rpc-api-v2/src/main/java/cn.hhj/IHelloService.java

@@ -0,0 +1,20 @@
+package cn.hhj;
+
+/**
+ * 腾讯课堂搜索 咕泡学院
+ * 加群获取视频:608583947
+ * 风骚的Michael 老师
+ */
+public interface IHelloService {
+
+    //
+    String sayHello(String content);
+
+    /**
+     * 保存用户
+     * @param user
+     * @return
+     */
+    String saveUser(User user);
+
+}

+ 5 - 0
rpc-api-v2/src/main/java/cn.hhj/IPaymentService.java

@@ -0,0 +1,5 @@
+package cn.hhj;
+
+public interface IPaymentService {
+    public void doPay();
+}

+ 49 - 0
rpc-api-v2/src/main/java/cn.hhj/RpcRequest.java

@@ -0,0 +1,49 @@
+package cn.hhj;
+
+import java.io.Serializable;
+
+/**
+ * 腾讯课堂搜索 咕泡学院
+ * 加群获取视频:608583947
+ * 风骚的Michael 老师
+ */
+public class RpcRequest implements Serializable {
+
+    private String className;
+    private String methodName;
+    private Object[] parameters;
+
+    private String version;
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public Object[] getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Object[] parameters) {
+        this.parameters = parameters;
+    }
+}

+ 37 - 0
rpc-api-v2/src/main/java/cn.hhj/User.java

@@ -0,0 +1,37 @@
+package cn.hhj;
+
+/**
+ * 腾讯课堂搜索 咕泡学院
+ * 加群获取视频:608583947
+ * 风骚的Michael 老师
+ */
+public class User {
+
+    private String name;
+
+    private int age;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    @Override
+    public String toString() {
+        return "User{" +
+                "name='" + name + '\'' +
+                ", age=" + age +
+                '}';
+    }
+}

+ 14 - 0
rpc-api/pom.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>rpc-api</artifactId>
+
+
+</project>

+ 2 - 0
rpc-api/rpcapi.iml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4" />

+ 16 - 0
rpc-api/src/main/java/cn.hhj/annotation/RpcService.java

@@ -0,0 +1,16 @@
+package cn.hhj.annotation;
+
+import org.springframework.stereotype.Component;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Component
+public @interface RpcService {
+    Class<?> value();
+    String version() default "";
+}

+ 5 - 0
rpc-api/src/main/java/cn.hhj/config/ZkConfig.java

@@ -0,0 +1,5 @@
+package cn.hhj.config;
+
+public class ZkConfig {
+    public static String CONNECTION_STR="192.168.135.131:2181,192.168.13.103:2181,192.168.13.104:2181";
+}

+ 6 - 0
rpc-api/src/main/java/cn.hhj/constant/Constant.java

@@ -0,0 +1,6 @@
+package cn.hhj.constant;
+
+public class Constant {
+    public static String SERVER_HOST="localhost";
+    public static Integer SERVER_PORT=8080;
+}

+ 52 - 0
rpc-api/src/main/java/cn.hhj/request/RpcRequest.java

@@ -0,0 +1,52 @@
+package cn.hhj.request;
+
+import java.io.Serializable;
+
+
+public class RpcRequest implements Serializable {
+    private String className;
+    private String methodName;
+    private Object[] parameters;
+    private Class<?>[] paramTypes;
+    private String version;
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public Class<?>[] getParamTypes() {
+        return paramTypes;
+    }
+
+    public void setParamTypes(Class<?>[] paramTypes) {
+        this.paramTypes = paramTypes;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public Object[] getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Object[] parameters) {
+        this.parameters = parameters;
+    }
+}

+ 9 - 0
rpc-api/src/main/java/cn.hhj/service/IHelloService.java

@@ -0,0 +1,9 @@
+package cn.hhj.service;
+
+import cn.hhj.vo.User;
+
+
+public interface IHelloService {
+    String sayHello(Object content);
+    String saveUser(User user);
+}

+ 5 - 0
rpc-api/src/main/java/cn.hhj/service/IPaymentService.java

@@ -0,0 +1,5 @@
+package cn.hhj.service;
+
+public interface IPaymentService {
+    public void doPay();
+}

+ 6 - 0
rpc-api/src/main/java/cn.hhj/version/Version.java

@@ -0,0 +1,6 @@
+package cn.hhj.version;
+
+public class Version {
+    public final static String V1="V1";
+    public final static String V2="V2";
+}

+ 25 - 0
rpc-api/src/main/java/cn.hhj/vo/User.java

@@ -0,0 +1,25 @@
+package cn.hhj.vo;
+
+import java.io.Serializable;
+
+public class User implements Serializable {
+    private String name;
+    private int age;
+    public String getName() {
+        return name;
+    }
+    public void setName(String name) {
+        this.name = name;
+    }
+    public int getAge() {
+        return age;
+    }
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    @Override
+    public String toString() {
+        return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
+    }
+}

+ 21 - 0
rpc-client-v3/pom.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rpc-client-v3</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.hhj</groupId>
+            <artifactId>rpc-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 2 - 0
rpc-client-v3/rpcclientv3.iml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4" />

+ 21 - 0
rpc-client-v3/src/main/java/cn/hhj/RpcClientStart.java

@@ -0,0 +1,21 @@
+package cn.hhj;
+
+
+import cn.hhj.config.SpringConfig;
+import cn.hhj.proxy.RpcProxyClient;
+import cn.hhj.service.IHelloService;
+import cn.hhj.version.Version;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+public class RpcClientStart {
+    public static void main( String[] args ) throws InterruptedException {
+        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
+        RpcProxyClient rpcProxyClient = context.getBean(RpcProxyClient.class);
+        IHelloService iHelloService = rpcProxyClient.getClientProxy(IHelloService.class, Version.V2);
+        for (int i = 0; i < 100; i++) {
+            Thread.sleep(2000);
+            System.out.println(iHelloService.sayHello(i));
+        }
+    }
+}

+ 20 - 0
rpc-client-v3/src/main/java/cn/hhj/balance/AbstractLoadBalance.java

@@ -0,0 +1,20 @@
+package cn.hhj.balance;
+
+import java.util.List;
+
+public abstract class AbstractLoadBalance implements LoadBalanceStrategy {
+    @Override
+    public String selectHost(List<String> repos) {
+        // repos可能为空, 可能只有一个。
+        if(repos==null||repos.size()==0){
+            return null;
+        }
+        if(repos.size()==1){
+            return repos.get(0);
+        }
+        return doSelect(repos);
+    }
+
+    protected abstract String doSelect(List<String> repos);
+
+}

+ 7 - 0
rpc-client-v3/src/main/java/cn/hhj/balance/LoadBalanceStrategy.java

@@ -0,0 +1,7 @@
+package cn.hhj.balance;
+
+import java.util.List;
+
+public interface LoadBalanceStrategy {
+    String selectHost(List<String> repos);
+}

+ 14 - 0
rpc-client-v3/src/main/java/cn/hhj/balance/RandomLoadBalance.java

@@ -0,0 +1,14 @@
+package cn.hhj.balance;
+
+import java.util.List;
+import java.util.Random;
+
+public class RandomLoadBalance extends AbstractLoadBalance {
+
+    @Override
+    protected String doSelect(List<String> repos) {
+        int length=repos.size();
+        Random random=new Random(); //从repos的集合内容随机获得一个地址
+        return repos.get(random.nextInt(length));
+    }
+}

+ 18 - 0
rpc-client-v3/src/main/java/cn/hhj/config/SpringConfig.java

@@ -0,0 +1,18 @@
+package cn.hhj.config;
+
+import cn.hhj.proxy.RpcProxyClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 腾讯课堂搜索 咕泡学院
+ * 加群获取视频:608583947
+ * 风骚的Michael 老师
+ */
+@Configuration
+public class SpringConfig {
+    @Bean(name="rpcPRoxyClient")
+    public RpcProxyClient proxyClient(){
+        return new RpcProxyClient();
+    }
+}

+ 8 - 0
rpc-client-v3/src/main/java/cn/hhj/disovery/IServiceDiscovery.java

@@ -0,0 +1,8 @@
+package cn.hhj.disovery;
+
+import java.util.List;
+
+public interface IServiceDiscovery {
+    //根据服务名称返回服务地址
+    List<String> discovery(String serviceName);
+}

+ 53 - 0
rpc-client-v3/src/main/java/cn/hhj/disovery/impl/ServiceDiscoveryWithZk.java

@@ -0,0 +1,53 @@
+package cn.hhj.disovery.impl;
+
+import cn.hhj.balance.LoadBalanceStrategy;
+import cn.hhj.balance.RandomLoadBalance;
+import cn.hhj.config.ZkConfig;
+import cn.hhj.disovery.IServiceDiscovery;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ServiceDiscoveryWithZk implements IServiceDiscovery {
+    private CuratorFramework curatorFramework =null;
+    List<String> serviceRepos=new ArrayList<>(); //服务地址的本地缓存
+
+    {
+        //初始化zookeeper的连接, 会话超时时间是5s,衰减重试
+        curatorFramework = CuratorFrameworkFactory.builder().
+                connectString(ZkConfig.CONNECTION_STR).sessionTimeoutMs(5000).
+                retryPolicy(new ExponentialBackoffRetry(1000, 3)).
+                namespace("registry")
+                .build();
+        curatorFramework.start();
+    }
+
+    @Override
+    public List<String> discovery(String serviceName) {
+        String path="/"+serviceName;
+        if(serviceRepos.isEmpty()) {
+            try {
+                serviceRepos = curatorFramework.getChildren().forPath(path);
+                registryWatch(path);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        return serviceRepos;
+    }
+
+    private void registryWatch(String path) throws Exception {
+        PathChildrenCache nodeCache=new PathChildrenCache(curatorFramework,path,true);
+        PathChildrenCacheListener cacheListener=(curatorFramework1, pathChildrenCacheEvent)->{
+            System.out.println("客户端收到变更节点的事件");
+            serviceRepos=curatorFramework1.getChildren().forPath(path);
+        };
+        nodeCache.getListenable().addListener(cacheListener);
+        nodeCache.start();
+    }
+}

+ 15 - 0
rpc-client-v3/src/main/java/cn/hhj/proxy/RpcProxyClient.java

@@ -0,0 +1,15 @@
+package cn.hhj.proxy;
+
+import cn.hhj.disovery.IServiceDiscovery;
+import cn.hhj.disovery.impl.ServiceDiscoveryWithZk;
+import cn.hhj.proxy.remote.RemoteInvocationHandler;
+
+import java.lang.reflect.Proxy;
+
+public class RpcProxyClient {
+    private IServiceDiscovery serviceDiscovery=new ServiceDiscoveryWithZk();
+
+    public  <T> T getClientProxy(final Class<T> interfaceCls,String version){
+        return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(), new Class<?>[]{interfaceCls}, new RemoteInvocationHandler(serviceDiscovery,version));
+    }
+}

+ 41 - 0
rpc-client-v3/src/main/java/cn/hhj/proxy/remote/RemoteInvocationHandler.java

@@ -0,0 +1,41 @@
+package cn.hhj.proxy.remote;
+
+import cn.hhj.disovery.IServiceDiscovery;
+import cn.hhj.request.RpcRequest;
+import cn.hhj.rpcsend.RpcNetTransport;
+import org.springframework.util.StringUtils;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.List;
+
+public class RemoteInvocationHandler implements InvocationHandler {
+
+    private IServiceDiscovery serviceDiscovery;
+    private String version;
+
+    public RemoteInvocationHandler(IServiceDiscovery serviceDiscovery, String version) {
+        this.serviceDiscovery = serviceDiscovery;
+        this.version = version;
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        // 进行请求数据的包装
+        RpcRequest request=new RpcRequest();
+        request.setClassName(method.getDeclaringClass().getName());
+        request.setMethodName(method.getName());
+        request.setParamTypes(method.getParameterTypes());
+        request.setParameters(args);
+        request.setVersion(version);
+        String serviceName=request.getClassName();
+        if(!StringUtils.isEmpty(version)){
+            serviceName=serviceName+"-"+version;
+        }
+        List<String> serviceAddress=serviceDiscovery.discovery(serviceName);
+        RpcNetTransport rnt=new RpcNetTransport(serviceAddress);
+        Object result=rnt.send(request);
+        System.err.println("【client】:远程通信,需要调用的接口是:"+serviceName);
+        return result;
+    }
+}

+ 73 - 0
rpc-client-v3/src/main/java/cn/hhj/rpcsend/RpcNetTransport.java

@@ -0,0 +1,73 @@
+package cn.hhj.rpcsend;
+
+import cn.hhj.balance.LoadBalanceStrategy;
+import cn.hhj.balance.RandomLoadBalance;
+import cn.hhj.request.RpcRequest;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.serialization.ClassResolvers;
+import io.netty.handler.codec.serialization.ObjectDecoder;
+import io.netty.handler.codec.serialization.ObjectEncoder;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+
+public class RpcNetTransport extends SimpleChannelInboundHandler<Object> {
+    private List<String> serviceAddress;
+    private Object result;
+    private NioEventLoopGroup bootStrap = new NioEventLoopGroup();
+    private Bootstrap bootstrap = new Bootstrap();
+    public RpcNetTransport(List<String> serviceAddress) {
+        this.serviceAddress = serviceAddress;
+    }
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
+        this.result = msg;
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        System.out.println("客户端发送消息到服务端时产生异常");
+        ctx.close();
+    }
+
+    public Object send(RpcRequest request) {
+        bootstrap.group(bootStrap).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
+            @Override
+            protected void initChannel(SocketChannel socketChannel) throws Exception {
+                socketChannel.pipeline().
+                        addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null))).
+                        addLast(new ObjectEncoder()).
+                        addLast(RpcNetTransport.this);
+            }
+        }).option(ChannelOption.TCP_NODELAY, true);
+        connect(request);
+        return result;
+    }
+
+    private String[] getUrl() {
+        LoadBalanceStrategy loadBalanceStrategy = new RandomLoadBalance();
+        return loadBalanceStrategy.selectHost(serviceAddress).split(":");
+    }
+
+    private void connect(RpcRequest request) {
+        try{
+            String[] urls = getUrl();
+            ChannelFuture future = bootstrap.connect(urls[0], Integer.parseInt(urls[1])).sync();
+            future.addListener((ChannelFutureListener) ch -> {
+                if (!ch.isSuccess()) {
+                    ch.channel().eventLoop().schedule(() -> connect(request), 3L, TimeUnit.SECONDS);
+                }
+            });
+            future.channel().writeAndFlush(request).sync();
+            if (request != null) {
+                future.channel().closeFuture().sync();
+            }
+        }catch (Exception e){ e.printStackTrace(); }
+    }
+}

+ 23 - 0
rpc-client/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rpc-client</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.hhj</groupId>
+            <artifactId>rpc-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 2 - 0
rpc-client/rpcclient.iml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4" />

+ 17 - 0
rpc-client/src/main/java/cn/hhj/RpcClientStart.java

@@ -0,0 +1,17 @@
+package cn.hhj;
+
+
+import cn.hhj.config.SpringConfig;
+import cn.hhj.proxy.RpcProxyClient;
+import cn.hhj.service.IHelloService;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+public class RpcClientStart {
+    public static void main( String[] args ) {
+        ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
+        RpcProxyClient rpcProxyClient=context.getBean(RpcProxyClient.class);
+        IHelloService helloService=rpcProxyClient.getClientProxy(IHelloService.class);
+        System.out.println(helloService.sayHello("noSum"));
+    }
+}

+ 18 - 0
rpc-client/src/main/java/cn/hhj/config/SpringConfig.java

@@ -0,0 +1,18 @@
+package cn.hhj.config;
+
+import cn.hhj.proxy.RpcProxyClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 腾讯课堂搜索 咕泡学院
+ * 加群获取视频:608583947
+ * 风骚的Michael 老师
+ */
+@Configuration
+public class SpringConfig {
+    @Bean(name="rpcPRoxyClient")
+    public RpcProxyClient proxyClient(){
+        return new RpcProxyClient();
+    }
+}

+ 19 - 0
rpc-client/src/main/java/cn/hhj/proxy/RpcProxyClient.java

@@ -0,0 +1,19 @@
+package cn.hhj.proxy;
+
+import cn.hhj.proxy.remote.RemoteInvocationHandler;
+
+import java.lang.reflect.Proxy;
+
+public class RpcProxyClient {
+    public static  <T> T clientProxy(final Class<T> interfaceCls){
+        return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(),
+                new Class<?>[]{interfaceCls},
+                new RemoteInvocationHandler());
+    }
+
+    public  <T> T getClientProxy(final Class<T> interfaceCls){
+        return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(),
+                new Class<?>[]{interfaceCls},
+                new RemoteInvocationHandler());
+    }
+}

+ 22 - 0
rpc-client/src/main/java/cn/hhj/proxy/remote/RemoteInvocationHandler.java

@@ -0,0 +1,22 @@
+package cn.hhj.proxy.remote;
+
+import cn.hhj.request.RpcRequest;
+import cn.hhj.rpcsend.RpcNetTransport;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+public class RemoteInvocationHandler implements InvocationHandler {
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        // 进行请求数据的包装
+        RpcRequest request=new RpcRequest();
+        request.setClassName(method.getDeclaringClass().getName());
+        request.setMethodName(method.getName());
+        request.setParameters(args);
+        request.setVersion("V1.0");
+        System.err.println("【client】:远程通信,需要调用的接口是:"+request.getClassName()+"."+request.getMethodName()+"()");
+        RpcNetTransport rnt=new RpcNetTransport();
+        return rnt.send(request);
+    }
+}

+ 19 - 0
rpc-client/src/main/java/cn/hhj/rpcsend/RpcNetTransport.java

@@ -0,0 +1,19 @@
+package cn.hhj.rpcsend;
+
+import cn.hhj.constant.Constant;
+import cn.hhj.request.RpcRequest;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.Socket;
+
+public class RpcNetTransport {
+    public Object send(RpcRequest request) throws Exception {
+        Socket socket = new Socket(Constant.SERVER_HOST,Constant.SERVER_PORT);
+        ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream());
+        os.writeObject(request);
+        os.flush();
+        ObjectInputStream is = new ObjectInputStream(socket.getInputStream());
+        return is.readObject();
+    }
+}

+ 21 - 0
rpc-server-v2/pom.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rpc-server-v2</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.hhj</groupId>
+            <artifactId>rpc-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 2 - 0
rpc-server-v2/rpcserverv2.iml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4" />

+ 12 - 0
rpc-server-v2/src/main/java/cn/hhj/RpcServerStart.java

@@ -0,0 +1,12 @@
+package cn.hhj;
+
+import cn.hhj.config.SpringConfig;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+public class RpcServerStart {
+    public static void main( String[] args ){
+        ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
+        ((AnnotationConfigApplicationContext) context).start();
+    }
+}

+ 16 - 0
rpc-server-v2/src/main/java/cn/hhj/config/SpringConfig.java

@@ -0,0 +1,16 @@
+package cn.hhj.config;
+
+import cn.hhj.server.RpcServer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ComponentScan(basePackages = "cn.hhj.service")
+public class SpringConfig {
+
+    @Bean(name="rpcService")
+    public RpcServer gpRpcServer(){
+        return new RpcServer();
+    }
+}

+ 63 - 0
rpc-server-v2/src/main/java/cn/hhj/handler/ProcessorHandler.java

@@ -0,0 +1,63 @@
+package cn.hhj.handler;
+
+import cn.hhj.request.RpcRequest;
+import org.springframework.util.StringUtils;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Method;
+import java.net.Socket;
+import java.util.Map;
+
+public class ProcessorHandler implements Runnable {
+    private Socket socket;
+    private Map<String,Object> handlerMap;
+
+    public ProcessorHandler(Socket socket, Map<String,Object> handlerMap) {
+        this.socket = socket;
+        this.handlerMap =handlerMap;
+    }
+    @Override
+    public void run() {
+        ObjectInputStream is=null;
+        ObjectOutputStream os=null;
+        try{
+            is=new ObjectInputStream(socket.getInputStream());
+            RpcRequest request= (RpcRequest) is.readObject();
+            Object result=invoke(request); //反射调用本地服务
+            os=new ObjectOutputStream(socket.getOutputStream());
+            os.writeObject(result);
+            os.flush();
+        }catch (Exception e){
+            e.printStackTrace();
+        }finally {
+            try { if (is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); }
+            try { if (os!=null){ os.close(); } } catch (IOException e) { e.printStackTrace(); }
+        }
+    }
+
+    private Object invoke(RpcRequest request)throws  Exception{
+        String serviceName=request.getClassName();
+        String version=request.getVersion();
+        if (!StringUtils.isEmpty(version)){
+            serviceName+="-"+version;
+        }
+        Object service= handlerMap.get(serviceName);
+        if (service==null){
+            throw new RuntimeException("service not found"+serviceName);
+        }
+        Object[] params=request.getParameters(); // 参数列表
+        Method method=null;
+        Class clazz=Class.forName(request.getClassName());
+        if(params!=null) {
+            Class<?>[] types = new Class[params.length]; // 获得每个参数的类型
+            for (int i = 0; i < params.length; i++) {
+                types[i] = params[i].getClass();
+            }
+            method=clazz.getMethod(request.getMethodName(),types);
+        }else{
+            method=clazz.getMethod(request.getMethodName());
+        }
+        return method.invoke(service,params);
+    }
+}

+ 46 - 0
rpc-server-v2/src/main/java/cn/hhj/server/RpcServer.java

@@ -0,0 +1,46 @@
+package cn.hhj.server;
+
+import cn.hhj.annotation.RpcService;
+import cn.hhj.constant.Constant;
+import cn.hhj.handler.ProcessorHandler;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.util.StringUtils;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class RpcServer  implements ApplicationContextAware, InitializingBean {
+    ExecutorService service = Executors.newCachedThreadPool();
+    private Map<String,Object> handlerMap=new HashMap();
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        ServerSocket serverSocket=new ServerSocket(Constant.SERVER_PORT);
+        while (true){
+            Socket socket=serverSocket.accept();
+            service.execute(new ProcessorHandler(socket,handlerMap));
+        }
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        Map<String,Object> serviceBeanMap=applicationContext.getBeansWithAnnotation(RpcService.class);
+        if (!serviceBeanMap.isEmpty()){
+            for(Object serviceBean:serviceBeanMap.values()){
+                RpcService rpcService=serviceBean.getClass().getAnnotation(RpcService.class);
+                String serviceName=rpcService.value().getName();//拿到接口类定义
+                String version=rpcService.version(); //拿到版本号
+                if (!StringUtils.isEmpty(version)){
+                    serviceName+="-"+version;
+                }
+                handlerMap.put(serviceName,serviceBean);
+            }
+        }
+    }
+}

+ 20 - 0
rpc-server-v2/src/main/java/cn/hhj/service/HelloServiceImpl.java

@@ -0,0 +1,20 @@
+package cn.hhj.service;
+
+import cn.hhj.annotation.RpcService;
+import cn.hhj.vo.User;
+
+
+@RpcService(value = IHelloService.class,version = "V1.0")
+public class HelloServiceImpl implements IHelloService {
+    @Override
+    public String sayHello(Object content) {
+        System.out.println("request in sayHello:"+content);
+        return "【ECHO】:"+content;
+    }
+
+    @Override
+    public String saveUser(User user) {
+        System.out.println("request in saveUser:"+user);
+        return "SUCCESS";
+    }
+}

+ 21 - 0
rpc-server-v3/pom.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rpc-server-v3</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.hhj</groupId>
+            <artifactId>rpc-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 12 - 0
rpc-server-v3/src/main/java/cn/hhj/RpcServerStart.java

@@ -0,0 +1,12 @@
+package cn.hhj;
+
+import cn.hhj.config.SpringConfig;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+
+public class RpcServerStart {
+    public static void main( String[] args ){
+        ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
+        ((AnnotationConfigApplicationContext) context).start();
+    }
+}

+ 17 - 0
rpc-server-v3/src/main/java/cn/hhj/config/SpringConfig.java

@@ -0,0 +1,17 @@
+package cn.hhj.config;
+
+import cn.hhj.constant.Constant;
+import cn.hhj.server.RpcServer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@ComponentScan(basePackages = "cn.hhj.service")
+public class SpringConfig {
+
+    @Bean(name="rpcService")
+    public RpcServer gpRpcServer(){
+        return new RpcServer(Constant.SERVER_PORT);
+    }
+}

+ 48 - 0
rpc-server-v3/src/main/java/cn/hhj/handler/ProcessorHandler.java

@@ -0,0 +1,48 @@
+package cn.hhj.handler;
+
+import cn.hhj.request.RpcRequest;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Method;
+import java.net.Socket;
+import java.util.Map;
+
+public class ProcessorHandler extends SimpleChannelInboundHandler<RpcRequest> {
+
+    private Map<String,Object> handlerMap;
+
+    public ProcessorHandler(Map<String,Object> handlerMap) {
+        this.handlerMap =handlerMap;
+    }
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, RpcRequest msg) throws Exception {
+        Object result=invoke(msg);
+        ctx.writeAndFlush(result).addListener(ChannelFutureListener.CLOSE);
+    }
+
+    private Object invoke(RpcRequest request)throws  Exception{
+        //反射调用
+        String serviceName=request.getClassName();
+        String version=request.getVersion();
+        //增加版本号的判断
+        if(!StringUtils.isEmpty(version)){
+            serviceName+="-"+version;
+        }
+
+        Object service=handlerMap.get(serviceName);
+        if(service==null){
+            throw new RuntimeException("service not found:"+serviceName);
+        }
+        Object[] args=request.getParameters(); // 拿到客户端请求的参数
+        Class clazz=Class.forName(request.getClassName()); // 跟去请求的类进行加载
+        Method method=clazz.getMethod(request.getMethodName(),request.getParamTypes()); // sayHello, saveUser找到这个类中的方法
+        return method.invoke(service,args);// HelloServiceImpl 进行反射调用
+    }
+}

+ 9 - 0
rpc-server-v3/src/main/java/cn/hhj/regiest/IRegistryCenter.java

@@ -0,0 +1,9 @@
+package cn.hhj.regiest;
+
+public interface IRegistryCenter {
+
+    /**
+     * 服务注册名称和服务注册地址实现服务的管理
+     */
+    void registry(String serviceName, String serviceAddress);
+}

+ 35 - 0
rpc-server-v3/src/main/java/cn/hhj/regiest/RegistryCenterWithZk.java

@@ -0,0 +1,35 @@
+package cn.hhj.regiest;
+
+import cn.hhj.config.ZkConfig;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.zookeeper.CreateMode;
+
+public class RegistryCenterWithZk implements  IRegistryCenter {
+    private CuratorFramework curatorFramework = null;
+
+    {
+        //初始化zookeeper的连接, 会话超时时间是5s,衰减重试
+        curatorFramework = CuratorFrameworkFactory.builder().
+                connectString(ZkConfig.CONNECTION_STR).sessionTimeoutMs(5000).
+                retryPolicy(new ExponentialBackoffRetry(1000, 3)).
+                namespace("registry")
+                .build();
+        curatorFramework.start();
+    }
+
+    @Override
+    public void registry(String serviceName, String serviceAddress) {
+        String servicePath = "/" + serviceName;
+        try{
+            // 判断节点是否存在
+            if (curatorFramework.checkExists().forPath(servicePath)==null){
+                curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(servicePath);
+            }
+            String addressPath=servicePath+"/"+serviceAddress;
+            String result=curatorFramework.create().withMode(CreateMode.EPHEMERAL).forPath(addressPath);
+            System.out.println("服务注册成功:"+result);
+        }catch (Exception e){e.printStackTrace();}
+    }
+}

+ 90 - 0
rpc-server-v3/src/main/java/cn/hhj/server/RpcServer.java

@@ -0,0 +1,90 @@
+package cn.hhj.server;
+
+import cn.hhj.annotation.RpcService;
+import cn.hhj.handler.ProcessorHandler;
+import cn.hhj.regiest.IRegistryCenter;
+import cn.hhj.regiest.RegistryCenterWithZk;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+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 io.netty.handler.codec.serialization.ClassResolvers;
+import io.netty.handler.codec.serialization.ObjectDecoder;
+import io.netty.handler.codec.serialization.ObjectEncoder;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.util.StringUtils;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class RpcServer  implements ApplicationContextAware, InitializingBean {
+    private int port;
+    private Map<String,Object> handlerMap=new HashMap();
+    private IRegistryCenter registryCenter=new RegistryCenterWithZk();
+
+    public RpcServer(int port) {
+        this.port = port;
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        EventLoopGroup bossGroup=new NioEventLoopGroup();
+        EventLoopGroup workerGroup=new NioEventLoopGroup();
+        try{
+            ServerBootstrap serverBootstrap=new ServerBootstrap();
+            serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
+                @Override
+                protected void initChannel(SocketChannel ch) throws Exception {
+                    ChannelPipeline pipeline = ch.pipeline();
+                    pipeline.addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
+                    pipeline.addLast(new ObjectEncoder());
+                    pipeline.addLast(new ProcessorHandler(handlerMap));
+                }
+            });
+            serverBootstrap.bind(port).sync();
+        }catch (Exception e){
+            e.printStackTrace();
+        }finally { // 此处不能关闭,此服务应当持续打开
+         /*   workerGroup.shutdownGracefully();
+            bossGroup.shutdownGracefully();*/
+        }
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        Map<String,Object> serviceBeanMap=applicationContext.getBeansWithAnnotation(RpcService.class);
+        if (!serviceBeanMap.isEmpty()){
+            for(Object serviceBean:serviceBeanMap.values()){
+                RpcService rpcService=serviceBean.getClass().getAnnotation(RpcService.class);
+                String serviceName=rpcService.value().getName();//拿到接口类定义
+                String version=rpcService.version(); //拿到版本号
+                if (!StringUtils.isEmpty(version)){
+                    serviceName+="-"+version;
+                }
+                handlerMap.put(serviceName,serviceBean);
+                registryCenter.registry(serviceName,getAddress()+":"+port);
+            }
+
+        }
+    }
+
+    private static String getAddress(){
+        InetAddress inetAddress=null;
+        try {
+            inetAddress=InetAddress.getLocalHost();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        return inetAddress.getHostAddress();// 获得本机的ip地址
+    }
+}

+ 21 - 0
rpc-server-v3/src/main/java/cn/hhj/service/HelloServiceImpl.java

@@ -0,0 +1,21 @@
+package cn.hhj.service;
+
+import cn.hhj.annotation.RpcService;
+import cn.hhj.version.Version;
+import cn.hhj.vo.User;
+
+
+@RpcService(value = IHelloService.class,version = Version.V2)
+public class HelloServiceImpl implements IHelloService {
+    @Override
+    public String sayHello(Object content) {
+        System.out.println("request in sayHello:"+content);
+        return "【ECHO】:"+content;
+    }
+
+    @Override
+    public String saveUser(User user) {
+        System.out.println("request in saveUser:"+user);
+        return "SUCCESS";
+    }
+}

+ 21 - 0
rpc-server/pom.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rpc-server</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.hhj</groupId>
+            <artifactId>rpc-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+    </dependencies>
+</project>

+ 13 - 0
rpc-server/src/main/java/cn/hhj/RpcServerStart.java

@@ -0,0 +1,13 @@
+package cn.hhj;
+
+import cn.hhj.proxy.RpcProxyServer;
+import cn.hhj.service.HelloServiceImpl;
+import cn.hhj.service.IHelloService;
+
+public class RpcServerStart {
+    public static void main( String[] args ) throws Exception {
+       IHelloService helloService=new HelloServiceImpl();
+       RpcProxyServer proxyServer=new RpcProxyServer();
+       proxyServer.push(helloService);
+    }
+}

+ 47 - 0
rpc-server/src/main/java/cn/hhj/handler/ProcessorHandler.java

@@ -0,0 +1,47 @@
+package cn.hhj.handler;
+
+import cn.hhj.request.RpcRequest;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.Socket;
+
+public class ProcessorHandler implements Runnable {
+
+    private Object service;
+    private Socket socket;
+
+    public ProcessorHandler(Socket socket,Object service ) {
+        this.socket = socket;
+        this.service = service;
+    }
+
+    @Override
+    public void run() {
+        ObjectInputStream is=null;
+        ObjectOutputStream os=null;
+        try{
+            is=new ObjectInputStream(socket.getInputStream());
+            RpcRequest request= (RpcRequest) is.readObject();
+            Object result=invoke(request); //反射调用本地服务
+            os=new ObjectOutputStream(socket.getOutputStream());
+            os.writeObject(result);
+        }catch (Exception e){
+            e.printStackTrace();
+        }finally {
+            try { if (is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); }
+            try { if (os!=null){ os.close(); } } catch (IOException e) { e.printStackTrace(); }
+        }
+    }
+
+    private Object invoke(RpcRequest rpcRequest)throws  Exception{
+        Object[] params=rpcRequest.getParameters();// 请求参数
+        Class<?>[] types=new Class[params.length];//保存请求参数的类型
+        for (int i = 0; i < params.length; i++) {
+            types[i]=params[i].getClass();
+        }
+        Class clazz=Class.forName(rpcRequest.getClassName());
+        return clazz.getMethod(rpcRequest.getMethodName(),types).invoke(service,params);
+    }
+}

+ 25 - 0
rpc-server/src/main/java/cn/hhj/proxy/RpcProxyServer.java

@@ -0,0 +1,25 @@
+package cn.hhj.proxy;
+
+import cn.hhj.constant.Constant;
+import cn.hhj.handler.ProcessorHandler;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class RpcProxyServer  {
+    ExecutorService executorService=Executors.newCachedThreadPool();
+    /**
+     * @param service 要暴露的服务接口
+     */
+    public void push(Object service) throws Exception{
+        ServerSocket serverSocket=null;
+        serverSocket=new ServerSocket(Constant.SERVER_PORT);
+        while (true){// 不断接收请求
+            Socket socket=serverSocket.accept();
+            executorService.execute(new ProcessorHandler(socket,service));
+        }
+    }
+}
+

+ 17 - 0
rpc-server/src/main/java/cn/hhj/service/HelloServiceImpl.java

@@ -0,0 +1,17 @@
+package cn.hhj.service;
+
+import cn.hhj.vo.User;
+
+public class HelloServiceImpl implements IHelloService {
+    @Override
+    public String sayHello(String content) {
+        System.out.println("request in sayHello:"+content);
+        return "【ECHO】:"+content;
+    }
+
+    @Override
+    public String saveUser(User user) {
+        System.out.println("request in saveUser:"+user);
+        return "SUCCESS";
+    }
+}

+ 15 - 0
rpc-tomcatv1/pom.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>rpc</artifactId>
+        <groupId>cn.hhj</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>rpc-tomcatv1</artifactId>
+
+
+</project>

+ 2 - 0
rpc-tomcatv1/rpctomcatv1.iml

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4" />

+ 61 - 0
rpc-tomcatv1/src/main/java/cn/hhj/aio/AIOClient.java

@@ -0,0 +1,61 @@
+package cn.hhj.aio;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousSocketChannel;
+import java.nio.channels.CompletionHandler;
+
+/**
+ * AIO客户端
+ */
+public class AIOClient {
+    private final AsynchronousSocketChannel client;
+
+    public AIOClient() throws Exception{
+        client = AsynchronousSocketChannel.open();
+    }
+
+    public void connect(String host,int port)throws Exception{
+        client.connect(new InetSocketAddress(host,port),null,new CompletionHandler<Void,Void>() {
+            @Override
+            public void completed(Void result, Void attachment) {
+                try {
+                    client.write(ByteBuffer.wrap("这是一条测试数据".getBytes())).get();
+                    System.out.println("已发送至服务器");
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+            }
+
+            @Override
+            public void failed(Throwable exc, Void attachment) {
+                exc.printStackTrace();
+            }
+        });
+        final ByteBuffer bb = ByteBuffer.allocate(1024);
+        client.read(bb, null, new CompletionHandler<Integer,Object>(){
+
+                    @Override
+                    public void completed(Integer result, Object attachment) {
+                        System.out.println("IO操作完成" + result);
+                        System.out.println("获取反馈结果" + new String(bb.array()));
+                    }
+
+                    @Override
+                    public void failed(Throwable exc, Object attachment) {
+                        exc.printStackTrace();
+                    }
+                }
+        );
+
+        try {
+            Thread.sleep(Integer.MAX_VALUE);
+        } catch (InterruptedException ex) {
+            System.out.println(ex);
+        }
+
+    }
+
+    public static void main(String args[])throws Exception{
+        new AIOClient().connect("localhost",8000);
+    }
+}

+ 83 - 0
rpc-tomcatv1/src/main/java/cn/hhj/aio/AIOServer.java

@@ -0,0 +1,83 @@
+package cn.hhj.aio;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousChannelGroup;
+import java.nio.channels.AsynchronousServerSocketChannel;
+import java.nio.channels.AsynchronousSocketChannel;
+import java.nio.channels.CompletionHandler;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * AIO服务端
+ */
+public class AIOServer {
+
+    private final int port;
+
+    public static void main(String args[]) {
+        int port = 8000;
+        new AIOServer(port);
+    }
+
+    public AIOServer(int port) {
+        this.port = port;
+        listen();
+    }
+
+    private void listen() {
+        try {
+            ExecutorService executorService = Executors.newCachedThreadPool();
+            AsynchronousChannelGroup threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);
+            //开门营业
+            //工作线程,用来侦听回调的,事件响应的时候需要回调
+            final AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(threadGroup);
+            server.bind(new InetSocketAddress(port));
+            System.out.println("服务已启动,监听端口" + port);
+
+            //准备接受数据
+            server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>(){
+                final ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
+                //实现completed方法来回调
+                //由操作系统来触发
+                //回调有两个状态,成功
+                public void completed(AsynchronousSocketChannel result, Object attachment){
+                    System.out.println("IO操作成功,开始获取数据");
+                    try {
+                        buffer.clear();
+                        result.read(buffer).get();
+                        buffer.flip();
+                        result.write(buffer);
+                        buffer.flip();
+                    } catch (Exception e) {
+                        System.out.println(e.toString());
+                    } finally {
+                        try {
+                            result.close();
+                            server.accept(null, this);
+                        } catch (Exception e) {
+                            System.out.println(e.toString());
+                        }
+                    }
+
+                    System.out.println("操作完成");
+                }
+
+                @Override
+                //回调有两个状态,失败
+                public void failed(Throwable exc, Object attachment) {
+                    System.out.println("IO操作是失败: " + exc);
+                }
+            });
+
+            try {
+                Thread.sleep(Integer.MAX_VALUE);
+            } catch (InterruptedException ex) {
+                System.out.println(ex);
+            }
+        } catch (IOException e) {
+            System.out.println(e);
+        }
+    }
+}

+ 34 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/BIOClient.java

@@ -0,0 +1,34 @@
+package cn.hhj.bio;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.UUID;
+
+public class BIOClient {
+
+	public static void main(String[] args) throws UnknownHostException, IOException {
+
+		//要和谁进行通信,服务器IP、服务器的端口
+		//一台机器的端口号是有限
+		Socket client = new Socket("localhost", 8080);
+
+		//输出 O  write();
+		//不管是客户端还是服务端,都有可能write和read
+
+		OutputStream os = client.getOutputStream();
+
+		//生成一个随机的ID
+		String name = UUID.randomUUID().toString();
+
+		System.out.println("客户端发送数据:" + name);
+		//传说中的101011010
+		os.write(name.getBytes());
+		os.close();
+		client.close();
+
+		
+	}
+	
+}

+ 61 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/BIOServer.java

@@ -0,0 +1,61 @@
+package cn.hhj.bio;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+
+//同步阻塞IO模型
+public class BIOServer {
+
+	//服务端网络IO模型的封装对象
+	ServerSocket server;
+	//服务器
+	public BIOServer(int port){
+		try {
+			//Tomcat 默认端口8080
+			//只要是Java写的都这么玩,3306
+			//Redis  6379
+			//Zookeeper  2181
+			//HBase
+			//RMI
+			//TCP
+			server = new ServerSocket(port);
+			System.out.println("BIO服务已启动,监听端口是:" + port);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	/**
+	 * 开始监听,并处理逻辑
+	 * @throws IOException 
+	 */
+	public void listen() throws IOException{
+		//循环监听
+		while(true){
+			//等待客户端连接,阻塞方法
+			//Socket数据发送者在服务端的引用
+			Socket client = server.accept();
+			System.out.println(client.getPort());
+
+			//对方法数据给我了,读 Input
+			InputStream is = client.getInputStream();
+
+			//网络客户端把数据发送到网卡,机器所得到的数据读到了JVM内中
+			byte [] buff = new byte[1024];
+			int len = is.read(buff);
+			if(len > 0){
+				String msg = new String(buff,0,len);
+				System.out.println("收到" + msg);
+			}
+		}
+	}
+	
+	
+	public static void main(String[] args) throws IOException {
+		new BIOServer(8080).listen();
+	}
+	
+}

+ 73 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/Tomcat.java

@@ -0,0 +1,73 @@
+package cn.hhj.bio.tomcat;
+
+import cn.hhj.bio.tomcat.constant.ConstantParam;
+import cn.hhj.bio.tomcat.http.Request;
+import cn.hhj.bio.tomcat.http.Response;
+import cn.hhj.bio.tomcat.http.Servlet;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+public class Tomcat {
+    private ServerSocket serverSocket;
+    private Map<String, Servlet> servletMap=new HashMap<>();
+    private Properties webXml=new Properties();
+
+
+    private void init()throws Exception{
+        //加载web.properties文件,同时初始化 ServletMapping对象
+        String WEB_INF = this.getClass().getResource("/").getPath();
+        FileInputStream fis = new FileInputStream(WEB_INF + "web.properties");
+        webXml.load(fis);
+        for (Object k:webXml.keySet()) {
+             String key=k.toString();
+            if(key.endsWith(".url")){
+                String servletName=key.replaceAll("\\.url$","");
+                String url=webXml.getProperty(key);
+                String className = webXml.getProperty(servletName + ".className");
+                Servlet servlet= (Servlet) Class.forName(className).newInstance();
+                servletMap.put(url,servlet);
+            }
+        }
+    }
+
+    public void start()throws Exception{
+        // 1、加载配置文件
+        init();
+        serverSocket=new ServerSocket(ConstantParam.PORT);
+        System.err.println("Tomcat启动,端口号:"+ConstantParam.PORT);
+        //2、等待用户请求,用一个死循环来等待用户请求
+        while (true){
+            Socket socket=serverSocket.accept();
+            //4、HTTP请求,发送的数据就是字符串,有规律的字符串(HTTP协议)
+            process(socket);
+        }
+
+    }
+
+    private void process(Socket socket)throws Exception {
+        InputStream is = socket.getInputStream();
+        OutputStream os = socket.getOutputStream();
+        Request request=new Request(is);
+        Response response=new Response(os);
+        String url=request.getUrl();
+        if (servletMap.containsKey(url)){
+            servletMap.get(url).service(request,response);
+        }else{
+            response.write("404 not found");
+        }
+        os.flush();
+        os.close();
+        is.close();
+        socket.close();
+    }
+
+    public static void main(String[] args) throws Exception{
+        new Tomcat().start();
+    }
+}

+ 6 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/constant/ConstantParam.java

@@ -0,0 +1,6 @@
+package cn.hhj.bio.tomcat.constant;
+
+public class ConstantParam {
+    public static final String HOST="localhost";
+    public static final Integer PORT=8080;
+}

+ 32 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/http/Request.java

@@ -0,0 +1,32 @@
+package cn.hhj.bio.tomcat.http;
+
+import java.io.InputStream;
+
+public class Request {
+    private String method;
+    private String url;
+
+    public Request(InputStream in)throws Exception{
+        //拿到HTTP协议内容
+        String content = "";
+        byte[] buffer=new byte[1024];
+        int len = 0;
+        if ((len = in.read(buffer)) > 0) {
+            content = new String(buffer,0,len);
+        }
+        String line = content.split("\\n")[0];
+        String [] arr = line.split("\\s");
+        this.method = arr[0];
+        this.url = arr[1].split("\\?")[0];
+        System.err.println(content);
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+}

+ 18 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/http/Response.java

@@ -0,0 +1,18 @@
+package cn.hhj.bio.tomcat.http;
+
+import java.io.OutputStream;
+
+public class Response {
+    private OutputStream out;
+    public Response(OutputStream out){
+        this.out = out;
+    }
+    public void write(String s) throws Exception {
+        StringBuilder sb = new StringBuilder();
+        sb.append("HTTP/1.1 200 OK\n") // 状态码,表示响应成功
+                .append("Content-Type: text/html;\n") // 返回值类型
+                .append("\r\n") // 分隔符
+                .append(s); // 返回值内容
+        out.write(sb.toString().getBytes());
+    }
+}

+ 13 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/http/Servlet.java

@@ -0,0 +1,13 @@
+package cn.hhj.bio.tomcat.http;
+
+public abstract class Servlet {
+    public void service(Request request, Response response) throws Exception{
+        if("GET".equalsIgnoreCase(request.getMethod())){
+            doGet(request,response);
+        }else{
+            doPost(request,response);
+        }
+    }
+    public abstract void doGet(Request request, Response response) throws Exception;
+    public abstract void doPost(Request request, Response response) throws Exception;
+}

+ 16 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/servlet/FirstServlet.java

@@ -0,0 +1,16 @@
+package cn.hhj.bio.tomcat.servlet;
+
+
+import cn.hhj.bio.tomcat.http.*;
+
+public class FirstServlet extends Servlet {
+
+	public void doGet(Request request, Response response) throws Exception {
+		this.doPost(request, response);
+	}
+
+	public void doPost(Request request, Response response) throws Exception {
+		response.write("This is First Serlvet");
+	}
+
+}

+ 18 - 0
rpc-tomcatv1/src/main/java/cn/hhj/bio/tomcat/servlet/SecondServlet.java

@@ -0,0 +1,18 @@
+package cn.hhj.bio.tomcat.servlet;
+
+
+import cn.hhj.bio.tomcat.http.Request;
+import cn.hhj.bio.tomcat.http.Response;
+import cn.hhj.bio.tomcat.http.Servlet;
+
+public class SecondServlet extends Servlet {
+
+	public void doGet(Request request, Response response) throws Exception {
+		this.doPost(request, response);
+	}
+
+	public void doPost(Request request, Response response) throws Exception {
+		response.write("This is Second Serlvet");
+	}
+
+}

+ 128 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/NIOServerDemo.java

@@ -0,0 +1,128 @@
+package cn.hhj.nio;
+
+import com.sun.org.apache.bcel.internal.generic.Select;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * NIO的操作过于繁琐,于是才有了Netty
+ * Netty就是对这一系列非常繁琐的操作进行了封装
+ *
+ * Created by Tom.
+ */
+public class NIOServerDemo {
+
+    private int port = 8080;
+
+    //准备两个东西
+    //轮询器 Selector 大堂经理
+    private Selector selector;
+    //缓冲区 Buffer 等候区
+    private ByteBuffer buffer = ByteBuffer.allocate(1024);
+
+    //初始化完毕
+    public NIOServerDemo(int port){
+        //初始化大堂经理,开门营业
+        try {
+            this.port = port;
+            ServerSocketChannel server = ServerSocketChannel.open();
+            //我得告诉地址
+            //IP/Port
+            server.bind(new InetSocketAddress(this.port));
+            //BIO 升级版本 NIO,为了兼容BIO,NIO模型默认是采用阻塞式
+            server.configureBlocking(false);
+
+            //大堂经理准备就绪,接客
+            selector = Selector.open();
+
+            //在门口翻牌子,正在营业
+            server.register(selector, SelectionKey.OP_ACCEPT);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void listen(){
+        System.out.println("listen on " + this.port + ".");
+        try {
+            //轮询主线程
+
+            while (true){
+                //大堂经理再叫号
+                selector.select();
+                //每次都拿到所有的号子
+                Set<SelectionKey> keys = selector.selectedKeys();
+                Iterator<SelectionKey> iter = keys.iterator();
+                //不断地迭代,就叫轮询
+                //同步体现在这里,因为每次只能拿一个key,每次只能处理一种状态
+                while (iter.hasNext()){
+                    SelectionKey key = iter.next();
+                    iter.remove();
+                    //每一个key代表一种状态
+                    //没一个号对应一个业务
+                    //数据就绪、数据可读、数据可写 等等等等
+                    process(key);
+                }
+                
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    //具体办业务的方法,坐班柜员
+    //每一次轮询就是调用一次process方法,而每一次调用,只能干一件事
+    //在同一时间点,只能干一件事
+    private void process(SelectionKey key) throws IOException {
+        //针对于每一种状态给一个反应
+        if(key.isAcceptable()){
+            ServerSocketChannel server = (ServerSocketChannel)key.channel();
+            //这个方法体现非阻塞,不管你数据有没有准备好
+            //你给我一个状态和反馈
+            SocketChannel channel = server.accept();
+            //一定一定要记得设置为非阻塞
+            channel.configureBlocking(false);
+            //当数据准备就绪的时候,将状态改为可读
+            key = channel.register(selector,SelectionKey.OP_READ);
+        }
+        else if(key.isReadable()){
+            //key.channel 从多路复用器中拿到客户端的引用
+            SocketChannel channel = (SocketChannel)key.channel();
+            int len = channel.read(buffer);
+            if(len > 0){
+                buffer.flip();
+                String content = new String(buffer.array(),0,len);
+                key = channel.register(selector,SelectionKey.OP_WRITE);
+                //在key上携带一个附件,一会再写出去
+                key.attach(content);
+                System.out.println("读取内容:" + content);
+            }
+        }
+        else if(key.isWritable()){
+            SocketChannel channel = (SocketChannel)key.channel();
+
+            String content = (String)key.attachment();
+            channel.write(ByteBuffer.wrap(("输出:" + content).getBytes()));
+
+            channel.close();
+        }
+    }
+
+    public static void main(String[] args) {
+        new NIOServerDemo(8080).listen();
+    }
+
+
+
+
+}

+ 55 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/BufferDemo.java

@@ -0,0 +1,55 @@
+package cn.hhj.nio.buffer;
+import java.io.FileInputStream;
+import java.nio.*;  
+import java.nio.channels.*;  
+  
+public class BufferDemo {
+
+
+    //put/get
+
+    public static void main(String args[]) throws Exception {  
+        //这用用的是文件IO处理
+        FileInputStream fin = new FileInputStream("E://test.txt");
+        //创建文件的操作管道
+        FileChannel fc = fin.getChannel();  
+  
+        //分配一个10个大小缓冲区,说白了就是分配一个10个大小的byte数组
+        ByteBuffer buffer = ByteBuffer.allocate(10);  
+        output("初始化", buffer);  
+        
+        //先读一下
+        fc.read(buffer);  
+        output("调用read()", buffer);  
+  
+        //准备操作之前,先锁定操作范围
+        buffer.flip();  
+        output("调用flip()", buffer);  
+  
+        //判断有没有可读数据
+        while (buffer.remaining() > 0) {  
+            byte b = buffer.get();  
+            // System.out.print(((char)b));  
+        }  
+        output("调用get()", buffer);  
+  
+        //可以理解为解锁
+        buffer.clear();  
+        output("调用clear()", buffer);  
+  
+        //最后把管道关闭
+        fin.close();  
+    }  
+
+    //把这个缓冲里面实时状态给答应出来
+    public static void output(String step, ByteBuffer buffer) {
+        System.out.println(step + " : "); 
+        //容量,数组大小
+        System.out.print("capacity: " + buffer.capacity() + ", ");
+        //当前操作数据所在的位置,也可以叫做游标
+        System.out.print("position: " + buffer.position() + ", ");
+        //锁定值,flip,数据操作范围索引只能在position - limit 之间
+        System.out.println("limit: " + buffer.limit());
+        System.out.println();
+    }
+}

+ 35 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/BufferSlice.java

@@ -0,0 +1,35 @@
+package cn.hhj.nio.buffer;
+import java.nio.ByteBuffer;
+
+/**
+ * 缓冲区分片
+ */
+public class BufferSlice {  
+    static public void main( String args[] ) throws Exception {  
+        ByteBuffer buffer = ByteBuffer.allocate( 10 );  
+          
+        // 缓冲区中的数据0-9  
+        for (int i=0; i<buffer.capacity(); ++i) {  
+            buffer.put( (byte)i );  
+        }  
+          
+        // 创建子缓冲区  
+        buffer.position( 3 );  
+        buffer.limit( 7 );  
+        ByteBuffer slice = buffer.slice();  
+          
+        // 改变子缓冲区的内容  
+        for (int i=0; i<slice.capacity(); ++i) {  
+            byte b = slice.get( i );  
+            b *= 10;  
+            slice.put( i, b );  
+        }  
+          
+        buffer.position( 0 );  
+        buffer.limit( buffer.capacity() );  
+          
+        while (buffer.remaining()>0) {  
+            System.out.println( buffer.get() );  
+        }  
+    }  
+}

+ 17 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/BufferWrap.java

@@ -0,0 +1,17 @@
+package cn.hhj.nio.buffer;
+import java.nio.ByteBuffer;
+
+/**
+ * 手动分配缓冲区
+ */
+public class BufferWrap {  
+    
+    public void myMethod() {  
+        // 分配指定大小的缓冲区  
+        ByteBuffer buffer1 = ByteBuffer.allocate(10);  
+          
+        // 包装一个现有的数组  
+        byte array[] = new byte[10];  
+        ByteBuffer buffer2 = ByteBuffer.wrap( array );
+    } 
+}

+ 44 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/DirectBuffer.java

@@ -0,0 +1,44 @@
+package cn.hhj.nio.buffer;
+import java.io.*;
+import java.nio.*;  
+import java.nio.channels.*;
+
+
+/**
+ * 直接缓冲区
+ * Zero Copy 减少了一个拷贝的过程
+  */
+public class DirectBuffer {  
+    static public void main( String args[] ) throws Exception {  
+
+        //在Java里面存的只是缓冲区的引用地址
+        //管理效率
+
+    	//首先我们从磁盘上读取刚才我们写出的文件内容
+        String infile = "E://test.txt";
+        FileInputStream fin = new FileInputStream( infile );  
+        FileChannel fcin = fin.getChannel();
+
+        //把刚刚读取的内容写入到一个新的文件中
+        String outfile = String.format("E://testcopy.txt");
+        FileOutputStream fout = new FileOutputStream(outfile);
+        FileChannel fcout = fout.getChannel();  
+          
+        // 使用allocateDirect,而不是allocate
+        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);  
+          
+        while (true) {  
+            buffer.clear();  
+              
+            int r = fcin.read(buffer);  
+              
+            if (r==-1) {  
+                break;  
+            }  
+              
+            buffer.flip();  
+              
+            fcout.write(buffer);  
+        }
+	}  
+}

+ 24 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/IntBufferDemo.java

@@ -0,0 +1,24 @@
+package cn.hhj.nio.buffer;
+import java.nio.IntBuffer;
+
+public class IntBufferDemo {
+	public static void main(String[] args) {  
+        // 分配新的int缓冲区,参数为缓冲区容量
+        // 新缓冲区的当前位置将为零,其界限(限制位置)将为其容量。它将具有一个底层实现数组,其数组偏移量将为零。  
+        IntBuffer buffer = IntBuffer.allocate(8);
+  
+        for (int i = 0; i < buffer.capacity(); ++i) {  
+            int j = 2 * (i + 1);  
+            // 将给定整数写入此缓冲区的当前位置,当前位置递增  
+            buffer.put(j);  
+        }
+        // 重设此缓冲区,将限制设置为当前位置,然后将当前位置设置为0  
+        buffer.flip();
+        // 查看在当前位置和限制位置之间是否有元素  
+        while (buffer.hasRemaining()) {  
+            // 读取此缓冲区当前位置的整数,然后当前位置递增  
+            int j = buffer.get();  
+            System.out.print(j + "  ");  
+        }
+	}  
+}

+ 26 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/MappedBuffer.java

@@ -0,0 +1,26 @@
+package cn.hhj.nio.buffer;
+import java.io.*;
+import java.nio.*;  
+import java.nio.channels.*;
+
+/**
+ * IO映射缓冲区
+ */
+public class MappedBuffer {  
+    static private final int start = 0;
+    static private final int size = 26;
+      
+    static public void main( String args[] ) throws Exception {  
+        RandomAccessFile raf = new RandomAccessFile( "E://test.txt", "rw" );
+        FileChannel fc = raf.getChannel();
+        
+        //把缓冲区跟文件系统进行一个映射关联
+        //只要操作缓冲区里面的内容,文件内容也会跟着改变
+        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE,start, size );
+          
+        mbb.put( 0, (byte)97 );  //a
+        mbb.put( 25, (byte)122 );   //z
+
+        raf.close();  
+    }  
+}

+ 33 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/buffer/ReadOnlyBuffer.java

@@ -0,0 +1,33 @@
+package cn.hhj.nio.buffer;
+import java.nio.*;
+/**
+ * 只读缓冲区
+ */
+public class ReadOnlyBuffer {  
+	static public void main( String args[] ) throws Exception {  
+		ByteBuffer buffer = ByteBuffer.allocate( 10 );  
+	    
+		// 缓冲区中的数据0-9  
+		for (int i=0; i<buffer.capacity(); ++i) {  
+			buffer.put( (byte)i );  
+		}  
+	
+		// 创建只读缓冲区  
+		ByteBuffer readonly = buffer.asReadOnlyBuffer();  
+	    
+		// 改变原缓冲区的内容  
+		for (int i=0; i<buffer.capacity(); ++i) {  
+			byte b = buffer.get( i );  
+			b *= 10;  
+			buffer.put( i, b );  
+		}  
+	    
+		readonly.position(0);  
+		readonly.limit(buffer.capacity());  
+	    
+		// 只读缓冲区的内容也随之改变  
+		while (readonly.remaining()>0) {  
+			System.out.println( readonly.get());  
+		}
+	}
+}

+ 30 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/channel/FileInputDemo.java

@@ -0,0 +1,30 @@
+package cn.hhj.nio.channel;
+import java.io.*;
+import java.nio.*;  
+import java.nio.channels.*;  
+  
+public class FileInputDemo {
+
+
+    static public void main( String args[] ) throws Exception {  
+        FileInputStream fin = new FileInputStream("E://test.txt");
+        
+        // 获取通道  
+        FileChannel fc = fin.getChannel();  
+          
+        // 创建缓冲区  
+        ByteBuffer buffer = ByteBuffer.allocate(1024);  
+          
+        // 读取数据到缓冲区  
+        fc.read(buffer);  
+        
+        buffer.flip();  
+          
+        while (buffer.remaining() > 0) {  
+            byte b = buffer.get();  
+            System.out.print(((char)b));  
+        }  
+          
+        fin.close();
+    }  
+}

+ 26 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/channel/FileOutputDemo.java

@@ -0,0 +1,26 @@
+package cn.hhj.nio.channel;
+import java.io.*;
+import java.nio.*;  
+import java.nio.channels.*;  
+  
+public class FileOutputDemo {
+    static private final byte message[] = { 83, 111, 109, 101, 32, 98, 121, 116, 101, 115, 46 };
+  
+    static public void main( String args[] ) throws Exception {  
+        FileOutputStream fout = new FileOutputStream( "E://test.txt" );
+          
+        FileChannel fc = fout.getChannel();  
+          
+        ByteBuffer buffer = ByteBuffer.allocate( 1024 );  
+          
+        for (int i=0; i<message.length; ++i) {  
+            buffer.put( message[i] );  
+        }  
+          
+        buffer.flip();   
+          
+        fc.write( buffer );  
+          
+        fout.close();  
+    }  
+}

+ 117 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/chat/NIOChatClient.java

@@ -0,0 +1,117 @@
+package cn.hhj.nio.chat;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.Charset;
+import java.util.Iterator;
+import java.util.Scanner;
+import java.util.Set;
+
+public class NIOChatClient {
+
+	private final InetSocketAddress serverAdrress = new InetSocketAddress("localhost", 8080);
+    private Selector selector = null;
+    private SocketChannel client = null;
+    
+    private String nickName = "";
+    private Charset charset = Charset.forName("UTF-8");
+    private static String USER_EXIST = "系统提示:该昵称已经存在,请换一个昵称";
+    private static String USER_CONTENT_SPILIT = "#@#";
+    
+    
+    public NIOChatClient() throws IOException{
+        selector = Selector.open();
+        //连接远程主机的IP和端口
+        client = SocketChannel.open(serverAdrress);
+        client.configureBlocking(false);
+        client.register(selector, SelectionKey.OP_READ);
+    }
+    
+    public void session(){
+    	//开辟一个新线程从服务器端读数据
+        new Reader().start();
+        //开辟一个新线程往服务器端写数据
+        new Writer().start();
+	}
+    
+    private class Writer extends Thread{
+
+		@Override
+		public void run() {
+			try{
+				//在主线程中 从键盘读取数据输入到服务器端
+		        Scanner scan = new Scanner(System.in);
+		        while(scan.hasNextLine()){
+		            String line = scan.nextLine();
+		            if("".equals(line)) continue; //不允许发空消息
+		            if("".equals(nickName)) {
+		            	nickName = line;
+		                line = nickName + USER_CONTENT_SPILIT;
+		            } else {
+		                line = nickName + USER_CONTENT_SPILIT + line;
+		            }
+//		            client.register(selector, SelectionKey.OP_WRITE);
+		            client.write(charset.encode(line));//client既能写也能读,这边是写
+		        }
+		        scan.close();
+			}catch(Exception e){
+				
+			}
+		}
+    	
+    }
+    
+    
+    private class Reader extends Thread {
+        public void run() {
+            try {
+                while(true) {
+                    int readyChannels = selector.select();
+                    if(readyChannels == 0) continue; 
+                    Set<SelectionKey> selectedKeys = selector.selectedKeys();  //可以通过这个方法,知道可用通道的集合
+                    Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
+                    while(keyIterator.hasNext()) {
+                         SelectionKey key = (SelectionKey) keyIterator.next();
+                         keyIterator.remove();
+                         process(key);
+                    }
+                }
+            }
+            catch (IOException io){
+            	
+            }
+        }
+
+        private void process(SelectionKey key) throws IOException {
+            if(key.isReadable()){
+                //使用 NIOServerDemoBak 读取 Channel中的数据,这个和全局变量client是一样的,因为只注册了一个SocketChannel
+                //client既能写也能读,这边是读
+                SocketChannel sc = (SocketChannel)key.channel();
+                
+                ByteBuffer buff = ByteBuffer.allocate(1024);
+                String content = "";
+                while(sc.read(buff) > 0)
+                {
+                    buff.flip();
+                    content += charset.decode(buff);
+                }
+                //若系统发送通知名字已经存在,则需要换个昵称
+                if(USER_EXIST.equals(content)) {
+                	nickName = "";
+                }
+                System.out.println(content);
+                key.interestOps(SelectionKey.OP_READ);
+            }
+        }
+    }
+    
+    
+    
+    public static void main(String[] args) throws IOException {
+        new NIOChatClient().session();
+    }
+}

+ 163 - 0
rpc-tomcatv1/src/main/java/cn/hhj/nio/chat/NIOChatServer.java

@@ -0,0 +1,163 @@
+package cn.hhj.nio.chat;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.charset.Charset;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * 网络多客户端聊天室
+ * 功能1: 客户端通过Java NIO连接到服务端,支持多客户端的连接
+ * 功能2:客户端初次连接时,服务端提示输入昵称,如果昵称已经有人使用,提示重新输入,如果昵称唯一,则登录成功,之后发送消息都需要按照规定格式带着昵称发送消息
+ * 功能3:客户端登录后,发送已经设置好的欢迎信息和在线人数给客户端,并且通知其他客户端该客户端上线
+ * 功能4:服务器收到已登录客户端输入内容,转发至其他登录客户端。
+ */
+public class NIOChatServer {
+
+    private int port = 8080;
+    private Charset charset = Charset.forName("UTF-8");
+    //用来记录在线人数,以及昵称
+    private static HashSet<String> users = new HashSet<String>();
+    
+    private static String USER_EXIST = "系统提示:该昵称已经存在,请换一个昵称";
+    //相当于自定义协议格式,与客户端协商好
+    private static String USER_CONTENT_SPILIT = "#@#";
+    
+    private Selector selector = null;
+    
+    public NIOChatServer(int port) throws IOException{
+		
+		this.port = port;
+		
+		ServerSocketChannel server = ServerSocketChannel.open();
+		
+		server.bind(new InetSocketAddress(this.port));
+		server.configureBlocking(false);
+		
+		selector = Selector.open();
+		
+		server.register(selector, SelectionKey.OP_ACCEPT);
+		
+		System.out.println("服务已启动,监听端口是:" + this.port);
+	}
+
+    /*
+    * 开始监听
+    */
+    public void listen() throws IOException{
+    	while(true) {
+            int wait = selector.select();
+            if(wait == 0) continue; 
+            Set<SelectionKey> keys = selector.selectedKeys();  //可以通过这个方法,知道可用通道的集合
+            Iterator<SelectionKey> iterator = keys.iterator();
+            while(iterator.hasNext()) {
+				SelectionKey key = (SelectionKey) iterator.next();
+				iterator.remove();
+				process(key);
+            }
+        }
+		
+	}
+    
+    
+    public void process(SelectionKey key) throws IOException {
+        if(key.isAcceptable()){
+        	ServerSocketChannel server = (ServerSocketChannel)key.channel();
+            SocketChannel client = server.accept();
+            //非阻塞模式
+            client.configureBlocking(false);
+            //注册选择器,并设置为读取模式,收到一个连接请求,然后起一个SocketChannel,并注册到selector上,之后这个连接的数据,就由这个SocketChannel处理
+            client.register(selector, SelectionKey.OP_READ);
+            
+            //将此对应的channel设置为准备接受其他客户端请求
+            key.interestOps(SelectionKey.OP_ACCEPT);
+//            System.out.println("有客户端连接,IP地址为 :" + sc.getRemoteAddress());
+            client.write(charset.encode("请输入你的昵称"));
+        }
+        //处理来自客户端的数据读取请求
+        if(key.isReadable()){
+            //返回该SelectionKey对应的 Channel,其中有数据需要读取
+            SocketChannel client = (SocketChannel)key.channel(); 
+            ByteBuffer buff = ByteBuffer.allocate(1024);
+            StringBuilder content = new StringBuilder();
+            try{
+                while(client.read(buff) > 0) {
+                    buff.flip();
+                    content.append(charset.decode(buff));
+                }
+//                System.out.println("从IP地址为:" + sc.getRemoteAddress() + "的获取到消息: " + content);
+                //将此对应的channel设置为准备下一次接受数据
+                key.interestOps(SelectionKey.OP_READ);
+            }catch (IOException io){
+            	key.cancel();
+                if(key.channel() != null) {
+                	key.channel().close();
+                }
+            }
+            if(content.length() > 0) {
+                String[] arrayContent = content.toString().split(USER_CONTENT_SPILIT);
+                //注册用户
+                if(arrayContent != null && arrayContent.length == 1) {
+                    String nickName = arrayContent[0];
+                    if(users.contains(nickName)) {
+                    	client.write(charset.encode(USER_EXIST));
+                    } else {
+                        users.add(nickName);
+                        int onlineCount = onlineCount();
+                        String message = "欢迎 " + nickName + " 进入聊天室! 当前在线人数:" + onlineCount;
+                        broadCast(null, message);
+                    }
+                } 
+                //注册完了,发送消息
+                else if(arrayContent != null && arrayContent.length > 1) {
+                    String nickName = arrayContent[0];
+                    String message = content.substring(nickName.length() + USER_CONTENT_SPILIT.length());
+                    message = nickName + " 说 " + message;
+                    if(users.contains(nickName)) {
+                        //不回发给发送此内容的客户端
+                    	broadCast(client, message);
+                    }
+                }
+            }
+            
+        }
+    }
+
+    public int onlineCount() {
+        int res = 0;
+        for(SelectionKey key : selector.keys()){
+            Channel target = key.channel();
+            
+            if(target instanceof SocketChannel){
+                res++;
+            }
+        }
+        return res;
+    }
+    
+    
+    public void broadCast(SocketChannel client, String content) throws IOException {
+        //广播数据到所有的SocketChannel中
+        for(SelectionKey key : selector.keys()) {
+            Channel targetchannel = key.channel();
+            //如果client不为空,不回发给发送此内容的客户端
+            if(targetchannel instanceof SocketChannel && targetchannel != client) {
+                SocketChannel target = (SocketChannel)targetchannel;
+                target.write(charset.encode(content));
+            }
+        }
+    }
+    
+    
+    public static void main(String[] args) throws IOException {
+        new NIOChatServer(8080).listen();
+    }
+}

+ 5 - 0
rpc-tomcatv1/src/main/resources/web.properties

@@ -0,0 +1,5 @@
+servlet.one.url=/firstServlet.do
+servlet.one.className=cn.hhj.bio.tomcat.servlet.FirstServlet
+
+servlet.two.url=/secondServlet.do
+servlet.two.className=cn.hhj.bio.tomcat.servlet.SecondServlet