springboot web项目启动挂掉之谜

springboot web项目启动挂掉之谜

    • 环境准备
    • 场景描述
    • 现实思考
    • 找出原因

环境准备

  1. idea 2020.1.2
  2. maven 3.6.3
  3. jdk 1.8
  4. 初始化springboot 项目demo

场景描述

  1. 场景描述:很多人在学习,或者搭建springboot 项目的时候, 或多或少都会遇到项目 项目点击启动, 没有任何报错,就挂掉了, 例如:springboot web项目启动挂掉之谜_第1张图片
  2. 怎么就解决呢? 如果不了解springboot的, 肯定会百度,百度大多解决办法如下:
    添加web依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
  1. 按照第二步添加web依赖:springboot web项目启动挂掉之谜_第2张图片
    在尝试启动:springboot web项目启动挂掉之谜_第3张图片
    启动成功, 度娘还是很管用, 问题解决了…

现实思考

既然添加spring-boot-starter-web 能够解决问题, 那我们肯定也想知道为什么项目启动需要我们添加spring-boot-starter-web呢? 不添加为什么会 挂掉呢? 接下来我们一起来看看springboot项目启动的过程, 找到我们懵逼的原因在哪…

找出原因

  1. 我们从springboot 启动找出 不添加web依赖 项目自动挂掉的原因
// 项目启动
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
// SpringBootApplication 类run方法的实现里面有一个刷新上下文的方法refreshContext()调用
//  在refreshContext()方法里面
private void refreshContext(ConfigurableApplicationContext context) {
		// 刷新应用上下文
		refresh((ApplicationContext) context);
		// 判断是否给应用上下文注册或者关机的钩子操作 默认true
		if (this.registerShutdownHook) {
			try {
				// 给应用上下文注册钩子
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}
// 钩子:向JVM运行时注册一个关闭钩子,在JVM关闭时关闭此上下文,除非此时它已经关闭
@Override
	public void registerShutdownHook() {
		// 判断关闭钩子是否注册
		if (this.shutdownHook == null) {
			// 尚未注册, 执行
			this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
				@Override
				public void run() {
					synchronized (startupShutdownMonitor) {
						doClose();
					}
				}
			};
	
		Runtime.getRuntime().addShutdownHook(this.shutdownHook); // 添加关闭注册钩子
		}
	}


// 到这相信大家会看出点问题, 主要就是startupShutdownMonitor监视器 是否执行doClose()方法, 当我们不引入web依赖时, startupShutdownMonitor 会监视并执行doClose(), 导致系统无报错挂掉

// 那为什么呢
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 判断应用类型, 从而选择内嵌服务器
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

// 当我们引入web依赖时webApplicationType 为servlet, 系统会给他加载内嵌服务器, 但是当我们 不引入时,webApplicationType 为 NONE

springboot web项目启动挂掉之谜_第4张图片

  1. 通过对代码的追朔, 在我们不引入web依赖, 也不指定项目所属的服务类型例如SERVLET, 在执run方法时就不能创建对应的服务类型, 导致连接vm失败, 项目挂掉, 所以如果我们不引用web依赖, 就指定其他服务类型
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            // 去掉tomcat
            <exclusions>  
                <exclusion>  
                    <groupId>org.springframework.boot</groupId>  
                    <artifactId>spring-boot-starter-tomcat</artifactId>  
                </exclusion>  
            </exclusions> 
        </dependency>
 
 // 加入
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>

你可能感兴趣的:(springboot,spring,boot)