zoukankan      html  css  js  c++  java
  • 简单Tomcat HTTP RPC框架

    RPC基础知识

    什么是RPC?

    RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。

    RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。

    RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

    RPC的模型

    C/S模式 
    基于传输层协议(例如TCP/IP)  远程调用不是新的一种数据传输协议
    事件响应基本模型(请求、计算、响应)

    RPC设计的目的

    通过固定的协议调用非本机的方法
    提供不同语言程序之间通信
    可以在不了解底层通信,像本地方法一样调用

    RPC框架完全封装了网络传输以及其他细节,比如Spring 的RPC框架在调用远程对象的方法时就像调用Spring Bean 对象一样使用.

    RPC的应用 大量的分布式应用都使用了RPC协议,比如分布式操作系统、分布式计算、分布式软件设计

    RPC过程详解

    RPC框架封装网络传输和其他细节,消费者和生产者不用去关心底层原理

    消费者的代理层控制了整个RPC调用的流程,生成代理对象,封装请求报文,发送请求之类的

    服务提供者会有一个监听模块,用来监听请求,并且按照约定,应该是注册了的服务才会被消费者调用到,注册的服务需要被反射调用到,用来计算结果

    RPC框架的特点和设计模型

    封装网络交互

    尽量不要让RPC框架的使用者涉及到过多的网络层的开发

    远程调用对象的代理

    将接口代理的对象放入到Spring 容器之中,方便服务端开发

    支持容器(Spring、Jetty等)

    支持Spring容器,还有Jetty这样的web容器

    可配置,可扩展

    尽量做到可配置,可扩展

    设计模型

    Proxy代理层

    用于对象的代理,对象的反射调用,RPC流程的控制

    Serialize序列化层

    将请求和结果做序列化和反序列化

    Invoke网络模块

    网络通信相关的处理

    Container容器组件

    支持代理层监听网络请求

    代码实现

    pom.xml

    [html] view plain copy
     
    1. <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">  
    2.   <modelVersion>4.0.0</modelVersion>  
    3.   <groupId>com.ibigsea</groupId>  
    4.   <artifactId>http-rpc</artifactId>  
    5.   <version>0.0.1-SNAPSHOT</version>  
    6.     
    7.   <dependencies>  
    8.         <dependency>  
    9.             <groupId>com.alibaba</groupId>  
    10.             <artifactId>fastjson</artifactId>  
    11.             <version>1.2.3</version>  
    12.         </dependency>  
    13.         <dependency>  
    14.             <groupId>ch.qos.logback</groupId>  
    15.             <artifactId>logback-classic</artifactId>  
    16.             <version>1.0.13</version>  
    17.         </dependency>  
    18.         <dependency>  
    19.             <groupId>org.mortbay.jetty</groupId>  
    20.             <artifactId>jetty</artifactId>  
    21.             <version>6.1.26</version>  
    22.         </dependency>  
    23.         <dependency>  
    24.             <groupId>org.apache.httpcomponents</groupId>  
    25.             <artifactId>httpcore</artifactId>  
    26.             <version>4.3.3</version>  
    27.         </dependency>  
    28.         <dependency>  
    29.             <groupId>org.apache.httpcomponents</groupId>  
    30.             <artifactId>httpclient</artifactId>  
    31.             <version>4.3.6</version>  
    32.             <exclusions>  
    33.                 <exclusion>  
    34.                     <artifactId>commons-logging</artifactId>  
    35.                     <groupId>commons-logging</groupId>  
    36.                 </exclusion>  
    37.             </exclusions>  
    38.         </dependency>  
    39.         <dependency>  
    40.             <groupId>org.springframework</groupId>  
    41.             <artifactId>spring-context</artifactId>  
    42.             <version>3.2.8.RELEASE</version>  
    43.             <exclusions>  
    44.                 <exclusion>  
    45.                     <artifactId>commons-logging</artifactId>  
    46.                     <groupId>commons-logging</groupId>  
    47.                 </exclusion>  
    48.             </exclusions>  
    49.         </dependency>  
    50.         <dependency>  
    51.           <groupId>commons-logging</groupId>  
    52.           <artifactId>commons-logging</artifactId>  
    53.           <version>1.2</version>  
    54.         </dependency>  
    55.   </dependencies>  
    56. </project>  

    config包下面的

    ConsumerConfig.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.config;  
    2.   
    3. /** 
    4.  * 服务消费者配置 
    5.  *  
    6.  * @author bigsea 
    7.  * 
    8.  */  
    9. public class ConsumerConfig {  
    10.   
    11.     /** 
    12.      * 请求地址 服务提供者监听的地址和端口 
    13.      */  
    14.     private String url;  
    15.   
    16.     public String getUrl() {  
    17.         return url;  
    18.     }  
    19.   
    20.     public void setUrl(String url) {  
    21.         this.url = url;  
    22.     }  
    23.   
    24. }   

    ProviderConfig.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.config;  
    2.   
    3. /** 
    4.  * 服务提供者配置 
    5.  *  
    6.  * @author bigsea 
    7.  * 
    8.  */  
    9. public class ProviderConfig {  
    10.   
    11.     /** 
    12.      * 监听端口 服务提供者监听请求端口 
    13.      */  
    14.     private int port;  
    15.   
    16.     public ProviderConfig() {  
    17.     }  
    18.   
    19.     public ProviderConfig(int port) {  
    20.         this.port = port;  
    21.     }  
    22.   
    23.     public int getPort() {  
    24.         return port;  
    25.     }  
    26.   
    27.     public void setPort(int port) {  
    28.         this.port = port;  
    29.     }  
    30.   
    31. }   

    序列化层

    Request.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.serizlize;  
    2.   
    3. import java.io.Serializable;  
    4.   
    5. import com.alibaba.fastjson.annotation.JSONType;  
    6.   
    7. /** 
    8.  * 请求信息 
    9.  *  
    10.  * @author bigsea 
    11.  * 
    12.  */  
    13. public class Request implements Serializable {  
    14.   
    15.     private static final long serialVersionUID = -4363326153251862952L;  
    16.   
    17.     private Class clazz;  
    18.   
    19.     private String method;  
    20.   
    21.     private Object param;  
    22.   
    23.     public Request() {  
    24.     }  
    25.   
    26.     public Request(Class clazz, String method, Object param) {  
    27.         this.clazz = clazz;  
    28.         this.method = method;  
    29.         this.param = param;  
    30.     }  
    31.   
    32.     public Class getClazz() {  
    33.         return clazz;  
    34.     }  
    35.   
    36.     public void setClazz(Class clazz) {  
    37.         this.clazz = clazz;  
    38.     }  
    39.   
    40.     public String getMethod() {  
    41.         return method;  
    42.     }  
    43.   
    44.     public void setMethod(String method) {  
    45.         this.method = method;  
    46.     }  
    47.   
    48.     public Object getParam() {  
    49.         return param;  
    50.     }  
    51.   
    52.     public void setParam(Object param) {  
    53.         this.param = param;  
    54.     }  
    55.   
    56.     /** 
    57.      * 通过反射执行对应的方法 
    58.      *  
    59.      * @param bean 
    60.      * @return 
    61.      * @throws Exception 
    62.      */  
    63.     public Object invoke(Object bean) throws Exception {  
    64.         return clazz.getMethod(method, param.getClass()).invoke(bean, param);  
    65.     }  
    66.   
    67. }  

    JsonParser.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.serizlize;  
    2.   
    3. import com.alibaba.fastjson.JSON;  
    4. import com.alibaba.fastjson.parser.ParserConfig;  
    5. import com.alibaba.fastjson.serializer.SerializerFeature;  
    6.   
    7. /** 
    8.  * 反序列化 
    9.  *  
    10.  * @author bigsea 
    11.  * 
    12.  */  
    13. public class JsonParser {  
    14.     /** 
    15.      * 反序列化请求 将请求反序列化成一个请求报文 
    16.      *  
    17.      * @param param 
    18.      * @return 
    19.      */  
    20.     public static Request reqParse(String param) {  
    21.         return JSON.parseObject(param, Request.class);  
    22.     }  
    23.   
    24.     /** 
    25.      * 反序列化响应 将响应反序列化成一个响应报文 
    26.      *  
    27.      * @param result 
    28.      * @return 
    29.      */  
    30.     public static <T> T resbParse(String result) {  
    31.         return (T) JSON.parse(result);  
    32.     }  
    33.   
    34. }  

    JsonFormatter.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.serizlize;  
    2.   
    3. import com.alibaba.fastjson.JSON;  
    4. import com.alibaba.fastjson.parser.ParserConfig;  
    5. import com.alibaba.fastjson.serializer.SerializerFeature;  
    6.   
    7. /** 
    8.  * 序列化 
    9.  *  
    10.  * @author bigsea 
    11.  * 
    12.  */  
    13. public class JsonFormatter {  
    14.   
    15.     /** 
    16.      * 将请求序列化成字符串 
    17.      *  
    18.      * @param clazz 
    19.      * @param method 
    20.      * @param param 
    21.      * @return 
    22.      */  
    23.     public static String reqFormatter(Class clazz, String method, Object param) {  
    24.         Request request = new Request(clazz, method, param);  
    25.         return JSON.toJSONString(request, SerializerFeature.WriteClassName);  
    26.     }  
    27.   
    28.     /** 
    29.      * 将响应序列化成字符串 
    30.      *  
    31.      * @param param 
    32.      * @return 
    33.      */  
    34.     public static String resbFormatter(Object param) {  
    35.         return JSON.toJSONString(param, SerializerFeature.WriteClassName);  
    36.     }  
    37.   
    38. }  


    http容器  httpContainer.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.container;  
    2.   
    3. import org.mortbay.jetty.Connector;  
    4. import org.mortbay.jetty.Server;  
    5. import org.mortbay.jetty.handler.AbstractHandler;  
    6. import org.mortbay.jetty.nio.SelectChannelConnector;  
    7. import org.slf4j.Logger;  
    8. import org.slf4j.LoggerFactory;  
    9.   
    10. import com.ibigsea.rpc.config.ProviderConfig;  
    11.   
    12. /** 
    13.  * 利用Jetty实现简单的嵌入式Httpserver 
    14.  *  
    15.  * @author bigsea 
    16.  * 
    17.  */  
    18. public class HttpContainer {  
    19.   
    20.     private Logger LOG = LoggerFactory.getLogger(HttpContainer.class);  
    21.   
    22.     private AbstractHandler httpHandler;  
    23.     private ProviderConfig providerConfig;  
    24.   
    25.     /** 
    26.      * 构造方法 
    27.      *  
    28.      * @param httpHandler 
    29.      */  
    30.     public HttpContainer(AbstractHandler httpHandler) {  
    31.         this(httpHandler, new ProviderConfig(8080));  
    32.     }  
    33.   
    34.     /** 
    35.      * 构造方法 
    36.      *  
    37.      * @param httpHandler 
    38.      * @param providerConfig 
    39.      */  
    40.     public HttpContainer(AbstractHandler httpHandler, ProviderConfig providerConfig) {  
    41.         this.httpHandler = httpHandler;  
    42.         this.providerConfig = providerConfig;  
    43.     }  
    44.   
    45.     public void start() {  
    46.         // 进行服务器配置  
    47.         Server server = new Server();  
    48.         try {  
    49.             SelectChannelConnector connector = new SelectChannelConnector();  
    50.             // 设置监听端口  
    51.             connector.setPort(providerConfig.getPort());  
    52.             // 设置handler,请求过来之后通过该handler来处理请求  
    53.             server.setHandler(httpHandler);  
    54.             server.setConnectors(new Connector[] { connector });  
    55.             server.start();  
    56.             LOG.info("容器启动~");  
    57.         } catch (Exception e) {  
    58.             LOG.error("容器启动异常~", e);  
    59.         }  
    60.   
    61.     }  
    62.   
    63. }   

    RpcException.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.exception;  
    2.   
    3. /** 
    4.  * 异常 
    5.  *  
    6.  * @author bigsea 
    7.  * 
    8.  */  
    9. public class RpcException extends Throwable {  
    10.     private Object data;  
    11.   
    12.     public RpcException(String message, Throwable cause, Object data) {  
    13.         super(message, cause);  
    14.         this.data = data;  
    15.     }  
    16.   
    17.     public RpcException(Object data) {  
    18.         super();  
    19.         this.data = data;  
    20.     }  
    21.   
    22.     public Object getData() {  
    23.         return data;  
    24.     }  
    25. }  

    HttpInvoke.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.invoke;  
    2.   
    3. import java.io.OutputStream;  
    4. import java.util.ArrayList;  
    5. import java.util.List;  
    6.   
    7. import org.apache.http.HttpHost;  
    8. import org.apache.http.HttpResponse;  
    9. import org.apache.http.NameValuePair;  
    10. import org.apache.http.client.HttpClient;  
    11. import org.apache.http.client.entity.UrlEncodedFormEntity;  
    12. import org.apache.http.client.methods.HttpPost;  
    13. import org.apache.http.conn.routing.HttpRoute;  
    14. import org.apache.http.impl.client.HttpClients;  
    15. import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;  
    16. import org.apache.http.message.BasicNameValuePair;  
    17. import org.apache.http.util.EntityUtils;  
    18.   
    19. import com.ibigsea.rpc.config.ConsumerConfig;  
    20. import com.ibigsea.rpc.exception.RpcException;  
    21.   
    22. /** 
    23.  * http请求和响应处理 
    24.  *  
    25.  * @author bigsea 
    26.  * 
    27.  */  
    28. public class HttpInvoke {  
    29.   
    30.     private static final HttpClient httpClient = getHttpClient();  
    31.   
    32.     /** 
    33.      * 单例 
    34.      */  
    35.     private static HttpInvoke httpInvoke;  
    36.   
    37.     private HttpInvoke() {  
    38.   
    39.     }  
    40.   
    41.     public static synchronized HttpInvoke getInstance() {  
    42.         if (httpInvoke == null) {  
    43.             httpInvoke = new HttpInvoke();  
    44.         }  
    45.         return httpInvoke;  
    46.     }  
    47.   
    48.     /** 
    49.      * 发送请求 
    50.      *  
    51.      * @param request 
    52.      *            服务消费者将 (类信息、方法、参数)封装成请求报文,序列化后的字符串 
    53.      * @param consumerConfig 
    54.      *            服务消费者请求的地址 
    55.      * @return 请求结果 
    56.      * @throws RpcException 
    57.      */  
    58.     public String request(String request, ConsumerConfig consumerConfig) throws RpcException {  
    59.         HttpPost post = new HttpPost(consumerConfig.getUrl());  
    60.         // 使用长连接  
    61.         post.setHeader("Connection", "Keep-Alive");  
    62.         List<NameValuePair> params = new ArrayList<NameValuePair>();  
    63.         params.add(new BasicNameValuePair("data", request));  
    64.   
    65.         try {  
    66.             post.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));  
    67.             HttpResponse response = httpClient.execute(post);  
    68.             if (response.getStatusLine().getStatusCode() == 200) {  
    69.                 return EntityUtils.toString(response.getEntity(), "UTF-8");  
    70.             }  
    71.             throw new RpcException(request);  
    72.         } catch (Exception e) {  
    73.             throw new RpcException("http调用异常", e, request);  
    74.         }  
    75.     }  
    76.   
    77.     /** 
    78.      * 响应结果 服务提供者根据服务消费者的请求报文执行后返回结果信息 
    79.      *  
    80.      * @param response 
    81.      * @param outputStream 
    82.      * @throws RpcException 
    83.      */  
    84.     public void response(String response, OutputStream outputStream) throws RpcException {  
    85.         try {  
    86.             outputStream.write(response.getBytes("UTF-8"));  
    87.             outputStream.flush();  
    88.         } catch (Exception e) {  
    89.             e.printStackTrace();  
    90.         }  
    91.     }  
    92.   
    93.     private static HttpClient getHttpClient() {  
    94.         PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();  
    95.         // 连接池最大生成连接数200  
    96.         cm.setMaxTotal(200);  
    97.         // 默认设置route最大连接数为20  
    98.         cm.setDefaultMaxPerRoute(20);  
    99.         // 指定专门的route,设置最大连接数为80  
    100.         HttpHost localhost = new HttpHost("localhost", 8080);  
    101.         cm.setMaxPerRoute(new HttpRoute(localhost), 50);  
    102.         // 创建httpClient  
    103.         return HttpClients.custom().setConnectionManager(cm).build();  
    104.     }  
    105.   
    106. }  

    接下来就是代理成了,因为我们使用了jetty容器,所以这里对服务提供者的代理我们通过jetty的AbstractHandler来实现请求的处理

    ProviderProxyFactory.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.proxy;  
    2.   
    3. import java.io.IOException;  
    4. import java.util.Map;  
    5. import java.util.concurrent.ConcurrentHashMap;  
    6.   
    7. import javax.servlet.ServletException;  
    8. import javax.servlet.http.HttpServletRequest;  
    9. import javax.servlet.http.HttpServletResponse;  
    10.   
    11. import org.mortbay.jetty.handler.AbstractHandler;  
    12. import org.mortbay.log.Log;  
    13. import org.slf4j.Logger;  
    14. import org.slf4j.LoggerFactory;  
    15.   
    16. import com.ibigsea.rpc.config.ProviderConfig;  
    17. import com.ibigsea.rpc.container.HttpContainer;  
    18. import com.ibigsea.rpc.exception.RpcException;  
    19. import com.ibigsea.rpc.invoke.HttpInvoke;  
    20. import com.ibigsea.rpc.serizlize.JsonFormatter;  
    21. import com.ibigsea.rpc.serizlize.JsonParser;  
    22. import com.ibigsea.rpc.serizlize.Request;  
    23.   
    24. /** 
    25.  * 服务提供者代理 
    26.  *  
    27.  * @author bigsea 
    28.  * 
    29.  */  
    30. public class ProviderProxyFactory extends AbstractHandler {  
    31.   
    32.     private Logger LOG = LoggerFactory.getLogger(ProviderProxyFactory.class);  
    33.   
    34.     /** 
    35.      * 提供服务需要注册,这里使用map类实现简单的注册 约定俗成的,暴漏服务是需要注册的 
    36.      */  
    37.     private Map<Class, Object> providers = new ConcurrentHashMap<Class, Object>();  
    38.   
    39.     /** 
    40.      * 这里用来获取暴露的服务 
    41.      */  
    42.     private static ProviderProxyFactory factory;  
    43.   
    44.     private static HttpInvoke invoke = HttpInvoke.getInstance();  
    45.   
    46.     /** 
    47.      * 构造方法 注册服务 创建http容器,并启动 
    48.      *  
    49.      * @param providers 
    50.      * @param config 
    51.      */  
    52.     public ProviderProxyFactory(Map<Class, Object> providers, ProviderConfig config) {  
    53.         this.providers = providers;  
    54.         HttpContainer container = new HttpContainer(this, config);  
    55.         container.start();  
    56.         factory = this;  
    57.         for (Map.Entry<Class, Object> entry : providers.entrySet()) {  
    58.             Log.info(entry.getKey().getSimpleName() + " register");  
    59.         }  
    60.     }  
    61.   
    62.     /** 
    63.      * 处理请求 服务消费者发送请求报文过来,服务提供者解析请求报文,通过反射执行方法 
    64.      */  
    65.     public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)  
    66.             throws IOException, ServletException {  
    67.         // 获取请求报文  
    68.         String data = request.getParameter("data");  
    69.   
    70.         try {  
    71.             // 反序列化  
    72.             Request req = JsonParser.reqParse(data);  
    73.             // 获取到注册的服务,并通过反射执行方法  
    74.             Object res = req.invoke(ProviderProxyFactory.getInstance().getBeanByClass(req.getClazz()));  
    75.             // 返回结果  
    76.             invoke.response(JsonFormatter.resbFormatter(res), response.getOutputStream());  
    77.         } catch (Exception e) {  
    78.             e.printStackTrace();  
    79.         } catch (RpcException e) {  
    80.             e.printStackTrace();  
    81.         }  
    82.   
    83.     }  
    84.   
    85.     public Object getBeanByClass(Class clazz) throws RpcException {  
    86.         Object bean = providers.get(clazz);  
    87.         if (bean != null) {  
    88.             return bean;  
    89.         }  
    90.         throw new RpcException("service no register", new NullPointerException(), clazz);  
    91.     }  
    92.   
    93.     public static ProviderProxyFactory getInstance() {  
    94.         return factory;  
    95.     }  
    96.   
    97. }  


    对于服务消费者,我们通过jdk的invocationHandler来生成代理对象,对于生成的代理对象都会去执行invoke方法

    ConsumerProxyFatory.java

    [java] view plain copy
     
    1. package com.ibigsea.rpc.proxy;  
    2.   
    3. import java.lang.reflect.InvocationHandler;  
    4. import java.lang.reflect.Method;  
    5. import java.lang.reflect.Proxy;  
    6.   
    7. import com.ibigsea.rpc.config.ConsumerConfig;  
    8. import com.ibigsea.rpc.invoke.HttpInvoke;  
    9. import com.ibigsea.rpc.serizlize.JsonFormatter;  
    10. import com.ibigsea.rpc.serizlize.JsonParser;  
    11.   
    12. /** 
    13.  * 服务消费者代理 
    14.  *  
    15.  * @author bigsea 
    16.  * 
    17.  */  
    18. public class ConsumerProxyFactory implements InvocationHandler {  
    19.   
    20.     /** 
    21.      * 消费者配置 
    22.      */  
    23.     private ConsumerConfig config;  
    24.   
    25.     /** 
    26.      * 需要通过远程调用的服务 
    27.      */  
    28.     private String clazz;  
    29.   
    30.     private static HttpInvoke invoke = HttpInvoke.getInstance();  
    31.   
    32.     /** 
    33.      * 创建一个动态代理对象,创建出来的动态代理对象会执行invoke方法 
    34.      *  
    35.      * @return 
    36.      * @throws ClassNotFoundException 
    37.      */  
    38.     public Object create() throws ClassNotFoundException {  
    39.         Class interfaceClass = Class.forName(clazz);  
    40.         return Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[] { interfaceClass }, this);  
    41.     }  
    42.   
    43.     /** 
    44.      * 动态代理对象执行该方法 获取(类信息,方法,参数)通过序列化封装成请求报文,通过http请求发送报文到服务提供者 
    45.      */  
    46.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
    47.         // 获取类信息  
    48.         Class interfaceClass = proxy.getClass().getInterfaces()[0];  
    49.         // 封装成请求报文  
    50.         String req = JsonFormatter.reqFormatter(interfaceClass, method.getName(), args[0]);  
    51.         // 发送请求报文  
    52.         String resb = invoke.request(req, config);  
    53.         // 解析响应报文  
    54.         return JsonParser.resbParse(resb);  
    55.     }  
    56.   
    57.     public ConsumerConfig getConfig() {  
    58.         return config;  
    59.     }  
    60.   
    61.     public void setConfig(ConsumerConfig config) {  
    62.         this.config = config;  
    63.     }  
    64.   
    65.     public String getClazz() {  
    66.         return clazz;  
    67.     }  
    68.   
    69.     public void setClazz(String clazz) {  
    70.         this.clazz = clazz;  
    71.     }  
    72.   
    73. }  


    简单的RPC框架已经写好

    然后我们准备一个公共的接口jar

    pom里面什么依赖都没有

    HelloInterface.java

    [java] view plain copy
     
    1. package com.ibigsea.facade;  
    2.   
    3. import com.ibigsea.vo.People;  
    4.   
    5. /** 
    6.  * 定义一个接口,如此而已 
    7.  * @author bigsea 
    8.  * 
    9.  */  
    10. public interface HelloInterface {  
    11.   
    12.     public String speak(People people);  
    13.       
    14. }  


    People.java

    [java] view plain copy
     
    1. package com.ibigsea.vo;  
    2.   
    3. import java.io.Serializable;  
    4.   
    5. /** 
    6.  * 实体 
    7.  * @author bigsea 
    8.  * 
    9.  */  
    10. public class People implements Serializable {  
    11.   
    12.     private static final long serialVersionUID = 1L;  
    13.       
    14.     private String name;  
    15.   
    16.     public People() {  
    17.     }  
    18.   
    19.     public People(String name) {  
    20.         this.name = name;  
    21.     }  
    22.   
    23.     public String getName() {  
    24.         return name;  
    25.     }  
    26.   
    27.     public void setName(String name) {  
    28.         this.name = name;  
    29.     }  
    30.       
    31. }  


    接口定义好了 ,我们可以开始弄服务提供者和服务消费者了

    服务提供者


    pom.xml

    [java] view plain copy
     
    1. <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">  
    2.   <modelVersion>4.0.0</modelVersion>  
    3.   <groupId>com.ibigsea</groupId>  
    4.   <artifactId>demo-provider</artifactId>  
    5.   <version>0.0.1-SNAPSHOT</version>  
    6.   <dependencies>  
    7.     <dependency>    
    8.         <groupId>com.ibigsea</groupId>  
    9.         <artifactId>http-rpc</artifactId>  
    10.         <version>0.0.1-SNAPSHOT</version>  
    11.     </dependency>  
    12.     <dependency>    
    13.           <groupId>com.ibigsea</groupId>  
    14.           <artifactId>demo-facade</artifactId>  
    15.           <version>0.0.1-SNAPSHOT</version>  
    16.     </dependency>  
    17.   </dependencies>  
    18. </project>  

    HelloService.java

    [java] view plain copy
     
    1. package com.ibigsea.service;  
    2.   
    3. import org.springframework.stereotype.Service;  
    4.   
    5. import com.ibigsea.facade.HelloInterface;  
    6. import com.ibigsea.vo.People;  
    7.   
    8. /** 
    9.  * 实现接口,通过spring配置文件,暴漏出一个服务 
    10.  * @author bigsea 
    11.  * 
    12.  */  
    13. @Service("helloInterface")  
    14. public class HelloService implements HelloInterface {  
    15.   
    16.     /** 
    17.      * 方法实现,服务消费者最终执行到该方法 
    18.      */  
    19.     public String speak(People people) {  
    20.         return "Hello " + people.getName();  
    21.     }  
    22.   
    23. }   

    启动类App.java

    [java] view plain copy
     
    1. package com.ibigsea;  
    2.   
    3. import java.util.concurrent.CountDownLatch;  
    4.   
    5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
    6.   
    7. /** 
    8.  * 启动类 
    9.  * @author bigsea 
    10.  * 
    11.  */  
    12. public class App {  
    13.       
    14.      public static void main(String[] args) throws Exception {  
    15.          ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring-*.xml");  
    16.          context.start();  
    17.          CountDownLatch countDownLatch = new CountDownLatch(1);  
    18.          countDownLatch.await();  
    19.      }  
    20.       
    21. }   

    spring-context.xml

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"  
    4.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"  
    5.     xmlns:util="http://www.springframework.org/schema/util"  
    6.     xsi:schemaLocation="  
    7.           http://www.springframework.org/schema/beans  
    8.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    9.        http://www.springframework.org/schema/tx  
    10.        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
    11.        http://www.springframework.org/schema/aop  
    12.        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
    13.        http://www.springframework.org/schema/util  
    14.        http://www.springframework.org/schema/util/spring-util-3.1.xsd  
    15.        http://www.springframework.org/schema/context  
    16.        http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
    17.   
    18.   
    19.     <!-- 扫描包 -->  
    20.     <context:component-scan base-package="com.ibigsea" />  
    21.     <!-- 支持注解配置 -->  
    22.     <context:annotation-config />  
    23.   
    24.     <!-- 构造注入,声明需要暴漏的服务. 还有需要监听的地址 -->  
    25.     <bean class="com.ibigsea.rpc.proxy.ProviderProxyFactory">  
    26.         <constructor-arg name="providers">  
    27.             <map key-type="java.lang.Class" value-type="java.lang.Object">  
    28.                 <!-- 注册服务,类信息,和接口实现 -->  
    29.                 <entry key="com.ibigsea.facade.HelloInterface" value-ref="helloInterface"/>  
    30.             </map>  
    31.         </constructor-arg>  
    32.         <constructor-arg name="config">  
    33.             <bean id="providerConfig" class="com.ibigsea.rpc.config.ProviderConfig">  
    34.                 <property name="port" value="8888"/>  
    35.             </bean>  
    36.         </constructor-arg>  
    37.     </bean>  
    38.   
    39. </beans>  

    服务消费者



    pom.xml

    [html] view plain copy
     
    1. <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">  
    2.   <modelVersion>4.0.0</modelVersion>  
    3.   <groupId>com.ibigsea</groupId>  
    4.   <artifactId>demo-comsumer</artifactId>  
    5.   <version>0.0.1-SNAPSHOT</version>  
    6.     
    7.   <dependencies>  
    8.     <dependency>    
    9.         <groupId>com.ibigsea</groupId>  
    10.         <artifactId>http-rpc</artifactId>  
    11.         <version>0.0.1-SNAPSHOT</version>  
    12.     </dependency>  
    13.     <dependency>    
    14.           <groupId>com.ibigsea</groupId>  
    15.           <artifactId>demo-facade</artifactId>  
    16.           <version>0.0.1-SNAPSHOT</version>  
    17.     </dependency>  
    18.         <dependency>  
    19.             <groupId>junit</groupId>  
    20.             <artifactId>junit</artifactId>  
    21.             <version>4.11</version>  
    22.         </dependency>  
    23.         <dependency>  
    24.             <groupId>org.springframework</groupId>  
    25.             <artifactId>spring-test</artifactId>  
    26.             <version>3.2.8.RELEASE</version>  
    27.             <scope>test</scope>  
    28.         </dependency>  
    29.   </dependencies>  
    30.     
    31. </project>  

    RefService.java

    [java] view plain copy
     
    1. package com.ibigsea.comsumer;  
    2.   
    3. import javax.annotation.Resource;  
    4.   
    5. import org.springframework.stereotype.Service;  
    6.   
    7. import com.ibigsea.facade.HelloInterface;  
    8. import com.ibigsea.vo.People;  
    9.   
    10. @Service("refService")  
    11. public class RefService {  
    12.       
    13.     //这里引用到的是java生成的代理对象  
    14.     @Resource  
    15.     private HelloInterface helloInterface;  
    16.       
    17.     public void sayHello(String name) {  
    18.         System.out.println(helloInterface.speak(new People(name)));  
    19.     }  
    20.       
    21. }   

    spring-context.xml

    [html] view plain copy
     
    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"  
    4.        xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"  
    5.        xmlns:util="http://www.springframework.org/schema/util"  
    6.        xsi:schemaLocation="  
    7.           http://www.springframework.org/schema/beans  
    8.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    9.        http://www.springframework.org/schema/tx  
    10.        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd  
    11.        http://www.springframework.org/schema/aop  
    12.        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd  
    13.        http://www.springframework.org/schema/util  
    14.        http://www.springframework.org/schema/util/spring-util-3.1.xsd  
    15.        http://www.springframework.org/schema/context  
    16.        http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
    17.   
    18.     <context:component-scan base-package="com.ibigsea" />  
    19.     <context:annotation-config />  
    20.   
    21. <!--     服务消费者请求的地址 -->  
    22.     <bean id="consumerConfig" class="com.ibigsea.rpc.config.ConsumerConfig">  
    23.         <property name="url" value="http://localhost:8888/invoke" />  
    24.     </bean>  
    25.   
    26. <!-- 设置请求地址,需要生成代理的代理对象 -->  
    27.     <bean id="helloInterfaceInvoke" class="com.ibigsea.rpc.proxy.ConsumerProxyFactory">  
    28.         <property name="config" ref="consumerConfig"/>  
    29.         <property name="clazz" value="com.ibigsea.facade.HelloInterface"/>  
    30.     </bean>  
    31. <!--    产生代理对象,服务消费者可以直接通过@Resource注解引用到该对象,通过http-rpc框架调用到服务消费者 -->  
    32.     <bean id="helloInterface" factory-bean="helloInterfaceInvoke" factory-method="create"/>  
    33. </beans>  

    测试类HttpRpcTest.java

    [java] view plain copy
     
    1. package com.zto.test;  
    2.   
    3. import org.junit.Test;  
    4. import org.junit.runner.RunWith;  
    5. import org.slf4j.Logger;  
    6. import org.slf4j.LoggerFactory;  
    7. import org.springframework.beans.factory.annotation.Autowired;  
    8. import org.springframework.test.context.ContextConfiguration;  
    9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
    10.   
    11. import com.ibigsea.comsumer.RefService;  
    12. import com.ibigsea.facade.HelloInterface;  
    13. import com.ibigsea.rpc.serizlize.JsonFormatter;  
    14.   
    15. /** 
    16.  * 测试类 
    17.  * @author bigsea 
    18.  * 
    19.  */  
    20. @RunWith(SpringJUnit4ClassRunner.class)  
    21. @ContextConfiguration({"classpath*:spring-*.xml"})  
    22. public class HttpRpcTest  
    23. {  
    24.     private static final Logger logger = LoggerFactory.getLogger(HttpRpcTest.class);  
    25.   
    26.     @Autowired  
    27.     private RefService service;  
    28.   
    29.     @Test  
    30.     public void test() throws InterruptedException {  
    31.         service.sayHello("张三");  
    32.     }  
    33. }  


    我们可以启动程序看看

    先启动服务提供者,服务提供者控制台

    [html] view plain copy
     
    1. 五月 01, 2017 2:43:43 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh  
    2. 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@685f4c2e: startup date [Mon May 01 14:43:43 CST 2017]; root of context hierarchy  
    3. 五月 01, 2017 2:43:43 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
    4. 信息: Loading XML bean definitions from file [E:workspace pcworkspacedemo-provider argetclassesspring-context.xml]  
    5. 五月 01, 2017 2:43:44 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons  
    6. 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@26be92ad: defining beans [helloInterface,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,com.ibigsea.rpc.proxy.ProviderProxyFactory#0,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy  
    7. 14:43:45.608 [main] INFO  org.mortbay.log - Logging to Logger[org.mortbay.log] via org.mortbay.log.Slf4jLog  
    8. 14:43:45.622 [main] DEBUG org.mortbay.log - Container Server@4562e04d + ProviderProxyFactory@2a65fe7c as handler  
    9. 14:43:45.622 [main] DEBUG org.mortbay.log - Container Server@4562e04d + SelectChannelConnector@0.0.0.0:8888 as connector  
    10. 14:43:45.622 [main] INFO  org.mortbay.log - jetty-6.1.26  
    11. 14:43:45.638 [main] DEBUG org.mortbay.log - Container Server@4562e04d + org.mortbay.thread.QueuedThreadPool@235834f2 as threadpool  
    12. 14:43:45.639 [main] DEBUG org.mortbay.log - started org.mortbay.thread.QueuedThreadPool@235834f2  
    13. 14:43:45.640 [main] DEBUG org.mortbay.log - starting ProviderProxyFactory@2a65fe7c  
    14. 14:43:45.640 [main] DEBUG org.mortbay.log - started ProviderProxyFactory@2a65fe7c  
    15. 14:43:45.640 [main] DEBUG org.mortbay.log - starting Server@4562e04d  
    16. 14:43:45.691 [main] DEBUG org.mortbay.log - started org.mortbay.jetty.nio.SelectChannelConnector$1@2b71e916  
    17. 14:43:45.692 [main] INFO  org.mortbay.log - Started SelectChannelConnector@0.0.0.0:8888  
    18. 14:43:45.693 [main] DEBUG org.mortbay.log - started SelectChannelConnector@0.0.0.0:8888  
    19. 14:43:45.693 [main] DEBUG org.mortbay.log - started Server@4562e04d  
    20. 14:43:45.693 [main] INFO  c.i.rpc.container.HttpContainer - 容器启动~  
    21. 14:43:45.693 [main] INFO  org.mortbay.log - HelloInterface register  


    然后执行服务消费者的测试方法,服务消费者控制台:

    [html] view plain copy
     
    1. 五月 01, 2017 2:44:31 下午 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners  
    2. 信息: Could not instantiate TestExecutionListener class [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their dependencies) available.  
    3. 五月 01, 2017 2:44:31 下午 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners  
    4. 信息: Could not instantiate TestExecutionListener class [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their dependencies) available.  
    5. 五月 01, 2017 2:44:31 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
    6. 信息: Loading XML bean definitions from file [E:workspace pcworkspacedemo-comsumer argetclassesspring-context.xml]  
    7. 五月 01, 2017 2:44:32 下午 org.springframework.context.support.GenericApplicationContext prepareRefresh  
    8. 信息: Refreshing org.springframework.context.support.GenericApplicationContext@7946e1f4: startup date [Mon May 01 14:44:32 CST 2017]; root of context hierarchy  
    9. 五月 01, 2017 2:44:32 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons  
    10. 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@4f51b3e0: defining beans [refService,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,consumerConfig,helloInterfaceInvoke,helloInterface,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy  
    11. Hello 张三  
    12. 五月 01, 2017 2:44:33 下午 org.springframework.context.support.GenericApplicationContext doClose  
    13. 信息: Closing org.springframework.context.support.GenericApplicationContext@7946e1f4: startup date [Mon May 01 14:44:32 CST 2017]; root of context hierarchy  


    服务提供者这里输出了消费者请求的日志

    [html] view plain copy
     
    1. 14:44:33.117 [348984985@qtp-592983282-1 - /invoke] DEBUG org.mortbay.log - REQUEST /invoke on org.mortbay.jetty.HttpConnection@6e01b90  
    2. 14:44:33.213 [348984985@qtp-592983282-1 - /invoke] DEBUG org.mortbay.log - RESPONSE /invoke  200  


    演示成功

    注意


    因为这里使用了fastjson,  而我们的Request里面有类信息,进行序列化和反序列的时候我们要在启动类增加参数

     -Dfastjson.parser.autoTypeSupport=true

    其他解决方案看这里

    https://github.com/alibaba/fastjson/wiki/enable_autotype

    好了,这里的代码我会上传到我的github上面

  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    Java面试题及解析
    Spring框架——IOC&DI
    Java项目开发流程()
    用户信息添加查重系统
    数据库对象——触发器、索引
    数据库对象——函数,视图,同义词,游标,包
  • 原文地址:https://www.cnblogs.com/csguo/p/7572984.html
Copyright © 2011-2022 走看看