目录
一、netty入门
二、启动方式
三、netty服务启动类
四、handler链
五、具体业务
六、 线程或者非spring管理的bean中获取spring管理的bean
七、效果
Netty-导学_哔哩哔哩_bilibili
入门视频量比较大,最主要是了解netty的架构
netty官网:
Netty.docs: User guide for 4.x
对springboot有入门级别会启动项目设置bean基本就可以完成了
maven依赖
org.springframework.boot
spring-boot-starter-parent
2.6.7
8
8
UTF-8
org.springframework.boot
spring-boot-starter-web
io.netty
netty-all
4.1.95.Final
mysql
mysql-connector-java
org.projectlombok
lombok
provided
com.google.code.gson
gson
2.10.1
com.baomidou
mybatis-plus-boot-starter
com.baomidou
mybatis-plus-generator
3.5.1
com.baomidou
mybatis-plus-extension
3.5.3.1
org.freemarker
freemarker
2.3.31
commons-io
commons-io
2.11.0
org.springframework.boot
spring-boot-starter-data-redis
com.github.ben-manes.caffeine
caffeine
org.apache.commons
commons-pool2
commons-codec
commons-codec
1.15
org.apache.commons
commons-lang3
3.12.0
org.apache.commons
commons-collections4
4.4
以web方式启动,tomcat占用80端口 netty占用9002端口
import com.xnetty.config.NettyServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
/**
* description: 以web的方式进行项目启动
*/
@SpringBootApplication
@Slf4j
public class XNettyApplication {
public static void main(String[] args) throws Exception {
ApplicationContext context = SpringApplication.run(XNettyApplication.class, args);
NettyServer nettyServer = context.getBean(NettyServer.class);
nettyServer.start();
log.info("XNettyApplication finish start....");
}
}
属性配置文件application.properties中配置
server.port=80
netty.server.port=9002
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
/**
* description:
*/
@Component
@Slf4j
public class NettyServer {
public void start() throws Exception {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
executor.setMaxPoolSize(200);
executor.setQueueCapacity(10000);
executor.setKeepAliveSeconds(60);
executor.setRejectedExecutionHandler((r, executor1) -> {
try {
executor1.getQueue().put(r);
log.info("执行了拒绝策略.....");
} catch (InterruptedException e) {
log.error("加入队列异常:{}", e.getMessage());
}
});
executor.setThreadGroupName("netty_request");
executor.initialize();
NioEventLoopGroup bossGroup = new NioEventLoopGroup(16);
NioEventLoopGroup workGroup = new NioEventLoopGroup(16);
try {
ChannelFuture channelFuture = new ServerBootstrap().group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.option(ChannelOption.ALLOCATOR, ByteBufAllocator.DEFAULT)
.childHandler(new ServerInit(executor))
.bind("0.0.0.0", port)
.sync();
Channel channel = channelFuture.channel();
channel.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
@Value("${netty.server.port}")
private int port;
}
import com.xnetty.service.ReadRequestHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* description:
*/
@Service
public class ServerInit extends ChannelInitializer {
private ThreadPoolTaskExecutor executor;
public ServerInit(ThreadPoolTaskExecutor executor) {
this.executor = executor;
}
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
ch.pipeline()
.addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS))
.addLast(new HttpServerCodec())
.addLast(new HttpObjectAggregator(5 * 1024 * 1024)) //大小为10M
.addLast(new MpHandler(executor));
}
}
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* description:
*/
public class MpHandler extends SimpleChannelInboundHandler {
ThreadPoolTaskExecutor executor;
public MpHandler(ThreadPoolTaskExecutor executor) {
this.executor = executor;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
String uri = request.uri();
if (uri.equals("/hello")) {
executor.execute(()->{
FullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(), HttpResponseStatus.OK, Unpooled.copiedBuffer("hello word", CharsetUtil.UTF_8)); // Unpooled.wrappedBuffer(responseJson)
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=UTF-8"); // HttpHeaderValues.TEXT_PLAIN.toString()
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
if (HttpUtil.isKeepAlive(request)) {
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
ctx.writeAndFlush(response);
});
} else {
executor.execute(() -> {
FullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(), HttpResponseStatus.OK, Unpooled.copiedBuffer("请求成功....", CharsetUtil.UTF_8)); // Unpooled.wrappedBuffer(responseJson)
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=UTF-8"); // HttpHeaderValues.TEXT_PLAIN.toString()
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
if (HttpUtil.isKeepAlive(request)) {
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
ctx.writeAndFlush(response);
});
}
}
}
至于如何在非spring管理的bean中获取spring管理的对象或者在线程中获取spring管理的bean,则自定义一个beanutils获取
如下
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringBeanUtils implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static Object getBean(String name) {
return context.getBean(name);
}
public static T getBean(Class clazz) {
return context.getBean(clazz);
}
public static T getBeanByName(String beanName, Class clazz) {
return context.getBean(beanName, clazz);
}
}
七http://localhost:9002/hello