Tomcat源码分析

tomcat启动过程分析

 

1、在bootstrap.start()方法里完成tomcat启动
2、bootstrap.start()启动过程:创建一个catalina实例,并执行catalina实例的start方法。
    1、执行init,创建一个catalina对象实例。
        1、初始化类加载器,
        2、通过类加载器+反射机制,加载org.apache.catalina.startup.Catalina类对象,并创建实例对象catalinaDaemon。
        (Class.forName-根级类加载器,具体类加载器.forClass,创建类对象,通过newInstance创建类对象实例)
        (反射机制创建实例与new创建实例区别:
            1、new创建实例,静态创建实例对象,因为要创建的实例类型是明确固定的-有编译后的class文件,可以调用类对象的任何构造器去创建,速度快
            2、反射机制创建实例,动态创建实例对象,速度要比new创建实例对象慢。因为要创建的实例类型不明确,没有编译后的class文件(可能是通过远端动态加载类),
            并且JVM还会去校验反射机制是否有权限创建该实例对象。反射机制创建实例对象也是不安全的,因为它是通过调用无参构造器来完成的,所以如果类没有定义无参构造器,反射机制会抛出异常。
        )
        3、通过反射机制,执行Catalina的start方法
3、Catalina.start方法:
    1、组件初始化:根据server.xml配置,创建一个server对象,并逐步初始化server下的service组件,service下的engine、executor、listener、connector组件。在初始化
       connector组件的时候,会为每个connector组件实例对象创建一个连接器适配器CoyoteAdapter对象,并绑定到协议处理器protocolHandler上。并在协议处理器初始化的时候,
       会去创建一个NioEndPoint对象。在NioEndPoint对象中,通过java.nio.channels.ServerSocketChannel获取Socket套接字。
        1、加载server.xml配置文件,创建一个Server实例对象,可以简单理解成创建了服务端
        2、进行Server.init()初始化,把包含的service组件进行初始化
            1、遍历Service集合,进行Service.init初始化,把service包含的engine、executor、listener、connector组件初始化
                1、进行engine初始化
                    1、初始化realm
                2、进行executor.init初始化
                3、进行listener.init初始化
                4、进行connector.init初始化,为connector创建连接器适配器和协议处理器
                    1、创建连接器适配器对象new CoyoteAdapter(Connector),并绑定到协议处理器上protocolHandler.setAdapter(adapter)
                    2、进行协议处理器protocolHandler.init初始化
    2、启动组件:依次执行start方法:server.start()->service.start()->[engine.start()、executor.start()、listener.start()、connector.start()]    。嵌套关系。
    在connector.start方法中,会去执行协议处理器protocolHandler.start方法。在protocolHandler.start方法中,会去执行NioEndPoint.startInternal方法。
    在NioEndPoint.startInternal方法中
        1、创建线程池,线程池最大线程数是200,LinkedBlockingQueue队列
        2、创建Acceptor类线程,并启动,接收请求。while (running) {SocketChannel socket = serverSock.accept();}。并将socket封装成NioChannel,交给某一个Poller处理。
        3、创建Poller类线程,并启动。接收Acceptor线程发过来的NioChannel,封装成NioSocketWrapper,创建SocketProcessor(socket处理器)对象,放到线程池执行。

tomcat接收请求分析
Acceptor线程类接收到一个请求,封装成SocketChannel,交给一个Poller线程类处理。
在Poller线程里又创建了一个SocketProcessor线程,由SocketProcessor处理请求,并将SocketProcessor线程放到线程池执行。
在SocketProcessor线程里,等三次握手完成后(TCP建立完成后),调用ConnectionHandler.process接口处理socket。
在ConnectionHandler里定义了socket到processor的映射,所以通过socket找到对应的processor。
HTTP1.1协议发起的socket,找到的processor一般是Http11Processor。以Http11Processor为例,通过Http11Processor.service接口,实现对socket的处理。
在Http11Processor.service接口里,将socket封装成了tomcat自己的request和response,并调用连接器适配器CoyoteAdapter.service(request, response)接口。
在CoyoteAdapter.service(request, response)接口里,将tomcat自己的request和response转换为HttpServletRequest、HttpServletResponse,
然后开始执行管道责任链(pipeline),最终找到对应的业务处理接口。
什么是管道责任链?
发出一个请求有的时候会报404错误,这个就是未通过管道责任链校验发出的提示。管道责任链还做了一些其他的工作,看的不是太明白。

怎么开始管道责任链执行的?
在server.xml中service下配置的有Connector,发出的请求会连接到某个Connector上,通过Connector对象,咱们能够获取该Connector属于哪个Service对象。再通过Service对象获取
engine对象。通过engine对象开始管道责任链处理。
    StandardEngineValve.invoke(request,response) -> StandardHostValve.invoke(request,response) -> StandardContextValve.invoke(request,response) -> StandardWrapperValve.invoke(request,response)
    connector.getService().getContainer().getPipeline()
     host.getPipeline()
     context.getPipeline()
     wrapper.getPipeline()
    1、在管道责任链里,依次去找engine、host、context、wrapper是否存在,不存在,报404错误
    2、在StandardWrapperValve.invoke方法中,先执行所有过滤器。过滤器都执行通过后,再去通过执行servlet.service接口实现业务接口执行。

一个service下可以包含多个connector。每个connector绑定了一个端口号。当有请求连接到一个端口号时,可以找到该connector属于哪个service,进而找到该service下的
engine、host、context、wrapper.

简单总结:

tomcat实现原理:tomcat接收到请求,封装成socket,放到一个线程里处理,线程又会放到线程池里执行。线程池最大执行线程数是200,所以同一时间,tomcat最多能处理200个请求。线程池采用的队列是LinkedBlockingQueue。LinkedBlockingQueue最大容量默认是Integer.MAX_VALUE

tomcat和servlet/spring mvc的关系:
https://blog.csdn.net/u010852544/article/details/104991417/
 

tomcat之DefaultServlet

Tomcat在$ CATALINA_BASE/conf/web.xml中默认定义了两个Servlet:DefaultServlet和JspServlet,而且由于$ CATALINA_BASE/conf/web.xml为Web应用的默认部署描述文件,因此这两个Servlet会默认存在所有Web应用容器中。

DefaultServlet为默认的Servlet,当客户端请求不能匹配其他所有Servlet时,将由该Servlet处理。

    DefaultServlet主要用于处理静态资源,如HTML、图片、CSS、JS文件等,而且为了提升服务器性能,Tomcat对访问文件进行缓存。按照默认配置,客户端请求路径与资源的物理路径是一致的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值