四篇文章带你玩转springboot——3启动源码及外部化配置

 第1章 main入口

public static void main(String[] args) {
    //代码很简单SpringApplication.run();
	SpringApplication.run(ConsumerApp.class, args);
}
public static ConfigurableApplicationContext run(Class<?> primarySource,
                                                 String... args) {
    //这个里面调用了run() 方法,我们转到定义
    return run(new Class<?>[] { primarySource }, args);
}
 
 
//这个run方法代码也很简单,就做了两件事情
//1、new了一个SpringApplication() 这么一个对象
//2、执行new出来的SpringApplication()对象的run()方法
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
                                                 String[] args) {
    return new SpringApplication(primarySources).run(args);
}

上面代码主要做了两件事情。

  • 第一步new了一个SpringApplication对象

  • 第二步调用了run()方法。

1.1 SpringApplication

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		//1、先把主类保存起来
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		//2、判断运行项目的类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		//3、扫描当前路径下META-INF/spring.factories文件的,加载ApplicationContextInitializer接口实例
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		//4、扫描当前路径下META-INF/spring.factories文件的,加载ApplicationListener接口实例
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
}

1.1.1 判断运行环境

构造方法内会调用枚举WebApplicationType的deduceFromClasspath方法获得应用类型并设置当前应用是普通web应用、响应式web应用还是非web应用。

this.webApplicationType = WebApplicationType.deduceFromClasspath();

deduceFromClasspath方法由枚举WebApplicationType提供,具体实现如下:  

static WebApplicationType deduceFromClasspath() {
    //当classpath下只存在org.springframework.web.reactive.DispatcherHandler,
    //且不存在org.springframework.web.servlet.DispatcherServlet,也不存在
    //org.glassfish.jersey.servlet.ServletContainer则运行环境为reactive,该模式是非阻塞模式
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
        && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}

 推断的过程中重点调用了ClassUtils.isPresent()方法,用来判断指定类名的类是否存在,是否可以进行加载。ClassUtils.isPresent()方法源代码如下:

public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
    try {
        forName(className, classLoader);
        return true;
    }
    catch (IllegalAccessError err) {
        throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
                                        className + "]: " + err.getMessage(), err);
    }
    catch (Throwable ex) {
        // Typically ClassNotFoundException or NoClassDefFoundError...
        return false;
    }
}

isPresent()方法调用了forName()方法,如果在调用forName()方法的过程中出现异常则返回false,也就是目标类不存在。否则,返回true。

看一下forName()方法的部分代码:

public static Class<?> forName(String name, @Nullable ClassLoader classLoader)
			throws ClassNotFoundException, LinkageError {

	// 此处省略一些非空和基础类型的判断逻辑代码

	ClassLoader clToUse = classLoader;
	if (clToUse == null) {
	    //如果为空则获取默认classLoader
		clToUse = getDefaultClassLoader();
	}
	try {
	    // 返回加载户的Class。
		return Class.forName(name, false, clToUse);
	} catch (ClassNotFoundException ex) {
	    // 如果直接加载类出现异常,则尝试加载内部类。
		int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
		if (lastDotIndex != -1) {
		    // 拼接内部类
			String innerClassName =
					name.substring(0, lastDotIndex) + INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
			try {
				return Class
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SpringBoot2的启动流程是通过@SpringBootApplication注解自动配置来实现的。该注解包含了多个注解的组合,其中包括@ComponentScan、@EnableAutoConfiguration和@Configuration等。通过这些注解,Spring Boot会自动扫描并加载配置类,并根据自动配置规则来配置应用程序。 具体而言,当应用程序启动时,Spring Boot会创建一个Spring应用程序上下文。在创建上下文的过程中,会先加载主配置类(通常是包含main方法的类),然后根据@ComponentScan注解扫描指定包下的所有组件。 接下来,Spring Boot会根据@EnableAutoConfiguration注解自动配置应用程序。这个注解会根据classpath和条件匹配的规则,加载配置类,并将它们注册到应用程序上下文中。这些配置类使用了@Configuration注解,会声明一些Bean,并根据条件来决定是否生效。 最后,Spring Boot启动应用程序,并执行相应的事件处理器。这些事件处理器可以通过自定义ApplicationListener来实现。在应用程序运行期间,Spring Boot会触发不同的事件,并调用相应的事件处理器。 参考文献: 引用:SpringBoot2 | @SpringBootApplication注解 自动配置流程源码分析(三) [2] 引用:SpringBoot2 | SpringBoot监听器源码分析 | 自定义ApplicationListener(六) 引用:该系列主要还是Spring的核心源码,不过目前Springboot大行其道,所以就从Springboot开始分析。最新版本是Springboot2.0.4,Spring5,所以新特性本系列后面也会着重分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木_2024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值