长连网关通过调用RPC接口,将上行消息直接透传给API处理层。
在API处理层,首先会根据 Header
中声明的接口信息,通过反射调用相应的Controller
中的 method
,长连网关层就类似 SpringMVC
的 DispatcherServlet
,而API层的处理就类似 @RequestMapping
所做的事情。
首先,定义注解,用来标识一个方法。
1 2 3 4 5 6 7 8 9
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DispatcherURL { String value();
String tag(); }
|
再定义一个对象,用来表示一个url - tag - bean - method
的关系。
1 2 3 4 5 6 7
| @Data public class DispatcherMapping { private String url; private String tag; private Object bean; private String method; }
|
基于SpringBoot
来实现,容器初始化完成将会初始化映射关系。
1 2 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); } }); }); } } }
|
声明一个方法大概如下:
1 2 3 4 5 6 7 8
| @Controller public class TestController { @DispatcherURL(value = "/say", tag = "(1,0)") public String say(Map<Integer, Object> header, Map<Integer, Object> body) { return "Hello world"; } }
|
RPC服务端如下:
1 2 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处理层即可。