1. 启动类的run方法
@SpringBootApplication
public class ZscApplication {
public static void main(String[] args) {
SpringApplication.run(ZscApplication.class, args);
}
}
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实例化,第二个是执行run方法。
1.1. SpringApplication实例化
public SpringApplication(Class<?>... primarySources) {
this((ResourceLoader)null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//传入的sources为null
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
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(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
//getSpringFactoriesInstances ,以spi的形式获取到接口的实例
//ApplicationContextInitializer是由context包提供的,这个包也是一个初始化器,
//在spi的规范条件下,有没有准备接口,在这里,已经准备了ApplicationContextInitializer接口
//有了接口后,就可以根据spi获取对应的接口实现类,可以在spring #refresh刷新之前做一些事情,那么就可以对初始化器进行实现,也就相当于对spring进行了扩展。
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//这个是事件监听器,
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
spi:根据接口获取实现类实例类
java spi : ServiceLoader
dubbo spi : ExtensionLoader
spring spi :springFactotrieLoader
package org.springframework.context;
@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
void initialize(C applicationContext);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return this.getSpringFactoriesInstances(type, new Class[0]);
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
//从spring.factories文件中尽显查找,以ApplicationContextInitializer的全路径为key,找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());
Iterator var7 = names.iterator();
while(var7.hasNext()) {
String name = (String)var7.next();
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
} catch (Throwable var12) {
Throwable ex = var12;
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList(initializers);
}
1.1.1. 自定义初始化器
//将spi的实例方法进行回调
那这个spi的实例方法回调的应用场景是什么呢:
如果我们想要在spring #refresh刷新之前做一些事情,那么就可以对初始化器进行实现,也就相当于对spring进行了扩展。
通过这个我们可以自定义自己的初始化器
1.1.2. 监听器
这是一种典型的观察者设计模式。
如果想查看监听器的更多事件详情,可以到ApplicationEvent类中查看。
事件有非常多的类型,这些事件都是ApplicationEvent的子类,可以自定义一个监听器,监听你感兴趣的事件,那如何缩小这个范围呢,就是这个范围是ApplicationEvent的子类型,继承这个子类就可以。
/**
* 这个监听器对ApplicationStartedEvent感兴趣,
* 也就是如果Spring源码启动的时候,有广播器发布了ApplicationStartedEvent事件,那么就会回调下面的方法
*/
public class Listener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("项目启动-------------");
}
}
org.springframework.context.ApplicationListener=\
com.zsc.zsc.demo.v3.Listener
1.2. Spring中的扩展机制
(1)自定义自己的初始化器:固定
(2)事件监听机制:可以在任意只要发布事件的地方进行监听,扩展更加灵活,贯穿整个spring启动的生命周期。
我们也可以自定义广播器、事件和监听器
(3)Run
(4)自定义BeanFactoryPostcessor用于修改beanfactory的属性值
1.3. SpringAoolication的run方法
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
//获取到一些监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//进行监听器的一个回调
listeners.starting(bootstrapContext, this.mainApplicationClass);
Throwable ex;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//打印banner操作,可以创建一个banner.txt文件,写启动时打印的东西
Banner printedBanner = this.printBanner(environment);
//创建context,根据你引入的jar包创建对应的context
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//回调初始化器
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//刷新
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
listeners.started(context, timeTakenToStartup);
//在最后的最后,可以在这里实现,可以实现资源的释放或清理
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
ex = var12;
this.handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
return context;
} catch (Throwable var11) {
ex = var11;
this.handleRunFailure(context, ex, (SpringApplicationRunListeners)null);
throw new IllegalStateException(ex);
}
}
@Component
public class ZscApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("我是最后执行的... ZscApplicationRunner");
}
}
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//下面这三个是准备系统bean对象
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var10) {
BeansException ex = var10;
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + ex);
}
this.destroyBeans();
this.cancelRefresh(ex);
throw ex;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
在上下文刷新过程中,可以修改bean的原属性:
org.springframework.context.ApplicationListener=\
com.zsc.zsc.demo.v3.Listener