Springboot应用的初始化源码你了解吗?

本章内容介绍一个Springboot应用程序从Main主入口执行的源码流程解析。

上图:

@SpringBootApplication
@EnableScheduling//开启定时任务
@MapperScan("com.tky.dao")
public class ModelEngineApplication {

    public static void main(String[] args) {
        SpringApplication.run(ModelEngineApplication.class, args);
    }

}

 

一个程序的开启从Main主入口开始。

程序调用SpringApplication.run方法。入参时自定义的启动类类型,和args参数。

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

 

继续调用run的重载接口

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

 

 在run接口里新建一个SpringApplication对象

public SpringApplication(Class<?>... primarySources) {
        this(null, primarySources);
    }

 

继续调用SpringApplication的构造函数

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// resourceLoader是null
this.resourceLoader = resourceLoader;
// primarySources 是启动类类型,在这里是“ModelEngineApplication.class” Assert.notNull(primarySources,
"PrimarySources must not be null");
     // 启动类类型赋值给应用对象
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 寻找webApplicationType的类型 应用使用spring-boot-web以来,返回SERVLET类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 构造一个引导注册初始化类,它可以在使用前初始化BootstrapRegistry
this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 构造一个应用上下文初始化类,它可以在刷新(refresh)ConfigureApplicationContext前初始化它 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.
class));
// 构造一个应用进程事件监听器,一般主要是用于监控应用内部的一些运行状况,在应用开发中也可以使用 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.
class));
// 一个推断main函数所在类,返回ModelEnginceApplication.class
this.mainApplicationClass = deduceMainApplicationClass(); }

 

 WebApplicationType.deduceFromClasspath()的源码如下:
public enum 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;

    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";

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

 

getSpringFactoriesInstances(BootstrapRegistryInitializer.class))方法的源码如下:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
        return getSpringFactoriesInstances(type, new Class<?>[] {}); 
    }

 

调用 getSpringFactoriesInstances(type, new Class<?>[] {})方法
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        // 返回AppClassLoader对象
ClassLoader classLoader
= getClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances);
// 这里最终返回一个
BootstrapRegistryInitializer
return instances;
}

 

第一个调用getClassLoader()的源码如下:

    public ClassLoader getClassLoader() {
        if (this.resourceLoader != null) {
            return this.resourceLoader.getClassLoader();
        }
        return ClassUtils.getDefaultClassLoader();
    }

 

直接去看 ClassUtils.getDefaultClassLoader(),发现最后返回了AppClassLoader类型;

    public static ClassLoader getDefaultClassLoader() {
        ClassLoader cl = null;
        try {
            cl = Thread.currentThread().getContextClassLoader();
        }
        catch (Throwable ex) {
            // Cannot access thread context ClassLoader - falling back...
        }
        if (cl == null) {
            // No thread context class loader -> use class loader of this class.
            cl = ClassUtils.class.getClassLoader();
            if (cl == null) {
                // getClassLoader() returning null indicates the bootstrap ClassLoader
                try {
// 进入这个方法 cl
= ClassLoader.getSystemClassLoader(); } catch (Throwable ex) { // Cannot access system ClassLoader - oh well, maybe the caller can live with null... } } } return cl; }
    public static ClassLoader getSystemClassLoader() {
        // 进入这个方法
initSystemClassLoader();
if (scl == null) { return null; } SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; }

 

    private static synchronized void initSystemClassLoader() {
        if (!sclSet) {
            if (scl != null)
                throw new IllegalStateException("recursive invocation");
            sun.misc.Launcher l = sun.misc.Launcher.getLauncher();
            if (l != null) {
                Throwable oops = null;
// 进入这个方法 scl
= l.getClassLoader(); try { scl = AccessController.doPrivileged( new SystemClassLoaderAction(scl)); } catch (PrivilegedActionException pae) { oops = pae.getCause(); if (oops instanceof InvocationTargetException) { oops = oops.getCause(); } } if (oops != null) { if (oops instanceof Error) { throw (Error) oops; } else { // wrap the exception throw new Error(oops); } } } sclSet = true; } }

 

  public ClassLoader getClassLoader() {
        return this.loader;
    }

 

发现调用了Launcher类的全局变量loader,它在构造Launcher方法被赋值,所以看Launcher类的构造函数源码:

public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
// 在这里生成了AppClassLoader
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); if (var2 != null) { SecurityManager var3 = null; if (!"".equals(var2) && !"default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); } catch (IllegalAccessException var5) { } catch (InstantiationException var6) { } catch (ClassNotFoundException var7) { } catch (ClassCastException var8) { } } else { var3 = new SecurityManager(); } if (var3 == null) { throw new InternalError("Could not create SecurityManager: " + var2); } System.setSecurityManager(var3); } }

 

推断出Main函数所在方法的类,实现原理比较巧妙,新建了一个运行时异常对象,通过这个对象获取当前的调用函数堆栈数组StackTrace,之后遍历这个堆栈数组,找到方法名为main的类,返回这个类。

    private Class<?> deduceMainApplicationClass() {
        try {
            StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                if ("main".equals(stackTraceElement.getMethodName())) {
                    return Class.forName(stackTraceElement.getClassName());
                }
            }
        }
        catch (ClassNotFoundException ex) {
            // Swallow and continue
        }
        return null;
    }

 

构建SpringApplication对象后,调用了该对象的run方法:

    public ConfigurableApplicationContext run(String... args) {
        long startTime = System.nanoTime();
// 创建引导上下文对象 DefaultBootstrapContext bootstrapContext
= createBootstrapContext();
// 初始化可配置应用上下问对象,默认为null ConfigurableApplicationContext context
= null; configureHeadlessProperty();
// 创建应用上下文对象 SpringApplicationRunListeners listeners
= getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment);
// 根据 WebApplicationType=SERVLET 构建 AnnotationConfigServletWebServerApplicationContext对象 context
= createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新上下文 refreshContext(context); afterRefresh(context, applicationArguments); Duration timeTakenToStartup
= Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); }
// 开始监听上下文 listeners.started(context, timeTakenToStartup);
// 调用ApplicationRunner方法 callRunners(context, applicationArguments); }
catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }

 callRunners方法源码如下:

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<>();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 继承Runner的类会在应用启动时调用run方法,可以按照Order进行排序 AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) { if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } }

 

posted @ 2023-07-26 15:08  IT知识生产小店铺  阅读(23)  评论(0编辑  收藏  举报