沉淀、分享、成长,让自己和他人都能有所收获。专注于原创专题案例编写,目前已完成的专题有;Netty4.x实战专题案例、用Java实现JVM、基于JavaAgent的全链路监控、手写RPC框架、架构设计专题案例、源码分析等。你用剑 、我用刀 ,好的代码都很烧,望你不吝出招!
一、前言介绍
在实际的开发场景中,我们希望将大量的业务以及用户行为数据存储起来用于分析处理,但是由于数据量较大且需要具备可分析功能所以将数据存储到文件系统更为合理。尤其是一些互联网高并发级应用,往往数据库都采用分库分表设计,那么将这些分散的数据通过binlog汇总到一个统一的文件系统就显得非常有必要。
二、开发环境jdk1.8【jdk1.7以下只能部分支持netty】
Netty4.1.36.Final【netty3.x 4.x 5每次的变化较大,接口类名也随着变化】
elasticsearch6.2.2
三、代码示例
itstack-demo-netty-2-06
└── src
├── main
│ ├── java
│ │ └── org.itstack.demo.netty
│ │ ├── codec
│ │ │ ├── ObjDecoder.java
│ │ │ └── ObjEncoder.java
│ │ ├── domain
│ │ │ ├── TransportProtocol.java
│ │ │ └── User.java
│ │ ├── server
│ │ │ ├── MyChannelInitializer.java
│ │ │ ├── MyServerHandler.java
│ │ │ └── NettyServer.java
│ │ ├── service
│ │ │ ├── impl
│ │ │ │ └── UserServiceImpl.java
│ │ │ ├── UserRepository.java
│ │ │ └── UserService.java
│ │ ├── util
│ │ │ └── SerializationUtil.java
│ │ ├── web
│ │ │ └── NettyController.java
│ │ └── Application.java
│ └── resources
│ └── application.yml
│
└── test
└── java
└── org.itstack.demo.test
└── ApiTest.java
演示部分重点代码块,完整代码下载关注公众号;bugstack虫洞栈domain/User.java
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 {获取学习源码}
* Create by fuzhengwei on 2019
*/
@Document(indexName = "stack", type = "group_user")
public class User {
@Id
private String id;
private String name; //姓名
private Integer age; //年龄
private String level; //级别
private Date entryDate;//时间
private String mobile; //电话
private String email; //邮箱
private String address;//地址
public User(String id, String name, Integer age, String level, Date entryDate, String mobile, String email, String address) {
this.id = id;
this.name = name;
this.age = age;
this.level = level;
this.entryDate = entryDate;
this.mobile = mobile;
this.email = email;
this.address = address;
}
... get/set
}server/MyServerHandler.java
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 {获取学习源码}
* Create by fuzhengwei on 2019
*/
@Service("myServerHandler")
public class MyServerHandler extends ChannelInboundHandlerAdapter {
private Logger logger = LoggerFactory.getLogger(MyServerHandler.class);
@Autowired
private UserService userService;
/**
* 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
SocketChannel channel = (SocketChannel) ctx.channel();
logger.info("链接报告开始");
logger.info("链接报告信息:有一客户端链接到本服务端");
logger.info("链接报告IP:{}", channel.localAddress().getHostString());
logger.info("链接报告Port:{}", channel.localAddress().getPort());
logger.info("链接报告完毕");
}
/**
* 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
logger.info("客户端断开链接{}", ctx.channel().localAddress().toString());
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//接收msg消息{与上一章节相比,此处已经不需要自己进行解码}
logger.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 服务端接收到消息:" + JSON.toJSONString(msg));
//接收数据写入到Elasticsearch
TransportProtocol transportProtocol = (TransportProtocol) msg;
userService.save((User) transportProtocol.getObj());
}
/**
* 抓住异常,当发生异常的时候,可以做一些相应的处理,比如打印日志、关闭链接
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
logger.info("异常信息&#x