剖析SpringBoot源码之一----从SpringApplication.run入手

目录

一. 前言

二. SpringBoot入口点

2.1. SpringApplication.run方法

2.2. SpringApplication构造方法

2.3. ResourceLoader

2.4. WebApplicationType枚举

2.5. 初识BootstrapRegistryInitializer、BootstrapRegistry

2.6. 初识ApplicationContextInitializer、ConfigurableApplicationContext

2.7. 初识ApplicationListener、ApplicationEvent、PayloadApplicationEvent

2.8. deduceMainApplicationClass方法

三. getSpringFactoriesInstances方法

3.1. getClassLoader()

3.2. SpringFactoriesLoader.loadFactoryNames

3.3. createSpringFactoriesInstances

3.4. AnnotationAwareOrderComparator.sort


一. 前言

        本文涉及代码所使用的SpringBoot版本为2.7.12(这是截至此文发布时JDK8支持的最新的SpringBoot版本),SpringBoot-3.0.0及以上版本必须要JDK17及以上版本才能支持,鉴于jdk-8u-202是Oracle JDK最后的免费版本,所以本系列基于JDK8支持的SpringBoot作分析。如果未来版本的SpringBoot源码有较大变动,则本系列再更新,欢迎持续关注。

二. SpringBoot入口点

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

上面这段代码相信使用SpringBoot的大家再熟悉不过了,是SpringBoot的应用程序启动入口,这也是SpringApplication(org.springframework.boot.SpringApplication)的最主要作用。SpringApplication没有继承除Object以外的任何类也没有实现任何接口,不需要考虑复杂的类层次性关系,这也是其适合作为学习SpringBoot源码入口点的主要原因。

2.1. SpringApplication.run方法

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

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}
public ConfigurableApplicationContext run(String... args) {
	long startTime = System.nanoTime();
	DefaultBootstrapContext bootstrapContext = createBootstrapContext();
	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);
		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);
		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;
}

上面就是SpringApplication的run方法源码,可以看到最终的run方法调用了构造方法new SpringApplication(primarySources)。

2.2. SpringApplication构造方法

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

@SuppressWarnings({ "unchecked", "rawtypes" })
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();
	this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

构造方法SpringApplication(Class<?>... primarySources)最终调用SpringApplication(ResourceLoader resourceLoader, Class<?>… primarySources)。下面来看SpringApplication构造方法每步代码的作用。

2.3. ResourceLoader

ResourceLoader(org.springframework.core.io.ResourceLoader)是用于加载资源(例如,类路径或文件系统资源)的策略接口。

public interface ResourceLoader {
	/** 
     * 从类路径加载的伪 URL 前缀:"classpath:" 
     */
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;


	/**
	 * 返回指定资源位置的Resource句柄。
	 */
	Resource getResource(String location);

	/**
	 * 返回此ResourceLoader使用的ClassLoader 。
	 */
	@Nullable
	ClassLoader getClassLoader();
}

ResourceLoader的层次性关系(子类型):

SpringApplication中的resourceLoader没有赋值,在printBanner(environment)方法中有使用但是也没赋值,只对局部变量有赋值,参见源码:

private Banner printBanner(ConfigurableEnvironment environment) {
	if (this.bannerMode == Banner.Mode.OFF) {
		return null;
	}
	ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
			: new DefaultResourceLoader(null);
	SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
	if (this.bannerMode == Mode.LOG) {
		return bannerPrinter.print(environment, this.mainApplicationClass, logger);
	}
	return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

2.4. WebApplicationType枚举

this.webApplicationType = WebApplicationType.deduceFromClasspath();

WebApplicationType(org.springframework.boot.WebApplicationType)列出了可能的 Web 应用程序类型的枚举:NONE、SERVLET、REACTIVE

public enum WebApplicationType {
	NONE,

	SERVLET,

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

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

	static WebApplicationType deduceFromApplicationContext(Class<?> applicationContextClass) {
		if (isAssignable(SERVLET_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
			return WebApplicationType.SERVLET;
		}
		if (isAssignable(REACTIVE_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
			return WebApplicationType.REACTIVE;
		}
		return WebApplicationType.NONE;
	}

	private static boolean isAssignable(String target, Class<?> type) {
		try {
			return ClassUtils.resolveClassName(target, null).isAssignableFrom(type);
		}
		catch (Throwable ex) {
			return false;
		}
	}
}

NONE:该应用程序不应作为Web应用程序运行,也不应启动嵌入式Web服务器。
SERVLET:该应用程序应作为基于Servlet的Web应用程序运行,并应启动嵌入式Servlet Web服务器。
REACTIVE:该应用程序应作为响应式Web应用程序运行,并应启动嵌入式响应式Web服务器。
WebApplicationType的deduceFromClasspath()方法实现了从类路径推断出Web应用程序类型的功能。
ClassUtils的isPresent(String className, @Nullable ClassLoader classLoader)方法可以通过传入类的全名和类加载器来判断该类是否被类加载器所加载。

应用引入的依赖会决定WebApplicationType类型,可以推出如下表格:

应用引入的依赖包含推断的类WebApplicationType
不引入web服务器-NONE
spring-boot-starter-webSERVLET_INDICATOR_CLASSES
WEBMVC_INDICATOR_CLASS
SERVLET
spring-boot-starter-webfluxWEBFLUX_INDICATOR_CLASSREACTIVE
spring-boot-starter-web和
spring-boot-starter-webflux
SERVLET_INDICATOR_CLASSES
WEBMVC_INDICATOR_CLASS
WEBFLUX_INDICATOR_CLASS
SERVLET

2.5. 初识BootstrapRegistryInitializer、BootstrapRegistry

this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));

BootstrapRegistryInitializer是在使用BootstrapRegistry之前对其进行初始化的回调接口(这是一个函数式接口)。

@FunctionalInterface
public interface BootstrapRegistryInitializer {
	/**
	 * 使用任何所需的registrations初始化给定的BootstrapRegistry 。
	 * @param 要初始化的BootstrapRegistry
	 */
	void initialize(BootstrapRegistry registry);

}

BootstrapRegistry是一个简单的对象注册表,在启动和Environment后处理期间可用,直到ApplicationContext准备好为止。

public interface BootstrapRegistry {
	/**
	 * 向注册表注册给定类型。如果给定的类型已经注册过并且没有作为singleton获取,则会被替换。
	 * @param type 实例类型
	 * @param instanceSupplier 实例供应者
	 */
	<T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier);

	/**
	 * 如果给定类型不存在,则向注册表注册该给定类型。
	 * @param type 实例类型
	 * @param instanceSupplier 实例供应者
	 */
	<T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier);

	/**
	 * 判断给定的类型是否存在。
	 */
	<T> boolean isRegistered(Class<T> type);

	/**
	 * 返回给定类型的任何现有BootstrapRegistry.InstanceSupplier
	 */
	<T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type);

	/**
	 * 添加一个ApplicationListener,当BootstrapContext关闭并且ApplicationContext已准备好时,
	 * 它将使用BootstrapContextClosedEvent调用。
	 */
	void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener);

	/**
	 * 在需要时提供实际实例的供应者
	 * @param <T> 实例类型
	 */
	@FunctionalInterface
	interface InstanceSupplier<T> {
		/**
		 * 工厂方法用于在需要时创建实例。
		 * @param context BootstrapContext可用于获取其他引导程序实例
		 * @return 实例
		 */
		T get(BootstrapContext context);

		/**
		 * 返回提供的实例的作用域。
		 * @since 2.4.2
		 */
		default Scope getScope() {
			return Scope.SINGLETON;
		}

		/**
		 * 返回一个带有更新的BootstrapRegistry.Scope的BootstrapRegistry.InstanceSupplier
		 * @param scope 新的作用域
		 * @since 2.4.2
		 */
		default InstanceSupplier<T> withScope(Scope scope) {
			Assert.notNull(scope, "Scope must not be null");
			InstanceSupplier<T> parent = this;
			return new InstanceSupplier<T>() {
				@Override
				public T get(BootstrapContext context) {
					return parent.get(context);
				}

				@Override
				public Scope getScope() {
					return scope;
				}
			};
		}

		/**
		 * 工厂方法用于为给定实例创建BootstrapRegistry.InstanceSupplier
		 * @param <T> 实例类型
		 * @param instance 实例
		 */
		static <T> InstanceSupplier<T> of(T instance) {
			return (registry) -> instance;
		}

		/**
		 * 工厂方法用于从Supplier创建BootstrapRegistry.InstanceSupplier
		 * @param <T> 实例类型
		 * @param supplier 提供实例的供应者
		 */
		static <T> InstanceSupplier<T> from(Supplier<T> supplier) {
			return (registry) -> (supplier != null) ? supplier.get() : null;
		}
	}

	/**
	 * 实例的作用域
	 * @since 2.4.2
	 */
	enum Scope {
		/**
		 * 单例实例。BootstrapRegistry.InstanceSupplier只会被调用一次,并且每次都会返回相同的实例
		 */
		SINGLETON,

		/**
		 * 原型实例。每当需要实例时,都会调用BootstrapRegistry.InstanceSupplier。
		 */
		PROTOTYPE
	}
}

BootstrapRegistry的层次性关系(子类型)

2.6. 初识ApplicationContextInitializer、ConfigurableApplicationContext

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

运行时加载的类:

SpringApplication的setInitializers方法:

public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
    this.initializers = new ArrayList<>(initializers);
}

ApplicationContextInitializer(org.springframework.context.ApplicationContextInitializer)是用于在刷新之前初始化Spring的ConfigurableApplicationContext的回调接口。(通常在需要对应用程序上下文进行一些编程初始化的Web应用程序中使用。例如,针对上下文环境注册属性源或激活配置文件)

@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
	/**
	 * 初始化给定的应用程序上下文。
	 * @param applicationContext 要配置的应用程序
	 */
	void initialize(C applicationContext);
}

ApplicationContextInitializer的层次性关系(子类型):

ConfigurableApplicationContext(org.springframework.context.ConfigurableApplicationContext)用于封装配置和生命周期方法

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
	/**
	 * 任意数量的这些字符都被视为单个字符串值中多个上下文配置路径之间的分隔符
	 */
	String CONFIG_LOCATION_DELIMITERS = ",; \t\n";

	/**
	 * 工厂中 ConversionService bean 的名称。如果未提供,则应用默认转换规则。
	 */
	String CONVERSION_SERVICE_BEAN_NAME = "conversionService";

	/**
	 * 工厂中 LoadTimeWeaver bean 的名称。
	 * 如果提供了这样的 bean,上下文将使用临时 ClassLoader 进行类型匹配,以允许 LoadTimeWeaver 处理所有实际的 bean 类。
	 */
	String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";

	/**
	 * 工厂中Environment bean 的名称。
	 */
	String ENVIRONMENT_BEAN_NAME = "environment";

	/**
	 * 工厂中系统属性 bean 的名称。
	 */
	String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";

	/**
	 * 工厂中系统环境 bean 的名称。
	 */
	String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

	/**
	 * 工厂中ApplicationStartup bean 的名称。
	 */
	String APPLICATION_STARTUP_BEAN_NAME = "applicationStartup";

	/**
	 * 关闭挂钩线程的名称:“SpringContextShutdownHook”。
	 */
	String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";


	/**
	 * 设置此应用程序上下文的唯一 ID。
	 */
	void setId(String id);

	/**
	 * 设置此应用程序上下文的父级。
	 */
	void setParent(@Nullable ApplicationContext parent);

	/**
	 * 为此应用程序上下文设置Environment。
	 * @since 3.1
	 */
	void setEnvironment(ConfigurableEnvironment environment);

	/**
	 * 以可配置的形式返回此应用程序上下文的Environment ,允许进一步定制。
	 */
	@Override
	ConfigurableEnvironment getEnvironment();

	/**
	 * 为此应用程序上下文设置ApplicationStartup 。
	 */
	void setApplicationStartup(ApplicationStartup applicationStartup);

	/**
	 * 返回此ApplicationStartup程序上下文的 ApplicationStartup。
	 */
	ApplicationStartup getApplicationStartup();

	/**
	 * 添加一个新的 BeanFactoryPostProcessor,
	 * 它将在刷新时应用于此应用程序上下文的内部 bean 工厂,然后再评估任何 bean 定义。
	 * 在上下文配置期间调用。
	 */
	void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);

	/**
	 * 添加一个新的 ApplicationListener,它将在上下文刷新和上下文关闭等上下文事件上得到通知。
	 */
	void addApplicationListener(ApplicationListener<?> listener);

	/**
	 * 指定 ClassLoader 来加载类路径资源和 bean 类。
	 * 这个上下文类加载器将被传递到内部 bean 工厂。
	 */
	void setClassLoader(ClassLoader classLoader);

	/**
	 * 使用此应用程序上下文注册给定的协议解析器,允许处理其他资源协议。
	 * 任何此类解析器都将在此上下文的标准解析规则之前调用。因此,它也可以覆盖任何默认规则。
	 */
	void addProtocolResolver(ProtocolResolver resolver);

	/**
	 * 加载或刷新配置的持久表示,它可能来自基于 Java 的配置、XML 文件、属性文件、关系数据库模式或其他格式。
	 * 由于这是一种启动方法,它应该在失败时销毁已经创建的单例,以避免悬空资源。
	 * 换句话说,在调用此方法之后,应该实例化所有或根本不实例化单例。
	 */
	void refresh() throws BeansException, IllegalStateException;

	/**
	 * 向 JVM 运行时注册一个关闭挂钩,在 JVM 关闭时关闭此上下文,除非它当时已经关闭。
	 * 该方法可以多次调用。每个上下文实例只会注册一个关闭挂钩(最多)。
	 */
	void registerShutdownHook();

	/**
	 * 关闭此应用程序上下文,释放实现可能持有的所有资源和锁。这包括销毁所有缓存的单例 bean。
	 * 注意:不在父上下文中调用close ;父上下文有自己独立的生命周期。
	 * 此方法可以多次调用而不会产生副作用:对已关闭上下文的后续close调用将被忽略
	 */
	@Override
	void close();

	/**
	 * 判断此应用上下文是否处于活动状态,即是否至少刷新过一次且尚未关闭。
	 */
	boolean isActive();

	/**
	 * 返回此应用程序上下文的内部 bean 工厂。可用于访问底层工厂的特定功能。
	 * 注意:不要用这个对bean工厂进行后处理;单例之前已经实例化过。
	 * 使用 BeanFactoryPostProcessor 在接触 bean 之前拦截 BeanFactory 设置过程。
	 * 通常,只有在上下文处于活动状态时才能访问此内部工厂,即在refresh()和close()之间。 
	 * isActive()标志可用于检查上下文是否处于适当的状态。
	 */
	ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

 ConfigurableApplicationContext的层次性关系(父类型):

ConfigurableApplicationContext的层次性关系(子类型):ConfigurableWebServerApplicationContext、ConfigurableReactiveWebApplicationContext、AbstractApplicationContext、ConfigurableWebApplicationContext

2.7. 初识ApplicationListener、ApplicationEvent、PayloadApplicationEvent

setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

SpringApplication的setListeners方法:

public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
    this.listeners = new ArrayList<>(listeners);
}

ApplicationListener(org.springframework.context.ApplicationListener)是由应用程序事件监听器实现的接口,也是基于观察者设计模式的标准java.util.EventListener接口。从Spring 3.0开始,ApplicationListener可以一般性地声明它感兴趣的事件类型。当使用Spring的ApplicationContext注册时,事件将被相应地过滤,只有匹配事件对象才会调用监听器。

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
	/**
	 * 处理应用程序事件。
	 * @param event 要响应的事件
	 * @param <E> 要监听的特定ApplicationEvent子类
	 */
	void onApplicationEvent(E event);


	/**
	 * 为给定的有效负载使用者创建一个新的ApplicationListener 。
	 * @param consumer 事件有效负载消费者
	 * @param <T> 事件负载的类型
	 */
	static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {
		return event -> consumer.accept(event.getPayload());
	}
}

ApplicationListener的层次性关系(父类型):

ApplicationListener的层次性关系(子类型):

ApplicationEvent(org.springframework.context.ApplicationEvent)可被所有应用程序扩展

ApplicationEvent的层次性关系

PayloadApplicationEvent(org.springframework.context.PayloadApplicationEvent)是携带任意有效负载的ApplicationEvent 。

PayloadApplicationEvent的层次性关系:

2.8. deduceMainApplicationClass方法

SpringApplication的deduceMainApplicationClass方法:

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代码的类,也是应用程序入口的main方法所在类。通过RuntimeException的getStackTrace()获得当前方法的堆栈跟踪,并遍历此堆栈跟踪,返回方法名称是main的类。

三. getSpringFactoriesInstances方法

        SpringApplication的getSpringFactoriesInstances方法提供了从应用的所有JAR包中的META-INF/spring.factories文件加载和实例化给定类型接口的实现类。

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
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

3.1. getClassLoader()

在传入的ResourceLoader是null时,调用ClassUtils.getDefaultClassLoader()方法

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

先从当前线程获取ClassLoader,没获取到再从class里获取

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

3.2. SpringFactoriesLoader.loadFactoryNames

/**
 * 使用给定的类加载器从"META-INF/spring.factories"加载给定类型的工厂实现的完全限定类名。
 * 从 Spring Framework 5.3 开始,如果为给定的工厂类型多次发现特定的实现类名称,则将忽略重复项。
 * @param factoryType 代表工厂的接口或抽象类
 * @param classLoader 用于加载资源的 ClassLoader;可以为null以使用默认值
 * @throws IllegalArgumentException 如果加载工厂名称时发生错误
 */
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	ClassLoader classLoaderToUse = classLoader;
	if (classLoaderToUse == null) {
		classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
	}
	String factoryTypeName = factoryType.getName();
	return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}

SpringFactoriesLoader的loadFactoryNames方法最终调用loadSpringFactories方法:

public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
	Map<String, List<String>> result = cache.get(classLoader);
	if (result != null) {
		return result;
	}

	result = new HashMap<>();
	try {
		Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			for (Map.Entry<?, ?> entry : properties.entrySet()) {
				String factoryTypeName = ((String) entry.getKey()).trim();
				String[] factoryImplementationNames =
						StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
				for (String factoryImplementationName : factoryImplementationNames) {
					result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
							.add(factoryImplementationName.trim());
				}
			}
		}

		// Replace all lists with unmodifiable lists containing unique elements
		result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
				.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
		cache.put(classLoader, result);
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
	return result;
}

SpringApplication的getSpringFactoriesInstances方法在调用SpringFactoriesLoader的loadSpringFactories方法时传入了classLoader,让SpringFactoriesLoader把该classLoader作为key在其成员字段cache(一个ConcurrentReferenceHashMap,key类型是ClassLoader,value是一个Map<String,List<String>>,value的key是factoryTypeName,value的value是factoryImplementationNames)中取出对应的value。由于这是首次调用,所以取出的value为null,需要对该key映射的value创建并赋值。

3.3. createSpringFactoriesInstances

createSpringFactoriesInstances方法用于创建Spring工厂实例(spring.factories的value的类对象)

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
	List<T> instances = new ArrayList<>(names.size());
	for (String name : names) {
		try {
			Class<?> instanceClass = ClassUtils.forName(name, classLoader);
			Assert.isAssignable(type, instanceClass);
			Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
			T instance = (T) BeanUtils.instantiateClass(constructor, args);
			instances.add(instance);
		}
		catch (Throwable ex) {
			throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
		}
	}
	return instances;
}

3.4. AnnotationAwareOrderComparator.sort

AnnotationAwareOrderComparator是OrderComparator的扩展,它支持 Spring 的org.springframework.core.Ordered接口以及@Order和@Priority注释, Ordered实例提供的顺序值覆盖静态定义的注释值(如果有)。
AnnotationAwareOrderComparator的sort方法使用默认AnnotationAwareOrderComparator对给定列表进行排序。

public static void sort(List<?> list) {
    if (list.size() > 1) {
        list.sort(INSTANCE);
    }
}

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2025-09-15 03:30:58 [restartedMain] [org.springframework.boot.SpringApplication]-[ERROR] Application run failed org.springframework.beans.factory.BeanDefinitionStoreException: Failed to parse configuration class [com.bjsasc.avplan.DmApplication]; nested exception is java.io.FileNotFoundException: class path resource [org/flywaydb/core/api/callback/FlywayCallback.class] cannot be opened because it does not exist at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:189) at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:319) at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:280) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:707) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533) at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) at com.bjsasc.avplan.DmApplication.main(DmApplication.java:29) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) Caused by: java.io.FileNotFoundException: class path resource [org/flywaydb/core/api/callback/FlywayCallback.class] cannot be opened because it does not exist at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:180) at org.springframework.core.type.classreading.SimpleMetadataReader.getClassReader(SimpleMetadataReader.java:55) at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:49) at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:103) at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.createMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:86) at org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataReaderFactory.getMetadataReader(ConcurrentReferenceCachingMetadataReaderFactory.java:73) at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:81) at org.springframework.context.annotation.ConfigurationClassParser.asSourceClass(ConfigurationClassParser.java:696) at org.springframework.context.annotation.ConfigurationClassParser$SourceClass.getInterfaces(ConfigurationClassParser.java:1024) at org.springframework.context.annotation.ConfigurationClassParser.processInterfaces(ConfigurationClassParser.java:386) at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:332) at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250) at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:199) at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:304) at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250) at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:207) at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:175) ... 19 common frames omitted
09-16
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

流华追梦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值