spring boot启动

缘由

java -jar xxx.jar

是Java运行jar程序的标准方式
Java启动程序入口由META-INF\MANIFEST.MF确定,最主要参数是:

Main-Class: org.springframework.boot.loader.JarLauncher

Java启动spring boot的JarLuncher,由spring-boot-loader处理后续加载和配置

spring-boot-loader源码

要查看spring-boot-loader的代码,可以通过在pom中添加依赖

<!-- spring-boot-loader-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-loader</artifactId>
	<scope>provided</scope>
</dependency>

在这里插入图片描述
在这里插入图片描述

JarLauncher入口并负责找到加载的类并启动spring boot application

public class JarLauncher extends ExecutableArchiveLauncher {
    protected ClassPathIndexFile getClassPathIndex(Archive archive) throws IOException {
        if (archive instanceof ExplodedArchive) {
            String location = this.getClassPathIndexFileLocation(archive);
            return ClassPathIndexFile.loadIfPossible(archive.getUrl(), location);
        } else {
            return super.getClassPathIndex(archive);
        }
    }
    public static void main(String[] args) throws Exception {
        (new JarLauncher()).launch(args);
    }
}    

ExecutableArchiveLauncher负责找到spring boot的Start-Class主类及其ClassLoader,Start-Class就是我们自定义的application类,位于MANIFEST.MF文件中。

Start-Class: com.example.XXXApplication
public abstract class ExecutableArchiveLauncher extends Launcher {
    public ExecutableArchiveLauncher() {
        try {
            this.archive = this.createArchive();
            this.classPathIndex = this.getClassPathIndex(this.archive);
        } catch (Exception var2) {
            throw new IllegalStateException(var2);
        }
    }
    protected String getMainClass() throws Exception {}
    protected ClassLoader createClassLoader(Iterator<Archive> archives) throws Exception {}   

Launcher启动应用

	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);
	}
	protected void launch(String[] args, String launchClass, ClassLoader classLoader) throws Exception {
		Thread.currentThread().setContextClassLoader(classLoader);
		createMainMethodRunner(launchClass, args, classLoader).run();
	}

MainMethodRunner具体实例化应用的SpringApplication类,并执行main方法。

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

补充:JarModeLauncher的介绍:“Delegate class used to launch the fat jar in a specific mode”

参考资料 : The Executable Jar Format


spring boot

boot负责启动工作,启动过程代码比较简洁,状态变化通过事件机制传递,各个接收方再次初始化配置。

Java事件接口

  • java.util.EventListener 事件接收/监听
  • java.util.EventObject 事件

spring基础类

  • SpringFactoriesLoader: General purpose factory loading mechanism for internal use within the framework

  • ApplicationEvent: Class to be extended by all application events

  • ApplicationListener: Interface to be implemented by application event listeners

  • ApplicationContextInitializer: Callback interface for initializing a Spring

  • SpringApplicationRunListener: Listener for the SpringApplication.run method.

  • ApplicationEventMulticaster: Interface to be implemented by objects that can manage a number of ApplicationListener objects and publish events to them

  • ApplicationContext :Central interface to provide configuration for an application

  • ConfigurableApplicationContext: SPI interface to be implemented by most if not all application contexts。SPI in spring is spring.factories


spring boot启动

应用启动入口

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

SpringApplicaiton 构造函数变量初始

	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();
		
		// 初始化类ApplicationContextInitializer
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		/*
		0 = {DelegatingApplicationContextInitializer@1689} 
		1 = {SharedMetadataReaderFactoryContextInitializer@1690} 
		2 = {ContextIdApplicationContextInitializer@1691} 
		3 = {ConfigurationWarningsApplicationContextInitializer@1692} 
		4 = {RSocketPortInfoApplicationContextInitializer@1693} 
		5 = {ServerPortInfoApplicationContextInitializer@1694} 
		6 = {ConditionEvaluationReportLoggingListener@1695} 
		*/
		
		// 监听类,当进程进入到某个阶段,再执行一系列操作,比如设置或者初始化
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		/*
		0 = {BootstrapApplicationListener@1768} 
		1 = {LoggingSystemShutdownListener@1769} 
		2 = {CloudFoundryVcapEnvironmentPostProcessor@1770} 
		3 = {ConfigFileApplicationListener@1771} 
		4 = {AnsiOutputApplicationListener@1772} 
		5 = {LoggingApplicationListener@1773} 
		6 = {ClasspathLoggingApplicationListener@1774} 
		7 = {BackgroundPreinitializer@1775} 
		8 = {DelegatingApplicationListener@1776} 
		9 = {RestartListener@1777} 
		10 = {ParentContextCloserApplicationListener@1778} 
		11 = {ClearCachesApplicationListener@1779} 		
		*/
		
		this.mainApplicationClass = deduceMainApplicationClass();
	}

SpringApplicaiton run方法启动应用

	/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		
		// 定义SpringApplicationRunListener,监控和反馈系统的各个阶段和状态
		// 实例为EventPublishingRunListener,在之后发布事件和状态
		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();
			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);
			
			// 比如找到声明CommandLineRunner的的bean,会执行run
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			// 发布应用就绪事件/状态
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

SpringApplicaiton 上下文

Spring的全局的东西可以通过上下文访问,SpringApplication的上下文类型是ConfigurableApplicationContext,默认的两个上下文实现类是

	/**
	 * The class name of application context that will be used by default for non-web
	 * environments.
	 */
	public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
			+ "annotation.AnnotationConfigApplicationContext";

	/**
	 * The class name of application context that will be used by default for web
	 * environments.
	 */
	public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
			+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

查看AbstractApplicationContext可以看到上下文持有的对象

	/** Environment used by this context. */
	@Nullable
	private ConfigurableEnvironment environment;

	/** BeanFactoryPostProcessors to apply on refresh. */
	private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
	/** ResourcePatternResolver used by this context. */
	private ResourcePatternResolver resourcePatternResolver;

	/** LifecycleProcessor for managing the lifecycle of beans within this context. */
	@Nullable
	private LifecycleProcessor lifecycleProcessor;

	/** MessageSource we delegate our implementation of this interface to. */
	@Nullable
	private MessageSource messageSource;

	/** Helper class used in event publishing. */
	@Nullable
	private ApplicationEventMulticaster applicationEventMulticaster;

	/** Statically specified listeners. */
	private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();	
	/** Local listeners registered before refresh. */
	@Nullable
	private Set<ApplicationListener<?>> earlyApplicationListeners;

	/** ApplicationEvents published before the multicaster setup. */
	@Nullable
	private Set<ApplicationEvent> earlyApplicationEvents;	

配置上下文ApplicationContext

	private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		//各类Initializers取得Spring 上下文
		applyInitializers(context);

		// Listeners与上下文关联
		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);
	}
	
	// 各类initializer的初始化
	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);
		}
	}
	

refresh context

这里又做了很多初始和配置工作,比如invokeBeanFactoryPostProcessors

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

spring boot事件

事件类型

spring boot事件

事件发布和接收

最初写代码,没有对象的概念,那是面向过程。Java是面向对象的语言,用对象来描述事物。物与物的连接是通过一些事件联系在一起的,比如天气预报,需要气象局预报递送给每一个人么?这就是事件的作用,气象局发布由声音、影像等发布天气预报,人的每个实例都可以选择接收或者不接收,这就是发布事件和事件接收者。

SpringApplicaiton在构造函数SpringFactoriesLoader根据spring的SPI机制创建Listeners,然后执行run方法;在方法中创建SpringApplicationRunListeners,在方法的执行过程中,由SpringApplicationRunListener实现类EventPublishingRunListener发布spring event,由各类Listeners接收,接收自己负责的事件类型,并进一步处理。

Spring事件发布和接收

ApplicationListener

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	/**
	 * Handle an application event.
	 * @param event the event to respond to
	 */
	void onApplicationEvent(E event);
}

SpringApplicationRunListener

它定义了Spring启动的中间过程,与事件类型呼应。

public interface SpringApplicationRunListener {
	default void starting() {	}
	default void environmentPrepared(ConfigurableEnvironment environment) {	}
	default void contextPrepared(ConfigurableApplicationContext context) {	}
	default void contextLoaded(ConfigurableApplicationContext context) {	}
	default void started(ConfigurableApplicationContext context) {	}
	default void running(ConfigurableApplicationContext context) {	}
	default void failed(ConfigurableApplicationContext context, Throwable exception) {	}
}

应用初始化

SpringApplicaiton在构造时,由SpringFactoriesLoader根据spring的SPI机制创建Initializers,在run方法的prepareContext中配置context,并通知Initializerslisteners执行初始化。

		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);

ApplicationContextInitializer

ApplicationContextInitializer监听事件

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {

	/**
	 * Initialize the given application context.
	 * @param applicationContext the application to configure
	 */
	void initialize(C applicationContext);
}

有些Initializer还同时接收事件通知

public class ConditionEvaluationReportLoggingListener
		implements ApplicationContextInitializer<ConfigurableApplicationContext> {
	
	// ApplicationContextInitializer
	@Override
	public void initialize(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		applicationContext.addApplicationListener(new ConditionEvaluationReportListener());
		if (applicationContext instanceof GenericApplicationContext) {
			// Get the report early in case the context fails to load
			this.report = ConditionEvaluationReport.get(this.applicationContext.getBeanFactory());
		}
	}

	// ApplicationListener
	protected void onApplicationEvent(ApplicationEvent event) {
		ConfigurableApplicationContext initializerApplicationContext = this.applicationContext;
		if (event instanceof ContextRefreshedEvent) {
			if (((ApplicationContextEvent) event).getApplicationContext() == initializerApplicationContext) {
				logAutoConfigurationReport();
			}
		}
		else if (event instanceof ApplicationFailedEvent
				&& ((ApplicationFailedEvent) event).getApplicationContext() == initializerApplicationContext) {
			logAutoConfigurationReport(true);
		}
	}	

到此,应用初始化并启动。但是listener们和initializer们是怎么确定的?
spring.factories

SpringFactoriesLoader

SpringFactoriesLoaderspring.factories中读配置,并把其中的类实例化

public final class SpringFactoriesLoader {

	/**
	 * The location to look for factories.
	 * <p>Can be present in multiple JAR files.
	 */
	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<>();
			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();
					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);
		}
	}


	@SuppressWarnings("unchecked")
	private static <T> T instantiateFactory(String factoryImplementationName, Class<T> factoryType, ClassLoader classLoader) {
		try {
			Class<?> factoryImplementationClass = ClassUtils.forName(factoryImplementationName, classLoader);
			if (!factoryType.isAssignableFrom(factoryImplementationClass)) {
				throw new IllegalArgumentException(
						"Class [" + factoryImplementationName + "] is not assignable to factory type [" + factoryType.getName() + "]");
			}
			return (T) ReflectionUtils.accessibleConstructor(factoryImplementationClass).newInstance();
		}
		catch (Throwable ex) {
			throw new IllegalArgumentException(
				"Unable to instantiate factory class [" + factoryImplementationName + "] for factory type [" + factoryType.getName() + "]",
				ex);
		}
	}	

比如上面SpringApplication的构造函数中备注了一些ApplicationListener,是我实际启动一个cloud应用时加载的类,其中有BootstrapApplicationListener,它位于spring-cloud-context-xxx.RELEASE.jar包中,找到包中META-INF\spring.factories,其中有一项配置# Application Listeners

# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\
org.springframework.cloud.context.restart.RestartListener
# Bootstrap components
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration,\
org.springframework.cloud.bootstrap.encrypt.EncryptionBootstrapConfiguration,\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.cloud.util.random.CachedRandomPropertySourceAutoConfiguration

再次延伸org.springframework.boot.autoconfigure.EnableAutoConfiguration,由org.springframework.boot.autoconfigure负责处理。看一下spring-boot-autoconfigure-xxx.RELEASE.jarspring.factoriesInitializersListeners部分:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

再延伸到org.springframework.cloud.bootstrap.BootstrapConfiguration,位于spring-cloud-context包中,找它的spring.factories:

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.cloud.bootstrap.BootstrapApplicationListener,\
org.springframework.cloud.bootstrap.LoggingSystemShutdownListener,\
org.springframework.cloud.context.restart.RestartListener

BeanFactoryPostProcessor

。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值