(1) 启动是重写 CommandLineRunner
(2) 写NettyServerListener Component
(3) 实现 TdgisnettyApplication run 方法
主要实现在SpringApplication 启动后启动NettyServer
下面是代码
@Component
public class NettyServerListener {
private static final Logger LOGGER = LoggerFactory.getLogger( NettyServerListener.class );
/**
* 创建bootstrap
*/
ServerBootstrap serverBootstrap = new ServerBootstrap();
/**
* BOSS
*/
EventLoopGroup boss = new NioEventLoopGroup();
/**
* Worker
*/
EventLoopGroup work = new NioEventLoopGroup();
/**
* 通道适配器
*/
@Resource
private ServerChannelHandlerAdapter channelHandlerAdapter;
@Resource
private NettyConfig nettyConfig;
@PreDestroy
public void close() {
LOGGER.info("关闭服务器....");
//优雅退出
boss.shutdownGracefully();
work.shutdownGracefully();
}
/**
* 开启及服务线程
*/
public void start() {
// 从配置文件中(application.yml)获取服务端监听端口号
int port = nettyConfig.getPort();
serverBootstrap.group(boss, work)
.channel(NioServerSocketChannel.class)
.option( ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler( LogLevel.INFO));
try {
//设置事件处理
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(nettyConfig.getMaxFrameLength()
, 0, 2, 0, 2));
pipeline.addLast(new LengthFieldPrepender(2));
pipeline.addLast(new ObjectCodec());
pipeline.addLast(channelHandlerAdapter);
}
});
LOGGER.info("netty服务器在[{}]端口启动监听", port);
ChannelFuture f = serverBootstrap.bind(port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
LOGGER.info("[出现异常] 释放资源");
boss.shutdownGracefully();
work.shutdownGracefully();
}
}
}
//ChannelHandlerAdapter 负责数据进入并在ChannelPipeline中按照从上至下的顺序查找调用相应的BoundHandler
@Component
@ChannelHandler.Sharable
public class ServerChannelHandlerAdapter extends ChannelHandlerAdapter {
private Logger logger = LoggerFactory.getLogger( ServerChannelHandlerAdapter.class);
@Resource
private RequestDispatcher dispatcher;
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
MethodInvokeMeta invokeMeta = (MethodInvokeMeta) msg;
// 屏蔽toString()方法
if (invokeMeta.getMethodName().endsWith("toString()")
&& !"class java.lang.String".equals(invokeMeta.getReturnType().toString()))
logger.info("客户端传入参数 :{},返回值:{}",
invokeMeta.getArgs(), invokeMeta.getReturnType());
dispatcher.dispatcher(ctx, invokeMeta);
}
}
//通过线程池来处理多用户请求的消息,回复消息
@Component
public class RequestDispatcher implements ApplicationContextAware {
private ExecutorService executorService = Executors.newFixedThreadPool(NettyConstant.getMaxThreads());
private ApplicationContext app;
public void dispatcher(final ChannelHandlerContext ctx, final MethodInvokeMeta invokeMeta) {
executorService.submit(() -> {
ChannelFuture f = null;
try {
Class<?> interfaceClass = invokeMeta.getInterfaceClass();
String name = invokeMeta.getMethodName();
Object[] args = invokeMeta.getArgs();
Class<?>[] parameterTypes = invokeMeta.getParameterTypes();
Object targetObject = app.getBean(interfaceClass);
Method method = targetObject.getClass().getMethod(name, parameterTypes);
Object obj = method.invoke(targetObject, args);
if (obj == null) {
f = ctx.writeAndFlush(NullWritable.nullWritable());
} else {
f = ctx.writeAndFlush(obj);
}
f.addListener( ChannelFutureListener.CLOSE);
} catch (Exception e) {
ResponseResult error = ResponseResultUtil.error(ResponseCodeEnum.SERVER_ERROR);
f = ctx.writeAndFlush(error);
} finally {
f.addListener(ChannelFutureListener.CLOSE);
}
});
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.app = applicationContext;
}
}
//rpc 调用的处理类 MethodInvokeMeta
@Component
public class MethodInvokeMeta implements Serializable {
private static final long serialVersionUID = -3991505734959724273L;
//接口
private Class<?> interfaceClass;
//方法名
private String methodName;
//参数
private Object[] args;
//返回值类型
private Class<?> returnType;
//参数类型
private Class<?>[] parameterTypes;
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
public Class<?> getInterfaceClass() {
return interfaceClass;
}
public void setInterfaceClass(Class<?> interfaceClass) {
this.interfaceClass = interfaceClass;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Class[] getParameterTypes() {
return parameterTypes;
}
public void setParameterTypes(Class<?>[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
public Class getReturnType() {
return returnType;
}
public void setReturnType(Class returnType) {
this.returnType = returnType;
}
}
//空的异常处理
@Component
public class NullWritable implements Serializable {
private static final long serialVersionUID = 1857236694251465532L;
private static NullWritable instance = new NullWritable();
private NullWritable() {
}
public static NullWritable nullWritable() {
return instance;
}
}
// 消息序列化处理
public class ObjectCodec extends MessageToMessageCodec<ByteBuf, Object> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Object o, List<Object> list) throws Exception {
byte[] data = ObjectSerializerUtils.serilizer(o);
ByteBuf buf = Unpooled.buffer();
buf.writeBytes(data);
list.add(buf);
}
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
Object deSerilizer = ObjectSerializerUtils.deSerilizer(bytes);
list.add(deSerilizer);
}
}
public class ObjectSerializerUtils {
private static final Logger logger = LoggerFactory.getLogger(ObjectSerializerUtils.class);
/**
* 反序列化
*
* @param data
* @return
*/
public static Object deSerilizer(byte[] data) {
if (data != null && data.length > 0) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
} catch (Exception e) {
logger.info("[异常信息] {}", e.getMessage());
e.printStackTrace();
}
return null;
} else {
logger.info("[反序列化] 入参为空");
return null;
}
}
/**
* 序列化对象
*
* @param obj
* @return
*/
public static byte[] serilizer(Object obj) {
if (obj != null) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
oos.close();
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
} else {
return null;
}
}
}