博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Lolttery】项目开发日志 (一) 微服务框架搭建
阅读量:5876 次
发布时间:2019-06-19

本文共 4978 字,大约阅读时间需要 16 分钟。

公司最新的项目Lolttery已经开始动工了。

因为微服务很火,之前专门研究了一阵子。决定在新项目中采用微服务结构。在此博客开始记录学习和开发的问题和进步。

采用Netty+Spring+mybatis的核心框架,内部通信使用socket tcp通信。协议为json。同时用Spring MVC做对外的http接口。数据库采用Mysql+Redis。

唉……反正说来说去服务器+web端都是我自己一个人的活,用什么技术完全不用讨论啊……

个人经验也不是很丰富,本系列博客作为学习日志和踩坑笔记,欢迎各路大神拍砖指正。


##第一篇:实现netty服务 框架的骨架是netty服务,netty是优秀的异步网络处理框架,通过各种Handle可以适应不同的网络协议。同时又不依赖于tomcat等中间件,是实现微服务的合适选择。

实现netty服务基本照搬了官网的源码。

在启动器中包含了spring的初始化,netty的启动和服务的注册。

/** * 启动器 * Created by shizhida on 16/3/15. */public class Bootstrap {    private int port = 2333;    public static String serverName = "";    private Logger logger = LoggerFactory.getLogger(Bootstrap.class);    public Bootstrap(int port){        //在初始化启动器时获取spring的上下文。        ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);        //将上下文加入到一个全局的变量中便于使用        Application.setApplicationContext(context);        this.port = port;    }    /**     * 在redis中注册本服务,以便被客户端获取     * @param host     * @param serverName     * @return     */    public Bootstrap register(String host,String serverName){        RedisDao redisDao = new RedisDao("localhost");        Map
info = new HashMap<>(); info.put("ip",host); info.put("port",port+""); this.serverName = serverName; redisDao.getJedis().hmset(serverName,info); return this; } /** * netty启动 * @throws Exception */ public void run() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer
() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast( new JsonDecoder(), new DispatchHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(port).sync(); //保存至全局变量,便于关闭服务 Application.future = f; logger.info("start service bin port " + port); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) { try { new Bootstrap(2333).register("locahost","server").run(); } catch (Exception e) { e.printStackTrace(); } }}复制代码

完成启动器之后,是协议的解析

为了避免出现粘包、半包等情况,协议采用4byte报文长度+json字符串的方式进行传输。

json包括header、body和foot三个部分,header包含了serviceName,serviceCode等请求信息,body为请求的参数,foot包含了来源、校验码等相关信息

自行编写了解析器如下,json解析使用阿里的fastjson库

protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception {        //若可读取长度不足4字节,不进行读取        if(in.readableBytes()<4)        {            logger.debug("长度不足,可读取长度为:" + in.readableBytes());            return;        }        byte[] byte_length = new byte[4];         in.readBytes(byte_length);        //读取报文长度        int length = BUtil.bytes2int(byte_length,0);        //若可读取长度小于约定长度,则不读取        if(in.readableBytes()

然后是服务的分发。

一个服务中也可以细分为多个业务。设计上使用serviceName和serviceCode来确定一个具体的业务。serviceName用于服务注册,可以获取到服务的ip和端口信息。serviceCode用于服务内部的业务具体划分。

利用spring框架的功能,服务分发可以做的很简单: netty处理:

public void channelRead(ChannelHandlerContext ctx, Object msg) {         //分发并处理请求        XORequest request = (XORequest) msg;        logger.info("-------------request start ------------");        logger.info("request to "+request.getServiceName());        logger.info("request at "+new Date(request.getRequestDate()));        logger.info("request for "+request.getServiceCode());        XOResponse result = dispatcher.dispatch(request);        //组装处理结果        byte[] json = result.toString().getBytes();        ByteBuf byteBuf = ctx.alloc().buffer(json.length);        byteBuf.writeBytes(json);        //发送给客户端        final ChannelFuture f = ctx.writeAndFlush(byteBuf);                 f.addListener(new ChannelFutureListener() {                        public void operationComplete(ChannelFuture future) {                assert f == future;                ctx.close();                logger.info("request process done");            }        });    }复制代码

分发服务:(dispatcher)

public XOResponse dispatch(XORequest request) { String service_code = request.getServiceCode(); XOService service = Application.applicationContext.getBean(service_code,XOService.class); return service.run(request); }

默认所有的服务都实现XOService接口,利用spring的Service("serviceCode")注解就可以简单的实现服务的分发。通过两层分发器、通用协议和服务接口。在这里就实现了业务逻辑与框架功能的高度分离。实现业务逻辑只需要添加更多的XOService接口的实例,就可以扩展业务逻辑。 在每个服务上依赖此框架,实现一个Bootstrap启动器,并添加Service等业务逻辑代码即可完成一个新的服务。复制代码

转载地址:http://ickix.baihongyu.com/

你可能感兴趣的文章
PHP - 如何打印函数调用树
查看>>
js闭包
查看>>
寒假。3.3.G - Common Child (最大公共子序)
查看>>
设计模式学习笔记--原型模式
查看>>
.Net 通过MySQLDriverCS操作MySQL
查看>>
JS Cookie
查看>>
ubuntu Unable to locate package sysv-rc-conf
查看>>
笔记:认识.NET平台
查看>>
cocos2d中CCAnimation的使用(cocos2d 1.0以上版本)
查看>>
【吉光片羽】短信验证
查看>>
MacBook如何用Parallels Desktop安装windows7/8
查看>>
gitlab 完整部署实例
查看>>
GNS关于IPS&ASA&PIX&Junos的配置
查看>>
七天学会ASP.NET MVC (四)——用户授权认证问题
查看>>
upgrade to iOS7,how to remove stroyboard?
查看>>
影响企业信息化成败的几点因素
查看>>
SCCM 2016 配置管理系列(Part8)
查看>>
zabbix监控部署
查看>>
struts中的xwork源码下载地址
查看>>
Android硬件抽象层(HAL)深入剖析(二)
查看>>