SpringBoot启动原理

SpringBootTest添加了@SpringBootApplication注解,标识这是一个配置类。调用SpringApplication的run方法,将配置类传入进行启动。

@SpringBootApplication
public class SpringBootTest {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootTest.class);
    }
}
1.SpringApplication实例化

调用SpringApplication的静态run方法,会先去实例化一个SpringApplication对象。

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

SpringApplication实例化主要做了以下几件事
(1)获取一个配置类集合primarySources。这个配置类就是调用run方法传入的类。
(2)获取应用类型,判断应用类型是Servlet类型还是Reactive类型。
(3)从spring.factories获取全部的ApplicationContextInitializer类。
(4)从spring.factories获取全部的ApplicationListener类。
(5)根据Main方法推断出项目真正的启动类。

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();
}
1.1WebApplicationType静态推断应用类型的方法。
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;
}
1.2从spring.factories获取指定类型的类

关键代码:SpringFactoriesLoader.loadFactoryNames(type, classLoader);
主要做了2件事:
(1)从spring.factories加载指定类型的实现类。
(2)实例化指定类型的实现类。

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();
	// 使用名字的Set集合是为了避免重复
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

根据给到的类加载器,从META-INF/spring.factories加载指定类型的实现类的全限定类名。

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	String factoryTypeName = factoryType.getName();
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

类加载器获取它加载的所有META-INF/spring.factories文件,遍历每个文件的key-value键值对,添加到Map集合中。再将这个类加载器获取到的结果集合添加到缓存中,下一次直接从缓存中读取这个类加载器加载的spring.factories内容。

从缓存中获取的MultiValueMap本质是一个Map<K, List>,添加元素的时候,会根据key先获取到List集合,再向这个List集合添加value。

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

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

	try {
		Enumeration<URL> urls = (classLoader != null ?
				classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
				ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
		result = new LinkedMultiValueMap<>();
		//遍历每一个spring.factories文件
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			UrlResource resource = new UrlResource(url);
			Properties properties = PropertiesLoaderUtils.loadProperties(resource);
			//遍历每一个key-value结果
			for (Map.Entry<?, ?> entry : properties.entrySet()) {
				String factoryTypeName = ((String) entry.getKey()).trim();
				//value根据逗号分割
				for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
					result.add(factoryTypeName, factoryImplementationName.trim());
				}
			}
		}
		cache.put(classLoader, result);
		return result;
	}
	catch (IOException ex) {
		throw new IllegalArgumentException("Unable to load factories from location [" +
				FACTORIES_RESOURCE_LOCATION + "]", ex);
	}
}

通过Constructor.newInstance方式构造从spring.factories获取的指定类型的实现类的实例。

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;
}
2.run方法实现

SpringApplication的run方法主要完成以下几件事情:
(1)调用StopWatch的start方法记录一个开始时间。
(2)设置系统属性java.awt.headless为true,开启headless模式。
(3)从META-INF/spring.factories中获取SpringApplicationRunListener类型的实现类。
(4)发布ApplicationStartingEvent事件。
(5)配置环境信息,发布ApplicationEnvironmentPreparedEvent事件。
(6)创建应用上下文。
(7)预初始化上下文,循环调用ApplicationContextInitializer的initialize方法,发布ApplicationContextInitializedEvent事件。
(8)将加了@SpringBootApplication注解的配置类注册到BeanFactory的IOC容器中,发布ApplicationPreparedEvent事件。
(9)刷新Spring上下文,调用AbstractApplicationContext的refresh方法,启动Spring容器。
(10)调用StopWatch的stop方法记录一个结束时间。
(11)发布ApplicationStartedEvent事件。
(12)发布带有LivenessState.CORRET的AvailabilityChangeEvent事件,指示应用程序被视为活动状态。
(13)发布ApplicationReadyEvent。
(14)发布带有ReadabilityState.ACCEPTING_TRAFFIC的AvailabilityChangeEvent事件,指示应用程序已准备就绪,可以
处理请求。
(15)如果启动时发生异常,则发布ApplicationFailedEvent事件。

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	SpringApplicationRunListeners listeners = getRunListeners(args);
	listeners.starting();
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext();
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		listeners.started(context);
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}
2.1记录开始时间

开启一个没有名称的任务。并记录当前时间。

public void start() throws IllegalStateException {
	start("");
}

public void start(String taskName) throws IllegalStateException {
	if (this.currentTaskName != null) {
		throw new IllegalStateException("Can't start StopWatch: it's already running");
	}
	this.currentTaskName = taskName;
	this.startTimeNanos = System.nanoTime();
}
2.2 设置系统属性java.awt.headless

将系统属性java.awt.headless设置为true。

private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";

private boolean headless = true;

private void configureHeadlessProperty() {
	System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
			System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
2.3 获取SpringApplicationRunListener类型的实现类

从spring.factories中加载SpringApplicationRunListener类型的实现类,加载方法和实例化SpringApplication加载ApplicationContextInitializer、ApplicationListener实现类一样。

private SpringApplicationRunListeners getRunListeners(String[] args) {
	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
	return new SpringApplicationRunListeners(logger,
			getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

遍历监听器,调用starting方法,SpringApplicationRunListener的子类EventPublishingRunListener会通过一个多播器广播ApplicationStartingEvent事件。

class SpringApplicationRunListeners {
	void starting() {
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}
}

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}
}
2.4 环境准备

根据应用类型创建ConfigurableEnvironment实例。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments) {
	//创建和配置环境信息
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach(environment);
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

private ConfigurableEnvironment getOrCreateEnvironment() {
	if (this.environment != null) {
		return this.environment;
	}
	switch (this.webApplicationType) {
	case SERVLET:
		return new StandardServletEnvironment();
	case REACTIVE:
		return new StandardReactiveWebEnvironment();
	default:
		return new StandardEnvironment();
	}
}

调用监听器的environmentPrepared方法,广播ApplicationEnvironmentPreparedEvent事件。

void environmentPrepared(ConfigurableEnvironment environment) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.environmentPrepared(environment);
	}
}

@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
	this.initialMulticaster
			.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
2.5 使用策略模式创建应用上下文

不同的应用类型创建不同的ApplicationContext。
对于Servlet应用类型,创建应用上下文类型是AnnotationConfigServletWebServerApplicationContext;
对于Reactive应用类型,创建应用上下文类型是AnnotationConfigReactiveWebServerApplicationContext;
默认是AnnotationConfigApplicationContext。这三个类有个共同的父类ConfigurableApplicationContext。

public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
		+ "annotation.AnnotationConfigApplicationContext";

public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
		+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
		+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

protected ConfigurableApplicationContext createApplicationContext() {
	Class<?> contextClass = this.applicationContextClass;
	if (contextClass == null) {
		try {
			switch (this.webApplicationType) {
			case SERVLET:
				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
				break;
			case REACTIVE:
				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
				break;
			default:
				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
			}
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
		}
	}
	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
2.6 预初始化上下文

从上下文获取BeanFactory,设置是否允许Bean定义覆盖;以及如果允许延迟初始化,添加一个BeanFactory后置处理器LazyInitializationBeanFactoryPostProcessor。

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
	SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	postProcessApplicationContext(context);
	applyInitializers(context);
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// Load the sources
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}

循环调用SpringApplication实例化获取的ApplicationContextInitializer实现类的initialize方法。

protected void applyInitializers(ConfigurableApplicationContext context) {
	for (ApplicationContextInitializer initializer : getInitializers()) {
		Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
				ApplicationContextInitializer.class);
		Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
		initializer.initialize(context);
	}
}

发布ApplicationContextInitializedEvent事件。

void contextPrepared(ConfigurableApplicationContext context) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.contextPrepared(context);
	}
}

@Override
public void contextPrepared(ConfigurableApplicationContext context) {
	this.initialMulticaster
			.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}

这里拿到的是run方法传入的配置类,也就是加了@SpringBootApplication的类。

public Set<Object> getAllSources() {
	Set<Object> allSources = new LinkedHashSet<>();
	if (!CollectionUtils.isEmpty(this.primarySources)) {
		allSources.addAll(this.primarySources);
	}
	if (!CollectionUtils.isEmpty(this.sources)) {
		allSources.addAll(this.sources);
	}
	return Collections.unmodifiableSet(allSources);
}

创建一个BeanDefinitionLoader,调用load方法

protected void load(ApplicationContext context, Object[] sources) {
	if (logger.isDebugEnabled()) {
		logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
	}
	BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
	if (this.beanNameGenerator != null) {
		loader.setBeanNameGenerator(this.beanNameGenerator);
	}
	if (this.resourceLoader != null) {
		loader.setResourceLoader(this.resourceLoader);
	}
	if (this.environment != null) {
		loader.setEnvironment(this.environment);
	}
	loader.load();
}

构造Bean定义读取器和扫描器

BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
	Assert.notNull(registry, "Registry must not be null");
	Assert.notEmpty(sources, "Sources must not be empty");
	this.sources = sources;
	this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
	this.xmlReader = new XmlBeanDefinitionReader(registry);
	if (isGroovyPresent()) {
		this.groovyReader = new GroovyBeanDefinitionReader(registry);
	}
	this.scanner = new ClassPathBeanDefinitionScanner(registry);
	this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}

加载类

private int load(Class<?> source) {
	if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
		// Any GroovyLoaders added in beans{} DSL can contribute beans here
		GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
		load(loader);
	}
	if (isEligible(source)) {
		this.annotatedReader.register(source);
		return 1;
	}
	return 0;
}

调用AnnotatedBeanDefinitionReader的register方法,将配置类注册到BeanFactory。

public void register(Class<?>... componentClasses) {
	for (Class<?> componentClass : componentClasses) {
		registerBean(componentClass);
	}
}

发布ApplicationPreparedEvent事件。

void contextLoaded(ConfigurableApplicationContext context) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.contextLoaded(context);
	}
}

public void contextLoaded(ConfigurableApplicationContext context) {
	for (ApplicationListener<?> listener : this.application.getListeners()) {
		if (listener instanceof ApplicationContextAware) {
			((ApplicationContextAware) listener).setApplicationContext(context);
		}
		context.addApplicationListener(listener);
	}
	this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
2.6 刷新上下文

刷新上下文最终会调用AbstractApplicationContext的refresh方法。启动Spring容器。这个refresh方法主要是实例化BeanFactoryPostProcess和BeanPostProcess,并调用这些后置处理器的一些特定方法。已经实例化非延迟加载类。

private void refreshContext(ConfigurableApplicationContext context) {
	if (this.registerShutdownHook) {
		try {
			context.registerShutdownHook();
		}
		catch (AccessControlException ex) {
			// Not allowed in some environments.
		}
	}
	refresh((ApplicationContext) context);
}

protected void refresh(ApplicationContext applicationContext) {
	Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
	refresh((ConfigurableApplicationContext) applicationContext);
}

protected void refresh(ConfigurableApplicationContext applicationContext) {
	applicationContext.refresh();
}
2.7 事件发布

发布ApplicationStartedEvent事件

void started(ConfigurableApplicationContext context) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.started(context);
	}
}

@Override
public void started(ConfigurableApplicationContext context) {
	context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
	AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}

发布带有LivenessState.CORRECT标识的AvailabilityChangeEvent事件。

public static <S extends AvailabilityState> void publish(ApplicationContext context, S state) {
	Assert.notNull(context, "Context must not be null");
	publish(context, context, state);
}

public static <S extends AvailabilityState> void publish(ApplicationEventPublisher publisher, Object source,
		S state) {
	Assert.notNull(publisher, "Publisher must not be null");
	publisher.publishEvent(new AvailabilityChangeEvent<>(source, state));
}

发布ApplicationReadyEvent事件和带有ReadinessState.ACCEPTING_TRAFFIC标识的AvailabilityChangeEvent事件。

void running(ConfigurableApplicationContext context) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.running(context);
	}
}

@Override
public void running(ConfigurableApplicationContext context) {
	context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
	AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
2.8 异常处理

发布ApplicationFailedEvent。

private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
	Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) {
	try {
		try {
			handleExitCode(context, exception);
			if (listeners != null) {
				listeners.failed(context, exception);
			}
		}
		finally {
			reportFailure(exceptionReporters, exception);
			if (context != null) {
				context.close();
			}
		}
	}
	catch (Exception ex) {
		logger.warn("Unable to close ApplicationContext", ex);
	}
	ReflectionUtils.rethrowRuntimeException(exception);
}

void failed(ConfigurableApplicationContext context, Throwable exception) {
	for (SpringApplicationRunListener listener : this.listeners) {
		callFailedListener(listener, context, exception);
	}
}

private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
			Throwable exception) {
	try {
		listener.failed(context, exception);
	}
	catch (Throwable ex) {
		if (exception == null) {
			ReflectionUtils.rethrowRuntimeException(ex);
		}
		if (this.log.isDebugEnabled()) {
			this.log.error("Error handling failed", ex);
		}
		else {
			String message = ex.getMessage();
			message = (message != null) ? message : "no error message";
			this.log.warn("Error handling failed (" + message + ")");
		}
	}
}

@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
	ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
	if (context != null && context.isActive()) {
		// Listeners have been registered to the application context so we should
		// use it at this point if we can
		context.publishEvent(event);
	}
	else {
		// An inactive context may not have a multicaster so we use our multicaster to
		// call all of the context's listeners instead
		if (context instanceof AbstractApplicationContext) {
			for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
					.getApplicationListeners()) {
				this.initialMulticaster.addApplicationListener(listener);
			}
		}
		this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
		this.initialMulticaster.multicastEvent(event);
	}
}
3.JarLaunch启动

SpringBoot生成的Jar包有一个MENIFEST.MF文件,里面记录了SpringBoot启动类。
Start-Class:项目真正的应用启动类
Main-Class:java -jar命令执行时JarLauncher会被执行,实际上是Start-Class会被执行。
在这里插入图片描述
JarLauncher继承ExecutableArchiveLauncher ,ExecutableArchiveLauncher 是Launcher的子类。JarLauncher可以加载/BOOT-INF/lib下的jar及/BOOT-INF/classes下的应用class

public class JarLauncher extends ExecutableArchiveLauncher {

    public JarLauncher() {
	}
	static final EntryFilter NESTED_ARCHIVE_ENTRY_FILTER = (entry) -> {
		if (entry.isDirectory()) {
			return entry.getName().equals("BOOT-INF/classes/");
		}
		return entry.getName().startsWith("BOOT-INF/lib/");
	};

    public static void main(String[] args) throws Exception {
		new JarLauncher().launch(args);
	}
}

JarLauncher实例化会调用父类ExecutableArchiveLauncher 的无参构造方法,找到所在的jar,并创建JarFileArchive。

public ExecutableArchiveLauncher() {
	try {
		this.archive = createArchive();
		this.classPathIndex = getClassPathIndex(this.archive);
	}
	catch (Exception ex) {
		throw new IllegalStateException(ex);
	}
}

protected final Archive createArchive() throws Exception {
	ProtectionDomain protectionDomain = getClass().getProtectionDomain();
	CodeSource codeSource = protectionDomain.getCodeSource();
	URI location = (codeSource != null) ? codeSource.getLocation().toURI() : null;
	String path = (location != null) ? location.getSchemeSpecificPart() : null;
	if (path == null) {
		throw new IllegalStateException("Unable to determine code source archive");
	}
	File root = new File(path);
	if (!root.exists()) {
		throw new IllegalStateException("Unable to determine code source archive from " + root);
	}
	return (root.isDirectory() ? new ExplodedArchive(root) : new JarFileArchive(root));
}

创建类加载器,获取真正的启动类,执行启动。

protected void launch(String[] args) throws Exception {
	if (!isExploded()) {
		JarFile.registerUrlProtocolHandler();
	}
	ClassLoader classLoader = createClassLoader(getClassPathArchivesIterator());
	String jarMode = System.getProperty("jarmode");
	String launchClass = (jarMode != null && !jarMode.isEmpty()) ? JAR_MODE_LAUNCHER : getMainClass();
	launch(args, launchClass, classLoader);
}

读取MANIFEST获取Start-Class对应的启动类。

protected String getMainClass() throws Exception {
	Manifest manifest = this.archive.getManifest();
	String mainClass = null;
	if (manifest != null) {
		mainClass = manifest.getMainAttributes().getValue(START_CLASS_ATTRIBUTE);
	}
	if (mainClass == null) {
		throw new IllegalStateException("No 'Start-Class' manifest entry specified in " + this);
	}
	return mainClass;
}

将classLoader设置为上下文类加载器。
创建一个MainMethodRunner对象,隐式加载一个类,通过反射调用目标main方法。

protected void launch(String[] args, String launchClass, ClassLoader classLoader) throws Exception {
	Thread.currentThread().setContextClassLoader(classLoader);
	createMainMethodRunner(launchClass, args, classLoader).run();
}

protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) {
	return new MainMethodRunner(mainClass, args);
}

public class MainMethodRunner {
	public MainMethodRunner(String mainClass, String[] args) {
		this.mainClassName = mainClass;
		this.args = (args != null) ? args.clone() : null;
	}
	
	public void run() throws Exception {
		Class<?> mainClass = Class.forName(this.mainClassName, false, Thread.currentThread().getContextClassLoader());
		Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
		mainMethod.setAccessible(true);
		mainMethod.invoke(null, new Object[] { this.args });
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值