JDK動態代理在RPC框架中的應用

RPC框架中通常都有3個角色:服務提供者、服務消費者和註冊中心。服務提供者將服務註冊到註冊中心,服務消費者從註冊中心拉取服務的地址,並根據服務地址向服務提供者發起RPC調用。動態代理在這個RPC調用的過程當中有什麼做用?對於服務消費者,通常只會依賴服務接口,而服務的具體實現是在服務提供者這一端的,服務消費者和服務提供者分別部署在不一樣的機器上,服務消費者調用接口中的方法時怎麼可以獲得結果呢?JDK的動態代理就派上用場了。服務消費者使用JDK的動態代理技術,能夠建立接口的代理對象,並在回調函數中將本身要調用的接口名稱、方法簽名信息經過http或者tcp的方式發送給服務提供者,服務提供者再經過反射的方式調用本地的服務,最後將結果經過http或tcp的方式返回給消費者。java

 

下面是一個簡單的演示程序:架構

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 import java.lang.reflect.Proxy;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 
 7 /**
 8  * 動態代理在RPC中的使用
 9  *
10  * @author syj
11  */
12 public class JDKProxyTest {
13 
14     // ---------------------------  模擬RPC客戶端  ---------------------------
15 
16     // 客戶端依賴服務端的接口(實現類在服務端)
17     private static IUserService userService;
18 
19     public static void main(String[] args) {
20         // 根據接口建立代理對象
21         userService = (IUserService) Proxy.newProxyInstance(
22                 JDKProxyTest.class.getClassLoader(),
23                 new Class[]{IUserService.class},
24                 new InvocationHandler() {
25                     // 在回調方法模擬進行RPC調用(經過http或者tcp與服務端通訊)
26                     @Override
27                     public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
28                         return rpcInvoke(IUserService.class.getSimpleName(), method.getName(), method.getParameterTypes(), params);
29                     }
30                 }
31         );
32         // 本地調用
33         String result = userService.sayHello("hello");
34         System.out.println(">>>> result =" + result);
35     }
36 
37 
38     // ---------------------------  模擬RPC服務端  ---------------------------
39 
40     /**
41      * 反射調用
42      *
43      * @param methodName     方法名稱
44      * @param parameterTypes 方法參數類型
45      * @param parameters     方法參數
46      * @return
47      */
48     private static Object rpcInvoke(String interfaceName, String methodName, Class<?>[] parameterTypes, Object[] parameters) {
49         Object result = null;
50         try {
51             // 根據接口名稱從Bean容器中獲取Bean實例
52             Object serviceBean = beanMap.get(interfaceName);
53             // 反射調用
54             Class<?> serviceClass = serviceBean.getClass();
55             Method method = serviceClass.getMethod(methodName, parameterTypes);
56             method.setAccessible(true);
57             // 獲得調用結果
58             result = method.invoke(serviceBean, parameters);
59         } catch (Exception e) {
60             e.printStackTrace();
61         }
62         return result;
63     }
64 
65     // 模擬Bean容器, key爲接口名稱, value爲bean實例
66     private static Map<String, Object> beanMap = new HashMap<String, Object>() {{
67         put("IUserService", new UserServiceImpl());
68     }};
69 }

接口(服務提供者和服務的消費者都會依賴該接口):框架

1 public interface IUserService {
2     String sayHello(String content);
3 }

服務提供者實現類:tcp

public class UserServiceImpl implements IUserService {
    @Override
    public String sayHello(String content) {
        return content + "::" + System.currentTimeMillis();
    }
}

 

其實,JDK的動態代理技術,不只能夠應用在RPC框架中,也能夠應用在全部基於客戶端和服務端通訊的架構中,好比微服務架構中的註冊中心、配置中心、消息中心等。ide

相關文章
相關標籤/搜索