SpringBoot内嵌的Tomcat启动过程以及请求

news2024/11/15 8:30:03

1.springboot内嵌的tomcat的pom坐标

 启动后可以看到tomcat版本为9.0.46

 2.springboot 内嵌tomcat启动流程

点击进入SpringApplication.run()方法里面

看这次tomcat启动相关的核心代码refreshContext(context);刷新上下文方法

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 此次的核心代码是刷新上下文方法
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		listeners.started(context);
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

进入 私有方法refreshContext

private void refreshContext(ConfigurableApplicationContext context) {
	if (this.registerShutdownHook) {
		try {
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
    // 核心方法,继续进入
	refresh((ApplicationContext) context);
}
@Deprecated
protected void refresh(ApplicationContext applicationContext) {
	Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
    // 核心代码,继续进入方法
	refresh((ConfigurableApplicationContext) applicationContext);
}

进入refresh方法

protected void refresh(ConfigurableApplicationContext applicationContext) {
	// 核心方法,查看调用的方法refresh()
    applicationContext.refresh();
}

查看refresh方法,有三个实现类,进入默认的实现类ServletWebServerApplicationContext,定位到实现方法

@Override
public final void refresh() throws BeansException, IllegalStateException {
	try {
        // 进入父类refresh
		super.refresh();
	}
	catch (RuntimeException ex) {
		WebServer webServer = this.webServer;
		if (webServer != null) {
			webServer.stop();
		}
		throw ex;
	}
}

 看onRefresh()方法

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();
		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);
		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);
			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);
			// Initialize message source for this context.
			initMessageSource();
			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();
            // 我们进入这个方法
			// Initialize other special beans in specific context subclasses.
			onRefresh();
			// Check for listener beans and register them.
			registerListeners();
			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);
			// Last step: publish corresponding event.
			finishRefresh();
		}
		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}
			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();
			// Reset 'active' flag.
			cancelRefresh(ex);
			// Propagate exception to caller.
			throw ex;
		}
		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

 找到子类的实现方法:

@Override
protected void onRefresh() {
	super.onRefresh();
	try {
        // 核心代码,创建web服务器
		createWebServer();
	}
	catch (Throwable ex) {
		throw new ApplicationContextException("Unable to start web server", ex);
	}
}

进入createWebServer方法,ServletContext、WebServer在tomcat启动的时候一定为空,还没有初始化完成,会进入if代码块执行

private void createWebServer() {
	WebServer webServer = this.webServer;
    // tomcat启动servletContext才进行创建
	ServletContext servletContext = getServletContext();
	if (webServer == null && servletContext == null) {
		ServletWebServerFactory factory = getWebServerFactory();
        // 核心代码,通过工厂获取一个WebServer实例
		this.webServer = factory.getWebServer(getSelfInitializer());
		getBeanFactory().registerSingleton("webServerGracefulShutdown",
				new WebServerGracefulShutdownLifecycle(this.webServer));
		getBeanFactory().registerSingleton("webServerStartStop",
				new WebServerStartStopLifecycle(this, this.webServer));
	}
	else if (servletContext != null) {
		try {
			getSelfInitializer().onStartup(servletContext);
		}
		catch (ServletException ex) {
			throw new ApplicationContextException("Cannot initialize servlet context", ex);
		}
	}
	initPropertySources();
}

 getWebServer方法需要参数,该参数是一个方法getSelfInitializer(),找到

private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
    // 方法引用,ServletContextInitializer是一个函数是接口,通过方法引用返回一个实现        
    // ServletContextInitializer的一个实现子类,作用同匿名内部类。
	return this::selfInitialize;
}

函数式接口:

@FunctionalInterface
public interface ServletContextInitializer {

	/**
	 * Configure the given {@link ServletContext} with any servlets, filters, listeners
	 * context-params and attributes necessary for initialization.
	 * @param servletContext the {@code ServletContext} to initialize
	 * @throws ServletException if any call against the given {@code ServletContext}
	 * throws a {@code ServletException}
	 */
	void onStartup(ServletContext servletContext) throws ServletException;

}

this::selfInitialize就是实例::方法名调用方式,this代表当前对象,selfInitialize是this(ServletWebServerApplicationContext)对象的一个私有方法

private void selfInitialize(ServletContext servletContext) throws ServletException {
	prepareWebApplicationContext(servletContext);
	registerApplicationScope(servletContext);
	WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
	for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
		beans.onStartup(servletContext);
	}
}

继续进入getWebServer,发现是一个接口,有三个实现类Jetty、Tomcat、UnderTow,我们是Tomcat服务器,进入TomcatServletWebServerFactory中的实现方法

@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
	if (this.disableMBeanRegistry) {
		Registry.disableRegistry();
	}
	Tomcat tomcat = new Tomcat();
	File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
    // 用于设置临时文件的目录,这些目录用于存放JSP生成的源代码及Class文件x
	tomcat.setBaseDir(baseDir.getAbsolutePath());
	Connector connector = new Connector(this.protocol);
	connector.setThrowOnFailure(true);
	tomcat.getService().addConnector(connector);
	customizeConnector(connector);
    // 用于设置链接器,包括协议、I/0、端口、压缩、加密等等
	tomcat.setConnector(connector);
    // 是否自动部署
	tomcat.getHost().setAutoDeploy(false);
	configureEngine(tomcat.getEngine());
	for (Connector additionalConnector : this.additionalTomcatConnectors) {
		tomcat.getService().addConnector(additionalConnector);
	}
	prepareContext(tomcat.getHost(), initializers);
    // 核心代码
	return getTomcatWebServer(tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
	return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}

进入TomcatWebServer构造方法

public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
	Assert.notNull(tomcat, "Tomcat Server must not be null");
	this.tomcat = tomcat;
	this.autoStart = autoStart;
	this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
    // 核心代码
	initialize();
}

 进入initialize()方法

private void initialize() throws WebServerException {
	logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
	synchronized (this.monitor) {
		try {
			addInstanceIdToEngineName();

			Context context = findContext();
			context.addLifecycleListener((event) -> {
				if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
					// Remove service connectors so that protocol binding doesn't
					// happen when the service is started.
					removeServiceConnectors();
				}
			});
            // 核心代码
			// Start the server to trigger initialization listeners
			this.tomcat.start();

			// We can re-throw failure exception directly in the main thread
			rethrowDeferredStartupExceptions();

			try {
				ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
			}
			catch (NamingException ex) {
				// Naming is not enabled. Continue
			}

			// Unlike Jetty, all Tomcat threads are daemon threads. We create a
			// blocking non-daemon to stop immediate shutdown
			startDaemonAwaitThread();
		}
		catch (Exception ex) {
			stopSilently();
			destroySilently();
			throw new WebServerException("Unable to start embedded Tomcat", ex);
		}
	}
}
public void start() throws LifecycleException {
	getServer();
    // 核心代码
	server.start();
}

进入start()方法,找到LifecycleBase实现类方法

 LifecycleBase类中init();startInternal();两个核心方法

 @Override
public final synchronized void start() throws LifecycleException {

	if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
			LifecycleState.STARTED.equals(state)) {

		if (log.isDebugEnabled()) {
			Exception e = new LifecycleException();
			log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
		} else if (log.isInfoEnabled()) {
			log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
		}

		return;
	}

	if (state.equals(LifecycleState.NEW)) {
        // 核心代码1
		init();
	} else if (state.equals(LifecycleState.FAILED)) {
		stop();
	} else if (!state.equals(LifecycleState.INITIALIZED) &&
			!state.equals(LifecycleState.STOPPED)) {
		invalidTransition(Lifecycle.BEFORE_START_EVENT);
	}

	try {
		setStateInternal(LifecycleState.STARTING_PREP, null, false);
        // 核心代码2
		startInternal();
		if (state.equals(LifecycleState.FAILED)) {
			// This is a 'controlled' failure. The component put itself into the
			// FAILED state so call stop() to complete the clean-up.
			stop();
		} else if (!state.equals(LifecycleState.STARTING)) {
			// Shouldn't be necessary but acts as a check that sub-classes are
			// doing what they are supposed to.
			invalidTransition(Lifecycle.AFTER_START_EVENT);
		} else {
			setStateInternal(LifecycleState.STARTED, null, false);
		}
	} catch (Throwable t) {
		// This is an 'uncontrolled' failure so put the component into the
		// FAILED state and throw an exception.
		handleSubClassException(t, "lifecycleBase.startFail", toString());
	}
}

 init()方法

 @Override
public final synchronized void init() throws LifecycleException {
	if (!state.equals(LifecycleState.NEW)) {
		invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
	}

	try {
		setStateInternal(LifecycleState.INITIALIZING, null, false);
        // 核心代码
		initInternal();
		setStateInternal(LifecycleState.INITIALIZED, null, false);
	} catch (Throwable t) {
		handleSubClassException(t, "lifecycleBase.initFail", toString());
	}
}

initInternal有很多实现类,看组件Connector中的实现方法

 组件Connector类型方法

@Override
protected void initInternal() throws LifecycleException {

	super.initInternal();

	if (protocolHandler == null) {
		throw new LifecycleException(
				sm.getString("coyoteConnector.protocolHandlerInstantiationFailed"));
	}

	// Initialize adapter
	adapter = new CoyoteAdapter(this);
	protocolHandler.setAdapter(adapter);
	if (service != null) {
		protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor());
	}

	// Make sure parseBodyMethodsSet has a default
	if (null == parseBodyMethodsSet) {
		setParseBodyMethods(getParseBodyMethods());
	}

	if (protocolHandler.isAprRequired() && !AprStatus.isInstanceCreated()) {
		throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
				getProtocolHandlerClassName()));
	}
	if (protocolHandler.isAprRequired() && !AprStatus.isAprAvailable()) {
		throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
				getProtocolHandlerClassName()));
	}
	if (AprStatus.isAprAvailable() && AprStatus.getUseOpenSSL() &&
			protocolHandler instanceof AbstractHttp11JsseProtocol) {
		AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
				(AbstractHttp11JsseProtocol<?>) protocolHandler;
		if (jsseProtocolHandler.isSSLEnabled() &&
				jsseProtocolHandler.getSslImplementationName() == null) {
			// OpenSSL is compatible with the JSSE configuration, so use it if APR is available
			jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
		}
	}

	try {
		// 核心方法
		protocolHandler.init();
	} catch (Exception e) {
		throw new LifecycleException(
				sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
	}
}

进入实现类AbstractProtocol中init()方法

@Override
public void init() throws Exception {
	if (getLog().isInfoEnabled()) {
		getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
		logPortOffset();
	}

	if (oname == null) {
		// Component not pre-registered so register it
		oname = createObjectName();
		if (oname != null) {
			Registry.getRegistry(null, null).registerComponent(this, oname, null);
		}
	}

	if (this.domain != null) {
		ObjectName rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
		this.rgOname = rgOname;
		Registry.getRegistry(null, null).registerComponent(
				getHandler().getGlobal(), rgOname, null);
	}

	String endpointName = getName();
	endpoint.setName(endpointName.substring(1, endpointName.length()-1));
	endpoint.setDomain(domain);
    // 核心代码
	endpoint.init();
}

进入endpoint.init()方法

public final void init() throws Exception {
	if (bindOnInit) {
        // 核心代码
		bindWithCleanup();
		bindState = BindState.BOUND_ON_INIT;
	}
	if (this.domain != null) {
		// Register endpoint (as ThreadPool - historical name)
		oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
		Registry.getRegistry(null, null).registerComponent(this, oname, null);

		ObjectName socketPropertiesOname = new ObjectName(domain +
				":type=SocketProperties,name=\"" + getName() + "\"");
		socketProperties.setObjectName(socketPropertiesOname);
		Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);

		for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
			registerJmx(sslHostConfig);
		}
	}
}

进入bindWithCleanup方法里面 

private void bindWithCleanup() throws Exception {
	try {
        // 核心代码
		bind();
	} catch (Throwable t) {
		// Ensure open sockets etc. are cleaned up if something goes
		// wrong during bind
		ExceptionUtils.handleThrowable(t);
		unbind();
		throw t;
	}
}
@Override
public void bind() throws Exception {
    // 核心代码
	initServerSocket();

	setStopLatch(new CountDownLatch(1));

	// Initialize SSL if needed
	initialiseSsl();

	selectorPool.open(getName());
}

初始化Socket 

protected void initServerSocket() throws Exception {
	if (getUseInheritedChannel()) {
		// Retrieve the channel provided by the OS
		Channel ic = System.inheritedChannel();
		if (ic instanceof ServerSocketChannel) {
			serverSock = (ServerSocketChannel) ic;
		}
		if (serverSock == null) {
			throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
		}
	} else if (getUnixDomainSocketPath() != null) {
		SocketAddress sa = JreCompat.getInstance().getUnixDomainSocketAddress(getUnixDomainSocketPath());
		serverSock = JreCompat.getInstance().openUnixDomainServerSocketChannel();
		serverSock.bind(sa, getAcceptCount());
		if (getUnixDomainSocketPathPermissions() != null) {
			Path path = Paths.get(getUnixDomainSocketPath());
			Set<PosixFilePermission> permissions =
					PosixFilePermissions.fromString(getUnixDomainSocketPathPermissions());
			if (path.getFileSystem().supportedFileAttributeViews().contains("posix")) {
				FileAttribute<Set<PosixFilePermission>> attrs = PosixFilePermissions.asFileAttribute(permissions);
				Files.setAttribute(path, attrs.name(), attrs.value());
			} else {
				java.io.File file = path.toFile();
				if (permissions.contains(PosixFilePermission.OTHERS_READ) && !file.setReadable(true, false)) {
					log.warn(sm.getString("endpoint.nio.perms.readFail", file.getPath()));
				}
				if (permissions.contains(PosixFilePermission.OTHERS_WRITE) && !file.setWritable(true, false)) {
					log.warn(sm.getString("endpoint.nio.perms.writeFail", file.getPath()));
				}
			}
		}
	} else {
		serverSock = ServerSocketChannel.open();
		socketProperties.setProperties(serverSock.socket());
		InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
		serverSock.bind(addr, getAcceptCount());
	}
	serverSock.configureBlocking(true); //mimic APR behavior
}

startInternal();

看下这个方法,找到Connector里面的startInternal()方法实现

@Override
protected void startInternal() throws LifecycleException {

	// Validate settings before starting
	String id = (protocolHandler != null) ? protocolHandler.getId() : null;
	if (id == null && getPortWithOffset() < 0) {
		throw new LifecycleException(sm.getString(
				"coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
	}

	setState(LifecycleState.STARTING);

	try {
        // 核心代码
		protocolHandler.start();
	} catch (Exception e) {
		throw new LifecycleException(
				sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
	}
}

进入protocolHandler.start();方法里面。进入AbstractProtocol里面的实现方法

@Override
public void start() throws Exception {
	if (getLog().isInfoEnabled()) {
		getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
		logPortOffset();
	}
    // 核心代码
	endpoint.start();
	monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
			() -> {
				if (!isPaused()) {
					startAsyncTimeout();
				}
			}, 0, 60, TimeUnit.SECONDS);
}

找到endpoint.start()方法

public final void start() throws Exception {
	if (bindState == BindState.UNBOUND) {
		bindWithCleanup();
		bindState = BindState.BOUND_ON_START;
	}
    // 核心代码
	startInternal();
}

进入这个实现类里,找到实现方法

 

@Override
    public void startInternal() throws Exception {

        if (!running) {
            running = true;
            paused = false;

            if (socketProperties.getProcessorCache() != 0) {
                processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getProcessorCache());
            }
            if (socketProperties.getEventCache() != 0) {
                eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getEventCache());
            }
            if (socketProperties.getBufferPool() != 0) {
                nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getBufferPool());
            }

            // Create worker collection
            if (getExecutor() == null) {
                createExecutor();
            }

            initializeConnectionLatch();

            // 核心代码 *******
            // Start poller thread
            poller = new Poller();
            Thread pollerThread = new Thread(poller, getName() + "-ClientPoller");
            // 设置进程的优先级
            pollerThread.setPriority(threadPriority);
            // 守护线程:当非守护线程销毁的时候,守护线程跟着销毁。当运行的唯一线程是守护线程时,        
            // Java虚拟机将退出
            pollerThread.setDaemon(true);
            // 开启线程
            pollerThread.start();

            startAcceptorThread();
        }
    }

Poller类是什么?

Poller里面的run方法

@Override
public void run() {
	// Loop until destroy() is called
    // 核心代码1 轮询
	while (true) {

		boolean hasEvents = false;

		try {
			if (!close) {
				hasEvents = events();
				if (wakeupCounter.getAndSet(-1) > 0) {
					// If we are here, means we have other stuff to do
					// Do a non blocking select
					keyCount = selector.selectNow();
				} else {
					keyCount = selector.select(selectorTimeout);
				}
				wakeupCounter.set(0);
			}
			if (close) {
				events();
				timeout(0, false);
				try {
					selector.close();
				} catch (IOException ioe) {
					log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
				}
				break;
			}
			// Either we timed out or we woke up, process events first
			if (keyCount == 0) {
				hasEvents = (hasEvents | events());
			}
		} catch (Throwable x) {
			ExceptionUtils.handleThrowable(x);
			log.error(sm.getString("endpoint.nio.selectorLoopError"), x);
			continue;
		}

		Iterator<SelectionKey> iterator =
			keyCount > 0 ? selector.selectedKeys().iterator() : null;
		// Walk through the collection of ready keys and dispatch
		// any active event.
		while (iterator != null && iterator.hasNext()) {
			SelectionKey sk = iterator.next();
			iterator.remove();
			NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
			// Attachment may be null if another thread has called
			// cancelledKey()
			if (socketWrapper != null) {
                // 核心代码2
				processKey(sk, socketWrapper);
			}
		}

		// Process timeouts
		timeout(keyCount,hasEvents);
	}

	getStopLatch().countDown();
}

启动一个Poller线程轮询监听NIO接收的请求,直到执行核心代码2processKey(sk, socketWrapper);Poller类会轮询监听Socket连接,到这里tomcat算启动成功啦。

springboot嵌入tomcat处理请求的过程

主要看下Poller类中的processKey方法,我们发起一个请求怎么处理的呢?

processKey方法

protected void processKey(SelectionKey sk, NioSocketWrapper socketWrapper) {
	try {
		if (close) {
			cancelledKey(sk, socketWrapper);
		} else if (sk.isValid() && socketWrapper != null) {
			if (sk.isReadable() || sk.isWritable()) {
				if (socketWrapper.getSendfileData() != null) {
					processSendfile(sk, socketWrapper, false);
				} else {
					unreg(sk, socketWrapper, sk.readyOps());
					boolean closeSocket = false;
					// Read goes before write
					if (sk.isReadable()) {
						if (socketWrapper.readOperation != null) {
                            // 核心代码
							if (!socketWrapper.readOperation.process()) {
								closeSocket = true;
							}
                        // 核心代码
						} else if (!processSocket(socketWrapper, SocketEvent.OPEN_READ, true)) {
							closeSocket = true;
						}
					}
					if (!closeSocket && sk.isWritable()) {
						if (socketWrapper.writeOperation != null) {
							if (!socketWrapper.writeOperation.process()) {
								closeSocket = true;
							}
						} else if (!processSocket(socketWrapper, SocketEvent.OPEN_WRITE, true)) {
							closeSocket = true;
						}
					}
					if (closeSocket) {
						cancelledKey(sk, socketWrapper);
					}
				}
			}
		} else {
			// Invalid key
			cancelledKey(sk, socketWrapper);
		}
	} catch (CancelledKeyException ckx) {
		cancelledKey(sk, socketWrapper);
	} catch (Throwable t) {
		ExceptionUtils.handleThrowable(t);
		log.error(sm.getString("endpoint.nio.keyProcessingError"), t);
	}
}

进入processSocket方法

public boolean processSocket(SocketWrapperBase<S> socketWrapper,
	SocketEvent event, boolean dispatch) {
	try {
		if (socketWrapper == null) {
			return false;
		}
        // 核心代码 线程
		SocketProcessorBase<S> sc = null;
		if (processorCache != null) {
			sc = processorCache.pop();
		}
		if (sc == null) {
			sc = createSocketProcessor(socketWrapper, event);
		} else {
			sc.reset(socketWrapper, event);
		}
        // 核心代码 获取线程池,通过线程池执行
		Executor executor = getExecutor();
		if (dispatch && executor != null) {
			executor.execute(sc);
		} else {
			sc.run();
		}
	} catch (RejectedExecutionException ree) {
		getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
		return false;
	} catch (Throwable t) {
		ExceptionUtils.handleThrowable(t);
		// This means we got an OOM or similar creating a thread, or that
		// the pool and its queue are full
		getLog().error(sm.getString("endpoint.process.fail"), t);
		return false;
	}
	return true;
}

看看SocketProcessBase是什么?  实现了Runnable接口 

看下SocketProcessBase的run()方法

 @Override
    public final void run() {
        synchronized (socketWrapper) {
            // It is possible that processing may be triggered for read and
            // write at the same time. The sync above makes sure that processing
            // does not occur in parallel. The test below ensures that if the
            // first event to be processed results in the socket being closed,
            // the subsequent events are not processed.
            if (socketWrapper.isClosed()) {
                return;
            }
            // 核心代码
            doRun();
        }
    }

看下doRun()方法

找到过滤器链ApplicationFilterChain,找到doFilter()方法

@Override
public void doFilter(ServletRequest request, ServletResponse response)
	throws IOException, ServletException {

	if( Globals.IS_SECURITY_ENABLED ) {
		final ServletRequest req = request;
		final ServletResponse res = response;
		try {
			java.security.AccessController.doPrivileged(
					(java.security.PrivilegedExceptionAction<Void>) () -> {
                        // 核心代码
						internalDoFilter(req,res);
						return null;
					}
			);
		} catch( PrivilegedActionException pe) {
			Exception e = pe.getException();
			if (e instanceof ServletException)
				throw (ServletException) e;
			else if (e instanceof IOException)
				throw (IOException) e;
			else if (e instanceof RuntimeException)
				throw (RuntimeException) e;
			else
				throw new ServletException(e.getMessage(), e);
		}
	} else {
		internalDoFilter(request,response);
	}
}

定位到internalDoFilter()方法

private void internalDoFilter(ServletRequest request,
							  ServletResponse response)
	throws IOException, ServletException {

	// Call the next filter if there is one
	if (pos < n) {
		ApplicationFilterConfig filterConfig = filters[pos++];
		try {
			Filter filter = filterConfig.getFilter();

			if (request.isAsyncSupported() && "false".equalsIgnoreCase(
					filterConfig.getFilterDef().getAsyncSupported())) {
				request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
			}
			if( Globals.IS_SECURITY_ENABLED ) {
				final ServletRequest req = request;
				final ServletResponse res = response;
				Principal principal =
					((HttpServletRequest) req).getUserPrincipal();

				Object[] args = new Object[]{req, res, this};
				SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
			} else {
				filter.doFilter(request, response, this);
			}
		} catch (IOException | ServletException | RuntimeException e) {
			throw e;
		} catch (Throwable e) {
			e = ExceptionUtils.unwrapInvocationTargetException(e);
			ExceptionUtils.handleThrowable(e);
			throw new ServletException(sm.getString("filterChain.filter"), e);
		}
		return;
	}

	// We fell off the end of the chain -- call the servlet instance
	try {
		if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
			lastServicedRequest.set(request);
			lastServicedResponse.set(response);
		}

		if (request.isAsyncSupported() && !servletSupportsAsync) {
			request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
					Boolean.FALSE);
		}
		// Use potentially wrapped request from this point
		if ((request instanceof HttpServletRequest) &&
				(response instanceof HttpServletResponse) &&
				Globals.IS_SECURITY_ENABLED ) {
			final ServletRequest req = request;
			final ServletResponse res = response;
			Principal principal =
				((HttpServletRequest) req).getUserPrincipal();
			Object[] args = new Object[]{req, res};
			SecurityUtil.doAsPrivilege("service",
									   servlet,
									   classTypeUsedInService,
									   args,
									   principal);
		} else {
            // 核心代码
			servlet.service(request, response);
		}
	} catch (IOException | ServletException | RuntimeException e) {
		throw e;
	} catch (Throwable e) {
		e = ExceptionUtils.unwrapInvocationTargetException(e);
		ExceptionUtils.handleThrowable(e);
		throw new ServletException(sm.getString("filterChain.servlet"), e);
	} finally {
		if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
			lastServicedRequest.set(null);
			lastServicedResponse.set(null);
		}
	}
}

定位到service()方法的实现类HttpServlet中的service()方法中

@Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;

        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException(lStrings.getString("http.non_http"));
        }
        // 核心代码
        service(request, response);
    }

继续进入到service()方法中

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	long startTime = System.currentTimeMillis();
	Throwable failureCause = null;

	LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
	LocaleContext localeContext = buildLocaleContext(request);

	RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
	ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
	asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

	initContextHolders(request, localeContext, requestAttributes);

	try {
        // 核心代码
		doService(request, response);
	}
	catch (ServletException | IOException ex) {
		failureCause = ex;
		throw ex;
	}
	catch (Throwable ex) {
		failureCause = ex;
		throw new NestedServletException("Request processing failed", ex);
	}

	finally {
		resetContextHolders(request, previousLocaleContext, previousAttributes);
		if (requestAttributes != null) {
			requestAttributes.requestCompleted();
		}
		logResult(request, response, failureCause, asyncManager);
		publishRequestHandledEvent(request, response, startTime, failureCause);
	}
}

 进入doService()方法

 https://blog.csdn.net/z69183787/article/details/129240218
https://blog.csdn.net/sunshinezx8023/article/details/128630710

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1360176.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【2023 CCF 大数据与计算智能大赛】基于TPU平台实现超分辨率重建模型部署 基于QuickRNet的TPU超分模型部署

2023 CCF 大数据与计算智能大赛 《赛题名称》 基于QuickRNet的TPU超分模型部署 巴黎欧莱雅 林松 智能应用业务部算法工程师 中信科移动 中国-北京 gpu163.com 团队简介 巴黎欧莱雅团队包含一个队长和零个队员。 队长林松&#xff0c;研究生学历&#xff0c;2019-202…

【数据库原理】(9)SQL简介

一.SQL 的发展历史 起源&#xff1a;SQL 起源于 1970 年代&#xff0c;由 IBM 的研究员 Edgar F. Codd 提出的关系模型概念演化而来。初期&#xff1a;Boyce 和 Chamberlin 在 IBM 开发了 SQUARE 语言的原型&#xff0c;后发展成为 SQL。这是为了更好地利用和管理关系数据库。…

Mysq之——分库分表

Mysq之——分库分表 简介分库分表的方式垂直分表垂直分库水平分库水平分表 图解&#xff1a;垂直分表与水平分表&#xff08;分库类似&#xff09;分库分表带来的问题 简介 分库分表就是为了解决由于数据量过大而导致数据库性能降低的问题&#xff0c;将原来独立的数据库拆分成…

鸿蒙应用中的通知

目录 1、通知流程 2、发布通知 2.1、发布基础类型通知 2.1.1、接口说明 2.1.2、普通文本类型通知 2.1.3、长文本类型通知 2.1.4、多行文本类型通知 2.1.5、图片类型通知 2.2、发布进度条类型通知 2.2.1、接口说明 2.2.2、示例 2.3、为通知添加行为意图 2.3.1、接…

神经网络框架的基本设计

一、神经网络框架设计的基本流程 确定网络结构、激活函数、损失函数、优化算法&#xff0c;模型的训练与验证&#xff0c;模型的评估和优化&#xff0c;模型的部署。 二、网络结构与激活函数 1、网络架构 这里我们使用的是多层感知机模型MLP(multilayer prrceptron)&#x…

iOS苹果和Android安卓测试APP应用程序的区别差异

在移动应用开发中&#xff0c;测试是一个至关重要的环节。无论是iOS苹果还是Android安卓&#xff0c;测试APP应用程序都需要注意一些差异和细节。本文将详细介绍iOS和Android的测试差异&#xff0c;包括操作系统版本、设备适配、测试工具和测试策略&#xff0c;并回答一些新手容…

Hive实战:分科汇总求月考平均分

文章目录 一、实战概述二、提出任务三、完成任务&#xff08;一&#xff09;准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 &#xff08;二&#xff09;实现步骤1、启动Hive Metastore服务2、启动Hive客户端3、创建分区的学生成绩表4、按分区加载数据5、查看分区…

C语言编译器(C语言编程软件)完全攻略(第二十部分:Code::Blocks下载地址和安装教程(图解))

介绍常用C语言编译器的安装、配置和使用。 二十、Code::Blocks下载地址和安装教程&#xff08;图解&#xff09; Code::Blocks 是一款免费开源的 C/C IDE&#xff0c;支持 GCC、MSVC 等多种编译器&#xff0c;还可以导入 Dev-C 的项目。Code::Blocks 的优点是&#xff1a;跨…

支持向量机(Support Vector Machines,SVM)

什么是机器学习 支持向量机&#xff08;Support Vector Machines&#xff0c;SVM&#xff09;是一种强大的机器学习算法&#xff0c;可用于解决分类和回归问题。SVM的目标是找到一个最优的超平面&#xff0c;以在特征空间中有效地划分不同类别的样本。 基本原理 超平面 在二…

YOLOv8改进 | 损失篇 | VarifocalLoss密集目标检测专用损失函数 (VFLoss,原论文一比一复现)

一、本文介绍 本文给大家带来的是损失函数改进VFLoss损失函数,VFL是一种为密集目标检测器训练预测IoU-aware Classification Scores(IACS)的损失函数,我经过官方的版本将其集成在我们的YOLOv8的损失函数使用上,其中有很多使用的小细节(否则按照官方的版本使用根本拟合不了…

代码随想录刷题第三十九天| 62.不同路径 ● 63. 不同路径 II

代码随想录刷题第三十九天 不同路径 (LC 62) 题目思路&#xff1a; 代码实现&#xff1a; class Solution:def uniquePaths(self, m: int, n: int) -> int:dp [[0 for _ in range(n1)] for _ in range(m1)]dp[0][1] 1for i in range(1,m1):for j in range(1, n1):dp[i]…

Qt6入门教程 2:Qt6下载与安装

Qt6不提供离线安装包&#xff0c;下载和安装实际上是一体的了。 关于Qt简介&#xff0c;详见&#xff1a;Qt6入门教程1&#xff1a;Qt简介 一.下载在线安装器 Qt官网 地址&#xff1a;https://download.qt.io/ 在线下载器地址&#xff1a;https://download.qt.io/archive/on…

PHP运行环境之宝塔软件安装及Web站点部署流程

PHP运行环境之宝塔软件安装及Web站点部署流程 1.1安装宝塔软件 官网&#xff1a;https://www.bt.cn/new/index.html 自行注册账号&#xff0c;稍后有用 下载安装页面&#xff1a;宝塔面板下载&#xff0c;免费全能的服务器运维软件 1.1.1Linux 安装 如图所示&#xff0c;宝…

使用STM32微控制器驱动LCD1602显示器

驱动LCD1602显示器是嵌入式系统常见的任务之一&#xff0c;而STM32微控制器因其灵活性和丰富的外设而成为了广泛采用的解决方案。在这篇文章中&#xff0c;我们将探讨如何使用STM32微控制器来驱动LCD1602显示器。我们将从STM32的GPIO配置、延时函数以及LCD1602的初始化和写入数…

深度学习中的自动化标签转换:对数据集所有标签做映射转换

在机器学习中&#xff0c;特别是在涉及图像识别或分类的项目中&#xff0c;标签数据的组织和准确性至关重要。本文探讨了一个旨在高效转换标签数据的 Python 脚本。该脚本在需要更新或更改类标签的场景中特别有用&#xff0c;这是正在进行的机器学习项目中的常见任务。我们将逐…

Windows BAT脚本 | 定时关机程序

使用说明&#xff1a;输入数字&#xff0c;实现一定时间后自动关机。 单位小时&#xff0c;用后缀 h 或 H。示例 1h 单位分钟&#xff0c;用后缀 m 或 M 或 min。示例 30min 单位秒。用后缀 s 或不用后缀。示例 100s 源码 及 配置方法 桌面新建文本文件&#xff0c;输入下面…

Jmeter相关概念

Jmeter相关概念 jmeter性能指标 Aggregate Report 是 JMeter 常用的一个 Listener&#xff0c;中文被翻译为“聚合报告”。今天再次有同行问到这个报告中的各项数据表示什么意思&#xff0c;顺便在这里公布一下&#xff0c;以备大家查阅。 如果大家都是做Web应用的性能测试&a…

实现并解决微服务间OpenFeign转发文件格式MultipartFile

场景 使用openfeign转发MultipartFile类型的文件时出现了下面的错误。 PostMapping(value "/upload", consumes MediaType.MULTIPART_FORM_DATA_VALUE) ApiOperation(value "导入") public ResponseJson<String> uploadFiles(RequestParam(&quo…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -小程序首页实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

ant-design-vue 使用本地iconfont.js

createFromIconfontCN只能使用【在线资源】&#xff0c;但是在线资源存在不稳定的风险 有人提了issue&#xff0c;不过目前也没有解决&#xff0c;但是有人提出了一种新的的解决方案 参考链接&#xff1a; https://github.com/ant-design/ant-design/issues/16480 main.js im…