springboot中tomcat的啟動(八)監聽啟動,讀寫
tomcat中所有的元件都啟動了之後,後面就需要繫結監聽埠了,監聽埠的地方是在ServletWebServerApplicationContext的finishRefresh()方法中,最後會進入了NioEndPoint的bind()方法,在這個方法中進行了埠的繫結和監聽
@Override public void bind() throws Exception { serverSock = ServerSocketChannel.open(); socketProperties.setProperties(serverSock.socket()); InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort())); serverSock.socket().bind(addr,getAcceptCount()); serverSock.configureBlocking(true); //mimic APR behavior // Initialize thread count defaults for acceptor, poller if (acceptorThreadCount == 0) { // FIXME: Doesn't seem to work that well with multiple accept threads acceptorThreadCount = 1; } if (pollerThreadCount <= 0) { //minimum one poller thread pollerThreadCount = 1; } setStopLatch(new CountDownLatch(pollerThreadCount)); // Initialize SSL if needed initialiseSsl(); selectorPool.open(); }
這段程式碼的功能就是開啟ServerSocketChannel,然後監聽埠。我們跟入程式碼看看監聽後是如何處理的,監聽其實是用到了Selector去輪詢的,監聽埠並處理邏輯的程式碼就在最後一行:selectorPool.open();這個方法後面進入了NioBlockingSelector的open()方法。
public void open(Selector selector) { sharedSelector = selector; poller = new BlockPoller(); poller.selector = sharedSelector; poller.setDaemon(true); poller.setName("NioBlockingSelector.BlockPoller-"+(++threadCounter)); poller.start(); }
這個open()方法中的BlockPoller類就是做了輪詢獲取接收到的訊息並處理的類。這個BlockPoller是Thread的子類,其run方法就是執行了本應用向channel中寫資料的邏輯。
而讀資料的邏輯是在NioEndPoint的內部類SocketProcessor的duRun()方法中,將讀取到的資訊封裝到了sockerWrapper,然後經過一系列路徑,進入到了spring的OncePerRequestFilter。其序列圖如下:
然後通過tomcat的ApplicationFilterChain進入了Spring的OncePerRequestFilter的doFilter()方法。
這裡有一個地方很奇怪,為什麼tomcat的FilterChain會進入Spring的Filter中呢,因為在Springboot的spring-boot-starter-web依賴了tomcat的tomcat-embed-core包。然後在AbstractFilterRegistrationBean中的addRegistration方法中,註冊了該filter。