博客中代码地址:https://github.com/farliu/farpc.git
dubbo结构
直至上一章,手写dubbo全部介绍完了,这一章作为番外篇,了解如何使用内嵌tomcat。
项目结构介绍
本节涉及博客中代码的module,farpc-rpc(远程调用)。
内嵌tomcat使用
使用tomcat,自然就是http协议,我们先导入tomcat的依赖。
代码语言:javascript复制 <dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.27</version>
</dependency>
继续实现之前留下的扩展接口IConsumerServer、IProviderServer。在实现IProviderServer之前,我们需要先得到一个Servlet用于处理请求。
代码语言:javascript复制public class DispatcherServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
new HttpServerHandler().handle(req, resp);
}
}
为了方便扩展,我在servlet中调用定义的Handler,后续如果需要增加Handler,也只要修改这里就行了。
代码语言:javascript复制public class HttpServerHandler {
private static final Logger logger = LoggerFactory.getLogger(HttpServerHandler.class);
public void handle(HttpServletRequest req, HttpServletResponse resp) {
try {
ServletInputStream inputStream = req.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
RequestDTO requestDTO = (RequestDTO) objectInputStream.readObject();
Object result = new Object();
logger.info("receive request.. {}", requestDTO);
if (Container.getProviders().containsKey(requestDTO.getClassName())) {
Object provider = Container.getProviders().get(requestDTO.getClassName());
Class<?> providerClazz = provider.getClass();
Method method = providerClazz.getMethod(requestDTO.getMethodName(), requestDTO.getTypes());
result = method.invoke(provider, requestDTO.getParams());
}
ObjectOutputStream objectOutputStream = new ObjectOutputStream(resp.getOutputStream());
objectOutputStream.writeObject(result);
objectOutputStream.flush();
objectOutputStream.close();
// IOUtils.write(result.toString(), resp.getOutputStream());
} catch (Exception e) {
}
}
}
Handler的代码也很容易理解,就是从Request中获得请求参数,然后根据请求参数反射执行对应的方法,然后输出到输出流中。
对于IConsumerServer的实现,就是Http调用了,代码如下:
代码语言:javascript复制public class HttpConsumerServer implements IConsumerServer {
public Object execute(String address, RequestDTO requestDTO) {
String[] addrs = address.split(":");
String ip = addrs[0];
Integer port = Integer.parseInt(addrs[1]);
try {
URL url = new URL("http", ip, port, "/");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
OutputStream outputStream = httpURLConnection.getOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(requestDTO);
objectOutputStream.flush();
objectOutputStream.close();
InputStream inputStream = httpURLConnection.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
Object result = objectInputStream.readObject();
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
还有别忘了增加SPI扩展点
代码语言:javascript复制http=com.ofcoder.farpc.rpc.http.HttpConsumerServer
http=com.ofcoder.farpc.rpc.http.HttpProviderServer
测试
测试代码位于farpc-demo的模块下。
代码语言:javascript复制@Test
public void providerTest() throws IOException {
IProviderServer server = RpcFactory.getProviderServer();
server.start("127.0.0.1:20880");
System.in.read();
}
@Test
public void consumerTest(){
IWelcome welcome = ConsumerProxy.create(IWelcome.class);
String far = welcome.greet("far");
System.out.println(far);
}
可以分别看到相应的日志。服务提供端日志如下:
代码语言:javascript复制...
十月 28, 2019 9:55:57 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-nio-20880"]
十月 28, 2019 9:55:57 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
十月 28, 2019 9:55:57 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.27]
十月 28, 2019 9:55:57 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-20880"]
消费端:
代码语言:javascript复制...
[28/10/19 21:56:56:191 CST] main-EventThread INFO state.ConnectionStateManager: State change: CONNECTED
hello far, welcome to ofcoder.