模仿《netty4 核心核心原理》一书中的例子,通过netty 实现简单tomcat功能。
通过启动启动类,在浏览器输入对应的地址,实现访问:
具体代码如下:
- tomcat servlet类
public abstract class MServletNetty {
public void service(MRequestNetty request, MRsponseNetty response)throws Exception{
if("GET".equalsIgnoreCase(request.getMethod())){
doGet(request,response);
}else {
doPost(request,response);
}
}
public abstract void doGet(MRequestNetty request,MRsponseNetty response) throws Exception;
public abstract void doPost(MRequestNetty request,MRsponseNetty response) throws Exception;
}
2,tomcat servlet实现类=对应controller
public class FirstServletNetty extends MServletNetty {
@Override
public void doGet(MRequestNetty request, MRsponseNetty response) throws Exception {
this.doPost(request,response);
}
@Override
public void doPost(MRequestNetty request, MRsponseNetty response) throws Exception {
response.write("firstServletNetty");
}
}
3,tomcat servlet实现类2=对应controller
public class SecondServletNetty extends MServletNetty {
@Override
public void doGet(MRequestNetty request, MRsponseNetty response) throws Exception {
this.doPost(request,response);
}
@Override
public void doPost(MRequestNetty request, MRsponseNetty response) throws Exception {
response.write("SecondServletNetty");
}
}
4,请求体类
public class MRequestNetty {
private ChannelHandlerContext ctx;
private HttpRequest request;
public MRequestNetty(ChannelHandlerContext ctx, HttpRequest request) {
this.ctx = ctx;
this.request = request;
}
public String getUrl(){
return request.uri();
}
public String getMethod(){
return request.method().name();
}
}```
5,响应体类
public class MRsponseNetty {
private ChannelHandlerContext ctx;
private HttpRequest request;
public MRsponseNetty(ChannelHandlerContext ctx, HttpRequest request) {
this.ctx = ctx;
this.request = request;
}
public void write(String out)throws Exception{
try {
if(out == null || out.length()==0){
return;
}
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(out.getBytes(StandardCharsets.UTF_8)));
response.headers().set("Content-Type", "text/html;");
ctx.write(response);
}catch (Exception e){
e.printStackTrace();
}finally {
ctx.flush();
ctx.close();
}
}
}
6,tomcat 核心类-启动类
public class MTomcatNetty {
private int port = 8080;
private ServerSocket serverSocket;
private Map<String, MServletNetty> servletMapping = new HashMap<>();
private Properties webXml = new Properties();
private void init(){
try {
// 模拟加载配置文件
String path = this.getClass().getResource("/").getPath();
FileInputStream fileInputStream = new FileInputStream(path + "configNetty.properties");
webXml.load(fileInputStream);
for (Object o : webXml.keySet()) {
String key = o.toString();
if(key.endsWith(".url")){
String servletName = key.replaceAll("\\.url$", "");
String url = webXml.getProperty(key);
String className = webXml.getProperty(servletName + ".className");
MServletNetty servlet = (MServletNetty) Class.forName(className).newInstance();
servletMapping.put(url, servlet);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
public void start(){
init();
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workGroup = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new HttpResponseEncoder());
socketChannel.pipeline().addLast(new HttpRequestDecoder());
socketChannel.pipeline().addLast(new MtomcatHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture channelFuture = serverBootstrap.bind(this.port).sync();
System.out.println("Mtomcat 已启动,监听的端口是:"+port);
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
new MTomcatNetty().start();
}
public class MtomcatHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)throws Exception{
if (msg instanceof HttpRequest) {
System.out.println("channel Read");
HttpRequest req = (HttpRequest) msg;
MRequestNetty request = new MRequestNetty(ctx,req);
MRsponseNetty response = new MRsponseNetty(ctx,req);
String url = request.getUrl();
if(servletMapping.containsKey(url)){
servletMapping.get(url).service(request,response);
}else {
response.write("404-not found");
}
}
}
}
}
7 配置文件:
servlet.one.url=/firstServlet.do
servlet.one.className=com.test.zlb.NettyBase.FirstServletNetty
servlet.two.url=/secondServlet.do
servlet.two.className=com.test.zlb.NettyBase.SecondServletNetty
8,项目结构: