java -jar xxx.jar
是Java运行jar程序的标准方式
Java启动程序入口由meta-INFMANIFEST.MF确定,最主要参数是:
Main-Class: org.springframework.boot.loader.JarLauncher
Java启动spring boot的JarLuncher,由spring-boot-loader处理后续加载和配置
spring-boot-loader源码要查看spring-boot-loader的代码,可以通过在pom中添加依赖
org.springframework.boot spring-boot-loader provided
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 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 事件
-
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));
// 监听类,当进程进入到某个阶段,再执行一系列操作,比如设置或者初始化
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
SpringApplicaiton run方法启动应用
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,默认的两个上下文实现类是
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";
查看AbstractApplicationContext可以看到上下文持有的对象
@Nullable private ConfigurableEnvironment environment; private final List配置上下文ApplicationContextbeanFactoryPostProcessors = new ArrayList<>(); private ResourcePatternResolver resourcePatternResolver; @Nullable private LifecycleProcessor lifecycleProcessor; @Nullable private MessageSource messageSource; @Nullable private ApplicationEventMulticaster applicationEventMulticaster; private final Set > applicationListeners = new linkedHashSet<>(); @Nullable private Set > earlyApplicationListeners; @Nullable private Set earlyApplicationEvents;
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
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 ApplicationListenerSpringApplicationRunListenerextends EventListener { void onApplicationEvent(E event); }
它定义了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{ void initialize(C applicationContext); }
有些Initializer还同时接收事件通知
public class ConditionevaluationReportLoggingListener implements ApplicationContextInitializer{ // 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); } }
SpringFactoriesLoader到此,应用初始化并启动。但是listener们和initializer们是怎么确定的?
spring.factories。
SpringFactoriesLoader从spring.factories中读配置,并把其中的类实例化
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "meta-INF/spring.factories";
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration 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 instantiateFactory(String factoryImplementationName, Class 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-INFspring.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
。。。



