启动流程图(个人理解)

springboot 启动一个类 springboot启动类代码_spring

我们都是知道SpringBoot启动其实了类似下面的代码

自动定义启动类代码

@Configuration
@Component
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class StudySpringApplication {
	public static void main(String[] args) {
		SpringApplication.run(StudySpringApplication.class, args);
	}
}

其实里面较为核心代码是

SpringApplication.run(StudySpringApplication.class, args);

启动类源码

下面我们就开始对这个代码的源码进行分析
首先进到对应的方法里面

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

首先我们来解读下改方法上的注释
原文

Static helper that can be used to run a SpringApplication from the specified sources using default settings and user supplied arguments.
Params:
primarySources – the primary sources to load
args – the application arguments (usually passed from a Java main method)
Returns:
the running ApplicationContext

翻译后的(加上个人理解)
该静态方法主要根据用户提供主启动类和其他参数,实例化一个SpringApplication,并返回一个ApplicationContext
参数:
primarySources–要加载的主要源
args–应用程序参数(通常从Java主方法传递)
返回:
运行中的应用上下文(ApplicationContext)
上面的源码我们拆分成两部分来分析,
一、new SpringApplication(primarySources)实例化对象,
二、执行run(args)
下面我们看他们的具体源码,进行分析

实例化对象new SpringApplication(primarySources)

核心源码

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();
	}

注释分析

注释原文
Create a new SpringApplication instance. The application context will load beans from the specified primary sources (see class-level documentation for details. The instance can be customized before calling run(String...).
Params:
resourceLoader – the resource loader to use
primarySources – the primary bean sources
See Also:
run(Class, String[]), setSources(Set)
翻译原文

创建一个新的SpringApplication实例。应用程序上下文将从指定的主源加载bean。可以在调用run(String…)之前自定义实例。
参数:
resourceLoader–要使用的资源加载器
primarySources–主要的bean源
该实例主要方法:
run(Class, String[]), setSources(Set)

源码拆解分析

对于资源加载器和主启动类属性赋值,较为简单没有分析必要

对应用类型赋值

SpringBoot启动时,在创建SpringApplication的构造方法内会调用枚举WebApplicationType的deduceFromClasspath方法获得应用类型并设置当前应用是普通web应用、响应式web应用还是非web应用。

this.webApplicationType = WebApplicationType.deduceFromClasspath();

我们先看下webApplicationType都有哪些类型

/**
	 * The application should not run as a web application and should not start an
	 * embedded web server.
	 */
	NONE,

	/**
	 * The application should run as a servlet-based web application and should start an
	 * embedded servlet web server.
	 */
	SERVLET,

	/**
	 * The application should run as a reactive web application and should start an
	 * embedded reactive web server.
	 */
	REACTIVE;

NONE:应用程序不作为web应用启动,不启动内嵌的服务。
SERVLET:应用程序以基于servlet的web应用启动,需启动内嵌servlet web服务。
REACTIVE:应用程序以响应式web应用启动,需启动内嵌的响应式web服务。

源码:

private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

	private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";

	private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";

	private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

	private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";

	private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
	
static WebApplicationType deduceFromClasspath() {
		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()方法,该方法源码是

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

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

public static Class<?> forName(String name, @Nullable ClassLoader classLoader) throws ClassNotFoundException, LinkageError {
        Assert.notNull(name, "Name must not be null");
        Class<?> clazz = resolvePrimitiveClassName(name);
        if (clazz == null) {
            clazz = (Class)commonClassCache.get(name);
        }

        if (clazz != null) {
            return clazz;
        } else {
            Class elementClass;
            String elementName;
            if (name.endsWith("[]")) {
                elementName = name.substring(0, name.length() - "[]".length());
                elementClass = forName(elementName, classLoader);
                return Array.newInstance(elementClass, 0).getClass();
            } else if (name.startsWith("[L") && name.endsWith(";")) {
                elementName = name.substring("[L".length(), name.length() - 1);
                elementClass = forName(elementName, classLoader);
                return Array.newInstance(elementClass, 0).getClass();
            } else if (name.startsWith("[")) {
                elementName = name.substring("[".length());
                elementClass = forName(elementName, classLoader);
                return Array.newInstance(elementClass, 0).getClass();
            } else {
                ClassLoader clToUse = classLoader;
                if (classLoader == null) {
                    clToUse = getDefaultClassLoader();
                }

                try {
                    return Class.forName(name, false, clToUse);
                } catch (ClassNotFoundException var9) {
                    int lastDotIndex = name.lastIndexOf(46);
                    if (lastDotIndex != -1) {
                        String innerClassName = name.substring(0, lastDotIndex) + '$' + name.substring(lastDotIndex + 1);

                        try {
                            return Class.forName(innerClassName, false, clToUse);
                        } catch (ClassNotFoundException var8) {
                        }
                    }
                    throw var9;
                }
            }
        }
    }
初始化集合赋值
//初始化集合赋值
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

根据当前类名,去找到所有包含META-INF/spring.factories的jar包,获取文件中该类名(ApplicationContextInitializer)为key值的value值

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// Use names and ensure unique to protect against duplicates
		//根据当前类名,去找到所有META-INF/spring.factories的jar包,获取该类名为key值的value值
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		//实例化获取的对象集合
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		//根据@Order注解进行排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
监听器集合赋值
//监听器集合赋值
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

集合获取方法同上,根据当前类名,去找到所有META-INF/spring.factories的jar包,获取该类名为key值的value值,然后返回根据@order注解排序后的实例化集合。

获取主启动类集合
this.mainApplicationClass = deduceMainApplicationClass();