发现了yar 这个东西, motan新增了 YarRpcProtocol 这个协议,主要支持php序列化。
来学习下yar协议的具体实现
从代码中看出,支持exporter,不支持refer 因为其走的http协议,所以php直接rest方式调用就行
@SpiMeta(name = "yar")
public class YarRpcProtocol extends AbstractProtocol {
private ConcurrentHashMap<String, ProviderMessageRouter> ipPort2RequestRouter = new ConcurrentHashMap<String, ProviderMessageRouter>();
@Override
protected <T> Exporter<T> createExporter(Provider<T> provider, URL url) {
return new YarExporter<T>(url, provider, this);
}
@Override
protected <T> Referer<T> createReferer(Class<T> clz, URL url, URL serviceUrl) {
//TODO
throw new MotanFrameworkException("not yet implemented!");
}
public ProviderMessageRouter initRequestRouter(URL url, Provider<?> provider) {
String ipPort = url.getServerPortStr();
ProviderMessageRouter requestRouter = ipPort2RequestRouter.get(ipPort);
if (requestRouter == null) {
ipPort2RequestRouter.putIfAbsent(ipPort, new YarMessageRouter());
requestRouter = ipPort2RequestRouter.get(ipPort);
}
requestRouter.addProvider(provider);
return requestRouter;
}
public void unexport(URL url, Provider<?> provider){
String protocolKey = MotanFrameworkUtil.getProtocolKey(url);
String ipPort = url.getServerPortStr();
Exporter<?> exporter = (Exporter<?>) exporterMap.remove(protocolKey);
if (exporter != null) {
exporter.destroy();
}
synchronized (ipPort2RequestRouter) {
ProviderMessageRouter requestRouter = ipPort2RequestRouter.get(ipPort);
if (requestRouter != null) {
requestRouter.removeProvider(provider);
}
}
LoggerUtil.info("yarRpcExporter unexport Success: url={}", url);
}
}
接着看endpointFactory,具体的实现类是netty4yar
@SpiMeta(name = "netty4yar")
public class Netty4YarEndpointFactory extends AbstractEndpointFactory {
@Override
protected Server innerCreateServer(URL url, MessageHandler messageHandler) {
return new Netty4HttpServer(url, new YarMessageHandlerWarpper(messageHandler));
}
@Override
protected Client innerCreateClient(URL url) {
// TODO
throw new MotanFrameworkException("not yet implemented!");
}
}
看netty的server的initchannel
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("http-decoder", new HttpRequestDecoder());
ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(maxContentLength));
ch.pipeline().addLast("http-encoder", new HttpResponseEncoder());
ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
ch.pipeline().addLast("serverHandler", handler);
}
}).option(ChannelOption.SO_BACKLOG, 1024).childOption(ChannelOption.SO_KEEPALIVE, false);
接着看看handler
public class YarMessageHandlerWarpper implements MessageHandler {
private YarMessageRouter orgHandler;
public YarMessageHandlerWarpper(MessageHandler orgHandler) {
if (orgHandler == null) {
throw new MotanFrameworkException("messageHandler is null!");
}
if (orgHandler instanceof YarMessageRouter) {
this.orgHandler = (YarMessageRouter) orgHandler;
} else {
throw new MotanFrameworkException("YarMessageHandlerWarper can not wrapper " + orgHandler.getClass().getSimpleName());
}
}
@Override
public Object handle(Channel channel, Object message) {
FullHttpRequest httpRequest = (FullHttpRequest) message;
String uri = httpRequest.getUri();
int index = uri.indexOf("?");// should not be null
String requestPath = uri;
Map<String, String> attachments = null;
if (index > -1) {
requestPath = uri.substring(0, index);
if (index != uri.length() - 1) {
attachments = getAttachMents(uri.substring(index + 1, uri.length()));
}
}
YarResponse yarResponse = null;
String packagerName = "JSON";
try {
ByteBuf buf = httpRequest.content();
final byte[] contentBytes = new byte[buf.readableBytes()];
buf.getBytes(0, contentBytes);
YarRequest yarRequest = new AttachmentRequest(YarProtocol.buildRequest(contentBytes), attachments);
yarRequest.setRequestPath(requestPath);
yarResponse = (YarResponse) orgHandler.handle(channel, yarRequest);
} catch (Exception e) {
LoggerUtil.error("YarMessageHandlerWarpper handle yar request fail.", e);
yarResponse = YarProtocolUtil.buildDefaultErrorResponse(e.getMessage(), packagerName);
}
byte[] responseBytes;
try {
responseBytes = YarProtocol.toProtocolBytes(yarResponse);
} catch (IOException e) {
throw new MotanFrameworkException("convert yar response to bytes fail.", e);
}
FullHttpResponse httpResponse =
new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(responseBytes));
httpResponse.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/x-www-form-urlencoded");
httpResponse.headers().set(HttpHeaders.Names.CONTENT_LENGTH, httpResponse.content().readableBytes());
if (HttpHeaders.isKeepAlive(httpRequest)) {
httpResponse.headers().set(HttpHeaders.Names.CONNECTION, Values.KEEP_ALIVE);
} else {
httpResponse.headers().set(HttpHeaders.Names.CONNECTION, Values.CLOSE);
}
return httpResponse;
}
private Map<String, String> getAttachMents(String params) {
Map<String, String> map = new HashMap<String, String>();
String[] paramArray = params.split("&");
for (String param : paramArray) {
String[] kv = param.split("=");
if (kv.length == 2) {
map.put(kv[0], kv[1]);
} else {
LoggerUtil.warn("yar attachment parse fail. uri param:" + param);
}
}
return map;
}
}