SpringBoot project started without listening port

premise

Our SpringBoot project relies on Dubbo, RocketMQ, Nacos, etc. occasionally one day, we found that we didn't register with SpringBootAdmin after startup, so we checked the reasons, searched online and found this article The springboot project starts and runs normally, but the port cannot listen for events and solutions The situation is similar. After the project is started, the dead loop is also started in the thread, as follows:

    @PostConstruct
    public void init() {
        log.info("==============initialization==============start");
        try {
            //Here's a piece of code to start the dead loop in the thread
            xxx.xxx
        } catch (Exception e) {
            log.error("", e);
        }
    }

Referring to the article, it may be that the dead loop has been running here before waiting for the listening port. Therefore, it is necessary to delay the startup of this code that opens the multi-threaded inner dead loop. The changes are as follows:

@Slf4j
@Component
//It's ranked 10th here
@Order(value = 10)
public class InitRunner implements ApplicationRunner {

    @Override
    public void run() {
        log.info("==============initialization==============start");
        try {
            //Here's a piece of code to start the dead loop in the thread
            xxx.xxx
        } catch (Exception e) {
            log.error("", e);
        }
    }
}

The test starts, but it still doesn't work. It doesn't seem to be the problem here. Continue to query the information and see this article SpringBoot built-in Tomcat startup time , since Tomcat doesn't listen to the port, debug it to see if the program doesn't listen to the port when it goes there.

Debug to critical code:

class:AbstractApplicationContext
   
    @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();
			}
		}
	}

onRefresh(); Method calls onrefresh () method in this class. See the notes:

	/**
	 * Template method which can be overridden to add context-specific refresh work.
	 * Called on initialization of special beans, before instantiation of singletons.
	 * <p>This implementation is empty.
	 * @throws BeansException in case of errors
	 * @see #refresh()
	 */
	protected void onRefresh() throws BeansException {
		// For subclasses: do nothing by default.
	}

The general meaning is:

Template method, which can be overridden to add context specific refresh work. Called when initializing a special bean, and then instantiate the singleton.

This implementation is empty.

Take a look at the following results of this method:

Obviously, the implementation in servletwebserver ApplicationContext should be called, but I made a breakpoint debugging and didn't enter this method:

	@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}

Instead, the empty method is directly adjusted:

It's amazing.

Found a normal project, and sure enough, it entered the servletwebserver ApplicationContext. Then the difference between the two projects was. It was really oolong.

My project does not rely on spring boot starter web

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

Add this paragraph and try it. It's ok as expected.

2021-04-15 10:33:52.538 [main] INFO [org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start: 204] - Tomcat started on port(s): 8080 (http) with context path ''
2021-04-15 10:33:52.546 [main] INFO [org.springframework.boot.StartupInfoLogger.logStarted: 61] - Started XXXMainApplication in 59.654 seconds (JVM running for 64.354)

Maybe I didn't rely on it because I thought that this project uses Dobbo instead of spring web. Later, SpringBootAdmin was added to monitor the project startup port, and then SpringBootAdmin called the interface to query information, and then forgot to add this dependency. It's really a big oolong, but I also learned something from debugging the source code. I feel that the source code is really a good thing.

 

Keywords: Dubbo Spring Spring Boot Tomcat Nacos

Added by apulmca2k4 on Mon, 07 Mar 2022 20:33:16 +0200