长连网关通过调用RPC接口,将上行消息直接透传给API处理层。
在API处理层,首先会根据 Header 中声明的接口信息,通过反射调用相应的Controller中的 method,长连网关层就类似 SpringMVC 的 DispatcherServlet,而API层的处理就类似 @RequestMapping所做的事情。
首先,定义注解,用来标识一个方法。
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)
 public @interface DispatcherURL {
 
 String value();
 
 
 String tag();
 }
 
 | 
再定义一个对象,用来表示一个url - tag - bean - method的关系。
| 12
 3
 4
 5
 6
 7
 
 | @Datapublic class DispatcherMapping {
 private String url;
 private String tag;
 private Object bean;
 private String method;
 }
 
 | 
基于SpringBoot来实现,容器初始化完成将会初始化映射关系。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 
 | import com.google.common.collect.Maps;import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationListener;
 import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.stereotype.Component;
 import org.springframework.util.ReflectionUtils;
 
 import java.util.Arrays;
 import java.util.Map;
 
 
 
 
 @Component
 public class Initializer implements ApplicationListener<ContextRefreshedEvent> {
 public static Map<String, DispatcherMapping> urlDispatcherMappingMap = Maps.newHashMap();
 
 @Override
 public void onApplicationEvent(ContextRefreshedEvent event) {
 ApplicationContext context = event.getApplicationContext();
 if (context != null) {
 String[] beanNames = context.getBeanDefinitionNames();
 Arrays.stream(beanNames).forEach(beanName -> {
 Object bean = context.getBean(beanName);
 ReflectionUtils.doWithMethods(bean.getClass(), method -> {
 if (method.isAnnotationPresent(DispatcherURL.class)) {
 DispatcherMapping dispatcherMapping = new DispatcherMapping();
 DispatcherURL dispatcherURL = method.getAnnotation(DispatcherURL.class);
 dispatcherMapping.setUrl(dispatcherURL.value());
 dispatcherMapping.setTag(dispatcherURL.tag());
 dispatcherMapping.setBean(bean);
 dispatcherMapping.setMethod(method.getName());
 urlDispatcherMappingMap.put(dispatcherMapping.getTag(), dispatcherMapping);
 }
 });
 });
 }
 }
 }
 
 | 
声明一个方法大概如下:
| 12
 3
 4
 5
 6
 7
 8
 
 | @Controllerpublic class TestController {
 @DispatcherURL(value = "/say", tag = "(1,0)")
 public String say(Map<Integer, Object> header, Map<Integer, Object> body) {
 
 return "Hello world";
 }
 }
 
 | 
RPC服务端如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | import org.springframework.stereotype.Service;
 import java.lang.reflect.Method;
 import java.util.Map;
 
 
 
 
 @Service
 public class RpcService {
 
 public Object invoke(Map<Integer, Object> headerMap, Map<Integer, Object> bodyMap) {
 Object result = null;
 try {
 String tag = getTagFromHeader(headerMap);
 DispatcherMapping dispatcherMapping = Initializer.urlDispatcherMappingMap.get(tag);
 if (dispatcherMapping == null) {
 
 return null;
 }
 Class bean = dispatcherMapping.getBean().getClass();
 Method method = bean.getDeclaredMethod(dispatcherMapping.getMethod(), new Class[]{Map.class, Map.class});
 result = method.invoke(bean, headerMap, bodyMap);
 } catch (Exception e) {
 e.printStackTrace();
 }
 return result;
 }
 
 private String getTagFromHeader(Map<Integer, Object> headerMap) {
 
 return "(" + headerMap.get(1) + "," + headerMap.get(2) + ")";
 }
 }
 
 | 
最终,客户端只需要在headerMap中传入tag,在bodyMap中传入业务参数,通过简单的RPC透传调用,即可实现网关通用性,一旦有新的接口上线,只需要修改API处理层即可。