缘由
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 isspring.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事件
事件类型
事件发布和接收
最初写代码,没有对象的概念,那是面向过程。Java是面向对象的语言,用对象来描述事物。物与物的连接是通过一些事件联系在一起的,比如天气预报,需要气象局预报递送给每一个人么?这就是事件的作用,气象局发布由声音、影像等发布天气预报,人的每个实例都可以选择接收或者不接收,这就是发布事件和事件接收者。
SpringApplicaiton
在构造函数SpringFactoriesLoader
根据spring的SPI机制创建Listeners
,然后执行run
方法;在方法中创建SpringApplicationRunListeners
,在方法的执行过程中,由SpringApplicationRunListener
实现类EventPublishingRunListener
发布spring event,由各类Listeners
接收,接收自己负责的事件类型,并进一步处理。
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,并通知Initializers
和listeners
执行初始化。
context.setEnvironment(environment);
postProcessApplicationContext(context);
applyInitializers(context);
listeners.contextPrepared(context);
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
SpringFactoriesLoader
从spring.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.jar
的spring.factories
中Initializers
和Listeners
部分:
# 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
。。。