What is a servlet

A servlet is one of JavaEE’s web specifications, which is simply a specification that defines the processing of network requests. When it comes to code, it’s an interface. The following methods are defined:

  • init
  • destory
  • service
  • getServletConfig
  • getServletInfo

That means that all the [JAVA] guys handling network requests need to inherit and implement me, or you don’t do any network requests at all.

That’s the picture below.

1.1 Why define standard Interfaces

You can write it yourself or not, yes, everyone can define a standard and a method. But then everybody might define a standard and a norm. Conversely, it is not a standard and is not conducive to the evolution and maintenance of the entire technology. So everyone complies with JavaEE defined interface standards, and you have servlet containers implemented by web container vendors such as tomcat,jetty, etc.

How to write a Tomcat servlet container by yourself

Here’s the basic Tomcat workflow.

1) The received request is transmitted to the Servlet container 3) the Servlet container obtains the specified request Servlet instance through the assembled Servlet 4) the Servlet instance obtains the corresponding request information for business processing 5) the Servlet instance processes the business result and returns it to the response object

You’ve seen the basic Tomcat process for handling servlets. So let’s do the same thing.

2.1 define the servlet

package com.craftsman.tomcat.tradition; import com.craftsman.tomcat.nio.BXNIORequest; import com.craftsman.tomcat.nio.BXNIOResponse; /** * abstract tomcat servlet * @author chenfanglin * @date 2021 05月16日 */ public abstract class BXServlet {public void service(BXRequest request, BXResponse response)throws Exception{ if("GET".equalsIgnoreCase(request.getMethod())){ doGet(request,response); }else if("POST".equalsIgnoreCase(request.getMethod())){ doPost(request,response); } } public abstract void doGet(BXRequest request,BXResponse response)throws Exception; public abstract void doPost(BXRequest request,BXResponse response)throws Exception; }Copy the code

The above defined servlet service method, init destory and other methods are omitted.

2.2 Specific business implementation

package com.craftsman.tomcat.tradition; public class FirstServlet extends BXServlet { public void doGet(BXRequest request, BXResponse response) throws Exception { doPost(request,response); } public void doPost(BXRequest request, BXResponse response) throws Exception { response.write("this is bx first servlet"); }}Copy the code

The above implementation of the Servlet protocol, defined the business processing logic. DoPost method.

2.3 Tomcat Startup Class

package com.craftsman.tomcat.tradition; import java.io.FileInputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.Properties; public class BXTomcat { private int port=8080; private ServerSocket SERVER; / / servlet mapping. Private Map<String,BXServlet> SERVLET_MAP =new HashMap<String,BXServlet>(); private Properties WEB_XML =new Properties(); Private void init(){String webInf=this.getClass().getResource("/").getPath(); try { FileInputStream fis=new FileInputStream(webInf+"web.properties"); WEB_XML.load(fis); for(Object k: WEB_XML.keySet()){ String key=k.toString(); if(key.endsWith(".url")){ String servletName=key.replaceAll("\\.url$",""); String url= WEB_XML.getProperty(key); String className= WEB_XML.getProperty(servletName+".className"); BXServlet obj=(BXServlet) Class.forName(className).newInstance(); Servlet_map. put(url,obj); // Load a fixed URL with the corresponding handler. } } } catch (Exception e) { e.printStackTrace(); }} public void start(){//1. Try {//2. Start the listener port SERVER =new ServerSocket(this.port); System.out.println("bx Tomcat enabled port :"+this.port); While (true){Socket client= server.accept (); process(client); } } catch (Exception e) { e.printStackTrace(); } } public void process(Socket client)throws Exception{ //1. InputStream is= client.getinputStream (); OutputStream os=client.getOutputStream(); BXRequest request=new BXRequest(is); BXResponse response=new BXResponse(os); //3. Process the request request and distribute it. String url=request.getUrl(); if(SERVLET_MAP.containsKey(url)){ SERVLET_MAP.get(url).service(request,response); }else{ response.write("this url is not founded"); } os.flush(); os.close(); is.close(); client.close(); } public static void main(String[] args) { new BXTomcat().start(); System.out.println("this bx tomcat already started"); }}Copy the code

Initialize the container, prepare the URL distributor, and receive the front-end request.

Netty’s transformation of the existing traditional model

Netty has the advantage of naturally supporting HTTP protocol decoding and encoding. Try to use Netty’s method to transform the existing Tomcat container.

Look directly at the existing Tomcat container section

3.1 Tomcat Container Transformation

package com.craftsman.tomcat.nio; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; import java.io.FileInputStream; import java.net.ServerSocket; import java.util.HashMap; import java.util.Map; import java.util.Properties; @author chenfanglin * @date 2021 05月16日 */ public class BXNIOTomcat {private int port=8081; private Map<String,BXNIOServlet> SERVLET_MAP =new HashMap<String,BXNIOServlet>(); private Properties WEB_XML =new Properties(); private void init(){ String webInf=this.getClass().getResource("/").getPath(); try { FileInputStream fis=new FileInputStream(webInf+"web-nio.properties"); WEB_XML.load(fis); for(Object k: WEB_XML.keySet()){ String key=k.toString(); if(key.endsWith(".url")){ String servletName=key.replaceAll("\\.url$",""); String url= WEB_XML.getProperty(key); String className= WEB_XML.getProperty(servletName+".className"); BXNIOServlet obj=(BXNIOServlet) Class.forName(className).newInstance(); SERVLET_MAP.put(url,obj); } } } catch (Exception e) { e.printStackTrace(); }} public void start(){//1. EventLoopGroup bossGroup=new NioEventLoopGroup(); bossGroup=new NioEventLoopGroup(); EventLoopGroup workerGroup=new NioEventLoopGroup(); ServerBootstrap =new ServerBootstrap(); serverBootstrap.group(bossGroup,workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel ch) throws Exception { // Ch.pipeline ().addlast (new HttpResponseEncoder()); ch.pipeline().addLast(new HttpRequestDecoder()); Pipeline ().addLast(new BXTomcatHandler()); Option(channeloption.so_backlog,128) // Child threads keep long links. ChildOption (channeloption.so_keepalive,true); ChannelFuture f=serverBootstrap.bind(this.port).sync(); System.out.println("bx nio Tomcat has started listening on port :"+this.port); f.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); }} / / business processor public class BXTomcatHandler extends ChannelInboundHandlerAdapter {@ Override public void channelRead(ChannelHandlerContext ctx, Object MSG) throws Exception {if(MSG instanceof HttpRequest){system.out.println (" received request MSG "+ MSG); HttpRequest request=(HttpRequest) msg; BXNIORequest realRequest=new BXNIORequest(ctx,request); BXNIOResponse realResponse=new BXNIOResponse(ctx,request); String url=realRequest.getRequest().uri(); If (servlet_map.containsKey (url)){// Distribute service requests servlet_map.get (url).service(realRequest,realResponse); }else{ realResponse.write("nio tomcat not found request url"); } } } } public static void main(String[] args) { new BXNIOTomcat().start(); System.out.println("this bx nio tomcat already started"); }}Copy the code

[Bug Mc-10837] – Resources file will not be packaged into target file when fetching configuration file in resources path.

Finally, add the corresponding Resources path and maven plug-in to the POM file to solve the problem. Record it again.

<build> <resources> <resource> <directory>src/main/java</directory> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> </includes> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId> Maven-resources-plugin </artifactId> <version>2.6</version> </plugin> </build>Copy the code

See the specific code:

To build your own Tomcat, please touch me