概要

  • Connector组成
  • Connector分类
  • Conector请求处理流程
  • Connector初始化流程

    1.Connector组成

  • Connector中包含一个ProtocolHandlerAdapter

  • ProtocolHandler创建对应Endpoint,用来处理请求。
  • Adapter是Connector与Container容器之间的一个连接器。```java public class Connector extends LifecycleMBeanBase {

    1. // 协议Handler

    protected final ProtocolHandler protocolHandler; // Coyote adapter. protected Adapter adapter = null; public Connector() {

    1. // 默认使用nio
    2. this("org.apache.coyote.http11.Http11NioProtocol");

    }

    public Connector(String protocol) { // 传入协议名称

    1. boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
    2. AprLifecycleListener.getUseAprConnector(); // 是否开启Apr
    3. if ("HTTP/1.1".equals(protocol) || protocol == null) { // HTTP/1.1
    4. if (aprConnector) {
    5. protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol";
    6. } else {
    7. protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol";
    8. }
    9. } else if ("AJP/1.3".equals(protocol)) { // AJP/1.3
    10. if (aprConnector) {
    11. protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol";
    12. } else {
    13. protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol";
    14. }
    15. } else {
    16. protocolHandlerClassName = protocol; // 其他自定义协议实现
    17. }
    18. ProtocolHandler p = null;
    19. try {
    20. // 反射获取协议处理类
    21. Class<?> clazz = Class.forName(protocolHandlerClassName);
    22. // 实例化
    23. p = (ProtocolHandler) clazz.getConstructor().newInstance();
    24. } catch (Exception e) {
    25. log.error(sm.getString(
    26. "coyoteConnector.protocolHandlerInstantiationFailed"), e);
    27. } finally {
    28. this.protocolHandler = p;
    29. }
    30. ...

    } } ```

2.Connector分类

可以分为以下三类

  • Http Connector:解析HTTP请求,又分为BIO Http Connector和NIO Http Connector,即阻塞IO Connector和非阻塞IO Connector。本文主要分析NIO Http Connector的实现过程。
  • APR HTTP Connector:解析HTTP请求,用C实现,通过JNI调用的。主要提升对静态资源(如HTML、图片、CSS、JS等)的访问性能。
  • AJP Connector:基于AJP协议,用于Tomcat与HTTP服务器通信定制的协议,能提供较高的通信速度和效率。如与Apache服务器集成时,采用这个协议。

具体要使用哪种Connector可以在server.xml文件中通过protocol属性配置如下:

  1. <Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
  2. connectionTimeout="20000"
  3. redirectPort="8443" />

每一类Connector对应这一种protocolHandlerprotocolHandler用来监听服务器某个端口的请求,但并不处理(处理请求由容器组件完成)。

3.Conector请求处理流程

Tomcat-Connector - 图1

  1. Acceptor为监听线程,调用serverSocketAccept()阻塞,本质上调用ServerSocketChannel.accept()
  2. Acceptor将接受的Socket封装成PollerEvent,调用Poll的register方法放到Poll的同步队列中
  3. Poller线程循环从队列获取数据,然后把socketWrapper包装成SocketProcessor
  4. SocketProcessor调用getHandler()获取对应的ConnectionHandler
  5. ConnectionHandler把socket交由Http11Processor处理,解析http的Header和Body
  6. Http11Processor调用service()把包装好的request和response传给CoyoteAdapter
  7. CoyoteAdapter会通过Mapper把请求对应的session、servlet等关联好,准备传给Containe

4.Connector初始化流程

本文以sprng boot为例

  1. //spring boot启动
  2. public ConfigurableApplicationContext run(String... args) {
  3. ...
  4. try {
  5. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  6. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  7. configureIgnoreBeanInfo(environment);
  8. Banner printedBanner = printBanner(environment);
  9. context = createApplicationContext();
  10. exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
  11. new Class[] { ConfigurableApplicationContext.class }, context);
  12. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  13. refreshContext(context);
  14. //spring启动,扫描并且初始化bean;启动了内置web容器
  15. afterRefresh(context, applicationArguments);
  16. stopWatch.stop();
  17. .....
  18. return context;
  19. }

在ServletWebServerApplicationContext的onRefresh()方会创建servlet容器

  1. protected void onRefresh() {
  2. super.onRefresh();
  3. try {
  4. //创建servlet容器
  5. createWebServer();
  6. }
  7. catch (Throwable ex) {
  8. throw new ApplicationContextException("Unable to start web server", ex);
  9. }
  10. }

在TomcatServletWebServerFactory#getWebServer()中会创建tomcat

  1. public WebServer getWebServer(ServletContextInitializer... initializers) {
  2. if (this.disableMBeanRegistry) {
  3. Registry.disableRegistry();
  4. }
  5. //创建tomcat
  6. Tomcat tomcat = new Tomcat();
  7. File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
  8. tomcat.setBaseDir(baseDir.getAbsolutePath());
  9. //创建http nio连接器
  10. Connector connector = new Connector(this.protocol);
  11. connector.setThrowOnFailure(true);
  12. //创建server和service,并把连接器放到service中
  13. tomcat.getService().addConnector(connector);
  14. customizeConnector(connector);
  15. tomcat.setConnector(connector);
  16. tomcat.getHost().setAutoDeploy(false);
  17. configureEngine(tomcat.getEngine());
  18. for (Connector additionalConnector : this.additionalTomcatConnectors) {
  19. tomcat.getService().addConnector(additionalConnector);
  20. }
  21. prepareContext(tomcat.getHost(), initializers);
  22. return getTomcatWebServer(tomcat);
  23. }

在增加的过程中会启动connetot

  1. public void addConnector(Connector connector) {
  2. synchronized (connectorsLock) {
  3. connector.setService(this);
  4. Connector results[] = new Connector[connectors.length + 1];
  5. System.arraycopy(connectors, 0, results, 0, connectors.length);
  6. results[connectors.length] = connector;
  7. connectors = results;
  8. }
  9. try {
  10. if (getState().isAvailable()) {
  11. //启动连接器
  12. connector.start();
  13. }
  14. } catch (LifecycleException e) {
  15. throw new IllegalArgumentException(
  16. sm.getString("standardService.connector.startFailed", connector), e);
  17. }
  18. // Report this property change to interested listeners
  19. support.firePropertyChange("connector", null, connector);
  20. }

下面以Http11NioProtocol为例分析启动初始化过程:

在Connector的startInternal()方法中启动了protocolHandler,代码如下:

  1. protected void startInternal() throws LifecycleException {
  2. if (getPortWithOffset() < 0) {
  3. throw new LifecycleException(sm.getString(
  4. "coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
  5. }
  6. setState(LifecycleState.STARTING);
  7. try {
  8. //启动protocolHandler
  9. protocolHandler.start();
  10. } catch (Exception e) {
  11. throw new LifecycleException(
  12. sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
  13. }
  14. }

在AbstractProtocol的start()方法中启动endpoint

  1. @Override
  2. public void start() throws Exception {
  3. if (getLog().isInfoEnabled()) {
  4. getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
  5. logPortOffset();
  6. }
  7. //启动endpoint
  8. endpoint.start();
  9. monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
  10. new Runnable() {
  11. @Override
  12. public void run() {
  13. if (!isPaused()) {
  14. startAsyncTimeout();
  15. }
  16. }
  17. }, 0, 60, TimeUnit.SECONDS);
  18. }

在NioEndpoint的startInternal()方法,创建creating acceptor, poller threads.

  1. /**
  2. * Start the NIO endpoint, creating acceptor, poller threads.
  3. */
  4. @Override
  5. public void startInternal() throws Exception {
  6. if (!running) {
  7. running = true;
  8. paused = false;
  9. if (socketProperties.getProcessorCache() != 0) {
  10. processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
  11. socketProperties.getProcessorCache());
  12. }
  13. if (socketProperties.getEventCache() != 0) {
  14. eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
  15. socketProperties.getEventCache());
  16. }
  17. if (socketProperties.getBufferPool() != 0) {
  18. nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
  19. socketProperties.getBufferPool());
  20. }
  21. // Create worker collection
  22. if (getExecutor() == null) {
  23. createExecutor();
  24. }
  25. initializeConnectionLatch();
  26. // Start poller thread
  27. poller = new Poller();
  28. Thread pollerThread = new Thread(poller, getName() + "-ClientPoller");
  29. pollerThread.setPriority(threadPriority);
  30. pollerThread.setDaemon(true);
  31. //调用SynchronizedQueue.poll(),直到拿到PollerEvent
  32. pollerThread.start();
  33. //创建接收器,在AbstractEndpoint#startAcceptorThread()中创建Acceptor,然后启动
  34. //最终调用NioEndpoint#serverSocketAccept(),启动socketServer
  35. //开始监听,到这Connector启动就结束了
  36. //Acceptor接收到请求封装成PollerEvent然后放到SynchronizedQueue中
  37. startAcceptorThread();
  38. }
  39. }

5.总结

  • Connector负责创建Request和Response
  • Connector初始化时会创建对应的Endpoint;Endpoint监听一个指定端口,负责对请求报文的解析和响应报文组装
  • Connector初始化时会创建对应的Adapter;Adapter将Request,Response交给给容器处理