SpringBoot2学习笔记06

目录

八十一、高级特性-Profile环境切换

八十二、高级特性-配置加载优先级

八十三、高级特性-自定义starter细节

八十四、原理解析-SpringApplication创建初始化流程

八十五、原理解析-SpringBoot完整启动过程

八十六、原理解析-自定义事件监听组件


八十一、高级特性-Profile环境切换

 1、Profile功能

为了方便多环节适配,springboot简化了profile功能

2、命令行激活

java -jar xxx.jar --spring.profiles.active=prod

 3、配置文件分组

# 应用名称
spring.application.name=boot-09-features-profile
# 指定激活的环境。默认配置文件和指定环境的配置文件都会生效。
spring.profiles.active=myprod
# 分组
spring.profiles.group.myprod[0]=ppd
spring.profiles.group.myprod[1]=prod

spring.profiles.group.mytest[0]=test

八十二、高级特性-配置加载优先级

八十三、高级特性-自定义starter细节

1、starter启动原理

 2、自定义starter

八十四、原理解析-SpringApplication创建初始化流程

1、SpringBoot原理,首先SpringBoot不是一个单纯的框架,它底层整合了非常多的技术,比如Spring、SpringMVC以及Spring整个系列技术栈的其它技术,甚至于第三方框架

2、需要理解Spring原理【Spring注解】,SpringMVC原理、自动配置原理、SpringBoot原理

3、前面给大家分析SpringBoot的自动配置原理,那我们接下来就来看我们整个SpringBoot应用是怎么启动起来的,它启动过程中又干了哪些活,接下来就研究一下启动原理

4、debug断点打在这里,这块启动原理,大家要额外注意一些,因为我们SpringBoot在启动整个应用的过程中,我们有非常多的时机,这些时机呢?我们有可能需要自定义干一些活,我们需要一些回调机制来完成这个事情,所以SpringBoot对底层这个能力也做了支持,所以我们在调试SpringBoot这个启动过程的时候,注意以下的这些东西,比如说有一个东西Listener(监听器)、Initializer(初始化器),它们都会在合适的时机进行回调,现在就来看一下整个启动过程。

5、我们来看一下SpringBoot应用是怎么启动的,我们已传入我们的主配置类就开始运行Spring的应用,怎么运行呢?我们step into进来,进来以后呢。它首先new Class把我们的主程序类传来,调用run方法,我们直接进入它的run方法,这个run方法呢?首先第一步会创建Spring应用,第二部把Spring的应用跑起来

 6、首先我们来分析创建SpringApplication干了什么?我们来Step into,它给我们传入的呢是主配置类,我们来step into进来,然后它调用this有参构造器,传了两个参数。我们再step into进来

 7、这个this里面呢,我们会看到初始化了很多东西,我们来往下走,这里来到SpringApplication里面的好多属性,我们要创建对象呢?这些属性先得初始化过来,我们先不管这些属性,我们再次来到下面这个类里面。首先呢,它先保存了第一个属性,this.resourceLoader(资源加载器),然后Assert.notNull('','')断言,如果没有主配置类会给你抛一个失败,然后把主配置类的信息先保存起来,在当前的SpringApplication这个类里面保存了当前主配置类是什么?(

Boot09HelloTestApplication

),当然这个主配置类里面,最核心的通过

@SpringBootApplication这个注解开启了整个自动配置功能,当然这一块我们就不用分析了。我们主配置类先记录了以后,接下来它再来在这保存了一些属性,所以呢?我们这个创建对象最核心的就是保存一些信息,这些信息包括些什么呢?

 8、我们来看一些关键的,这个信息其中里面还有一个叫webApplicationType,它来决定当前的这个应用的web应用的类型,它调用了WebApplicationType.deduceFromClasspath(),它来判断我们web应用的类型,Step into进来,看是怎么判断的。用类工具类ClassUtils,我们看源码底层的时候,会看到非常多有用的工具类,ClassUtils会先来判断当前这个系统里面有没有导入reactive,相当于响应式编程的整个请求处理器,但是呢,我们现在不是响应式编程,如果是响应式编程,我们整个应用就会返回它是一个响应式编程。而我们现在是原生的servlet编程,所以呢,接下来就会返回

WebApplicationType.SERVLET,当前web应用的类型是servlet

 9、this.bootstrappers这相当于一些初始启动器,什么叫做初始启动器呢?项目一启动我们就要干什么的,而这些初始启动器呢?它是这么来做的 getSpringFactoriesInstances 它是调用这个方法把我们这个类型传过去,在this.bootstrappers这里记录一下,它还是list,list里面都是Bootstrapper,它想要获取所有的初始化启动器,初始启动器是什么?我们看它是怎么获取的,step into进来

private List<Bootstrapper> bootstrappers;

10、它调用getSpringFactoriesInstances这个方法获取的,我们再来点进来,它相当于想要获取这个Bootstrapper,我们再step into进来。

它先拿到类加载器,然后呢使用一个SpringFactoriesLoader,这个东西呢,我们以前在讲自动配置原理的时候讲过,这个东西呢?SpringFactoriesLoader就是从spring.factories那个文件里面来读取这些类,所以我们来看一下,它是要读取哪些类呢?它是要读取Bootstrapper,但是呢,names等于0,它相当于会去来找所有的spring.factories这个文件里面看你有没有在这配置称为Bootstrapper类型。所以,我们如果想要项目一启动以后有一些启动类,所以我们在这一块找寻办法就是去spring.factories文件中找这个org.springframework.boot.Bootstrapper类型的,没有我们就不管,说明呢,我们当前类里面所有的jar包里面都没人配置这个东西,那如果有配置的话,会把这些东西创建一个实例,把这些实例给我们返回,而现在没有任何实例,说明我们的项目初始化启动没有任何初始化的引导器

 11、这个东西我们先不管,现在又有一个核心叫setInitializers(翻译过来叫初始化器),它还是这个方法getSpringFactoriesInstances,如果大家以后呢,都遇到这个方法,都是去spring.factories这个文件里面去来找,看你有没有相关配置这个类,它的值是什么。你如果在系统里面配了一个叫ApplicationContextInitializer它就能给我们找到,如果找到了以后呢,会set保存起来,保存为initializers这个属性,它不仅找到了,还找到了7个

①、spring.factories找到ApplicationContextInitializer

 ②、源码

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();
		this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

12、叫setListeners, 它又找一些监听器叫ApplicationListener(应用监听器->一般就是来监听当前应用状态的),去spring.factories找 ApplicationListener,找到以后最终保存到下面的代码里面

①、

private List<ApplicationListener<?>> listeners;

②、SpringBoot应用启动保存的初始化器和监听器

 13、this.mainApplicationClass = deduceMainApplicationClass();决定哪个是我们的主程序,它是通过找到堆栈,哪个是有main方法的,有main方法的就是主程序。这个就是我们SpringApplication应用创建做了那么一堆。简单来说,应用创建的过程,就是把一些关键的组件给我们去读取信息读取来,先提前保存到SpringApplication里面,保存到这里未来肯定是有用。接下来,看看SpringApplication创建完以后,run的时候干了哪些活。

八十五、原理解析-SpringBoot完整启动过程

1、接着前面,我们step into进入这个run方法。大家注意这个run方法其实还传了一个args,这个args说的就是我们,以前呢,这个jar包一启动,我们可能通过命令行传一些参数,不就是这些args吗?所以大家就可想而知,在这步args能传进来,那未来我们对命令行参数的解析可能也会得到。

 2、我们step into进来,整个run的流程就这么多。首先第一个,它准备一个StopWatch(停止的监听器),这相当于new了一个对象StopWatch,相当于我们来监控整个应用的启停的,StopWacth呢上来调用了一个方法start()

/**
	 * 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();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			prepareContext(bootstrapContext, 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, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

3、start()方法step into进来,发现这个方法啊,非常的简单,给StopWatch里面保存一些信息(像当前我们任务的名字,以及我们当前的时间(纳秒时间)),把这些信息呢给我们保存起来,像它们在这里给我们记录了一下,我们是哪一时刻启动的,应用的启动时间记录了以后呢

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

    public void start(String taskName) throws IllegalStateException {
        if (this.currentTaskName != null) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        } else {
            this.currentTaskName = taskName;
            this.startTimeNanos = System.nanoTime();
        }
    }

4、createBootstrapContext相当于创建引导上下文,所谓的上下文就是我们以后见到什么的Context都是我们当前引导环境上下文,我们整个应用的引导启动环境它里面有哪些就是在这里创建的,我们来看看,创建引导上下文,它里面又做了什么?进来以后,我们会发现它在这里创建了一个默认引导上下文,这个对象默认以后就会给里面保存很多的信息,这个信息呢,就会在这个上下文环境(DefaultBootstrapContext )里面保存,这里有一个关键叫this.bootstrappers,然后呢,这个bootstrappers调一个forEach(),这个bootstrappers是什么呢?是下面的属性(private List<Bootstrapper> bootstrappers;),所以我们之前呢,会在配置文件中,如果你配了Bootstrapper

private List<Bootstrapper> bootstrappers;

private DefaultBootstrapContext createBootstrapContext() {
		DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
		this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext));
		return bootstrapContext;
	}

5、Bootstrapper点击来,Bootstrapper是这个接口。如果人家一开始找到了你这个Bootstrapper,相当于我们的整个引导启动器找到了以后呢,接下来它就会调用这个我们的这个方法createBootstrapContext,你如果自定义了引导启动器,它会把所有的引导启动器forEach遍历一遍,然后呢?每一个引导启动器都会调用它的intitialize方法,因为我们看到引导启动器的接口有一个方法叫intitialize,它传入我们这个引导的注册工厂,然后呢,这个工厂里面我们就可以给它加入一些当前上下文的引导环境信息,所以我们这一块的核心就是 获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置  我们现在这个引导启动器一个都没有,如果你想写了,你可以在spring.factories里面写一个

public interface Bootstrapper {

	/**
	 * Initialize the given {@link BootstrapRegistry} with any required registrations.
	 * @param registry the registry to initialize
	 */
	void intitialize(BootstrapRegistry registry);

}

6、让当前应用进入headless模式。java.awt.headless

configureHeadlessProperty();

private void configureHeadlessProperty() {
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
				System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

7、这里的 getRunListeners,会在

SpringApplicationRunListeners listeners这里保存一下

①、获取所有 RunListener(运行监听器)【为了方便所有Listener进行事件感知】

②、getSpringFactoriesInstances 去spring.factoriesSpringApplicationRunListener.

SpringApplicationRunListeners listeners = getRunListeners(args);

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

③、找到了SpringApplicationRunListener并且保存到了SpringApplicationRunListeners

 8、遍历 SpringApplicationRunListener 调用 starting 方法;

①、​​​​​​​相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。

listeners.starting(bootstrapContext, this.mainApplicationClass);

void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
		doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
				(step) -> {
					if (mainApplicationClass != null) {
						step.tag("mainApplicationClass", mainApplicationClass.getName());
					}
				});
	}

private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
			Consumer<StartupStep> stepAction) {
		StartupStep step = this.applicationStartup.start(stepName);
		this.listeners.forEach(listenerAction);
		if (stepAction != null) {
			stepAction.accept(step);
		}
		step.end();
	}

9、保存命令行参数;ApplicationArguments

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

10、准备环境 prepareEnvironment();

①、返回或者创建基础环境信息对象。StandardServletEnvironment

②、​​​​​​​配置环境信息对象。(​​​​​​​读取所有的配置源的配置属性值。)

③、绑定环境信息

④、监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成

ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
		listeners.environmentPrepared(bootstrapContext, environment);
		DefaultPropertiesPropertySource.moveToEnd(environment);
		configureAdditionalProfiles(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
		if (this.addConversionService) {
			ConversionService conversionService = ApplicationConversionService.getSharedInstance();
			environment.setConversionService((ConfigurableConversionService) conversionService);
		}
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		DefaultPropertiesPropertySource.ifNotEmpty(this.defaultProperties, sources::addLast);
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(
						new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
		doWithListeners("spring.boot.application.environment-prepared",
				(listener) -> listener.environmentPrepared(bootstrapContext, environment));
	}

11、创建IOC容器(createApplicationContext())

ConfigurableApplicationContext context = null;

context = createApplicationContext();

protected ConfigurableApplicationContext createApplicationContext() {
		return this.applicationContextFactory.create(this.webApplicationType);
	}

12、根据项目类型(Servlet)创建容器,

 当前会创建 AnnotationConfigServletWebServerApplicationContext

/**
	 * A default {@link ApplicationContextFactory} implementation that will create an
	 * appropriate context for the {@link WebApplicationType}.
	 */
	ApplicationContextFactory DEFAULT = (webApplicationType) -> {
		try {
			switch (webApplicationType) {
			case SERVLET:
				return new AnnotationConfigServletWebServerApplicationContext();
			case REACTIVE:
				return new AnnotationConfigReactiveWebServerApplicationContext();
			default:
				return new AnnotationConfigApplicationContext();
			}
		}
		catch (Exception ex) {
			throw new IllegalStateException("Unable create a default ApplicationContext instance, "
					+ "you may need a custom ApplicationContextFactory", ex);
		}
	};

13、​​​​​​​​​​​​​​准备ApplicationContext IOC容器的基本信息   prepareContext()

①、保存环境信息

context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		context.setEnvironment(environment);
		postProcessApplicationContext(context);
		applyInitializers(context);
		listeners.contextPrepared(context);
		bootstrapContext.close(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);
	}

②、IOC容器的后置处理流程。

/**
	 * Apply any relevant post processing the {@link ApplicationContext}. Subclasses can
	 * apply additional processing as required.
	 * @param context the application context
	 */
	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
		if (this.beanNameGenerator != null) {
			context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			if (context instanceof GenericApplicationContext) {
				((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
			}
			if (context instanceof DefaultResourceLoader) {
				((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
			}
		}
		if (this.addConversionService) {
			context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
		}
	}

14、应用初始化器;applyInitializers;

①、遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能

/**
	 * Apply any {@link ApplicationContextInitializer}s to the context before it is
	 * refreshed.
	 * @param context the configured ApplicationContext (not refreshed yet)
	 * @see ConfigurableApplicationContext#refresh()
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	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);
		}
	}

15、遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器contextPrepared

listeners.contextPrepared(context);

void contextPrepared(ConfigurableApplicationContext context) {
		doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
	}

16、所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded

listeners.contextLoaded(context);

void contextLoaded(ConfigurableApplicationContext context) {
		doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
	}

private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
		doWithListeners(stepName, listenerAction, null);
	}

	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
			Consumer<StartupStep> stepAction) {
		StartupStep step = this.applicationStartup.start(stepName);
		this.listeners.forEach(listenerAction);
		if (stepAction != null) {
			stepAction.accept(step);
		}
		step.end();
	}

17、​​​​​​​刷新IOC容器。refreshContext

①、创建容器中的所有组件(Spring注解)

refreshContext(context);

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

/**
	 * Refresh the underlying {@link ApplicationContext}.
	 * @param applicationContext the application context to refresh
	 * @deprecated since 2.3.0 in favor of
	 * {@link #refresh(ConfigurableApplicationContext)}
	 */
	@Deprecated
	protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
		refresh((ConfigurableApplicationContext) applicationContext);
	}

/**
	 * Refresh the underlying {@link ApplicationContext}.
	 * @param applicationContext the application context to refresh
	 */
	protected void refresh(ConfigurableApplicationContext applicationContext) {
		applicationContext.refresh();
	}

@Override
	public final void refresh() throws BeansException, IllegalStateException {
		try {
			super.refresh();
		}
		catch (RuntimeException ex) {
			WebServer webServer = this.webServer;
			if (webServer != null) {
				webServer.stop();
			}
			throw ex;
		}
	}

②、最重要的代码,ioc容器单例实例化

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

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

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

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

				// 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();
				contextRefresh.end();
			}
		}
	}

18、容器刷新完成后工作?afterRefresh


/**
	 * Called after the context has been refreshed.
	 * @param context the application context
	 * @param args the application arguments
	 */
	protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	}

19、所有监听 器 调用 listeners.started(context); 通知所有的监听器 started

listeners.started(context);

20、​​​​​​​调用所有runners;callRunners()

①、​​​​​​​获取容器中的 ApplicationRunner

②、​​​​​​​获取容器中的 CommandLineRunner

③、​​​​​​​合并所有runner并且按照@Order进行排序

④、​​​​​​​遍历所有的runner。调用 run 方法

callRunners(context, applicationArguments);

private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args);
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
		}
	}

	private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args.getSourceArgs());
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
		}

@FunctionalInterface
public interface ApplicationRunner {

	/**
	 * Callback used to run the bean.
	 * @param args incoming application arguments
	 * @throws Exception on error
	 */
	void run(ApplicationArguments args) throws Exception;

}

21、​​​​​​​如果以上有异常,​​​​​​​调用Listener 的 failed

catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}

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

22、调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running

​​​​​​​running如果有问题。继续通知 failed 。调用所有 Listener 的 failed;通知所有的监听器 failed

try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}

23、总结

①、

 ②、

 ③、

八十六、原理解析-自定义事件监听组件

猜你喜欢

转载自blog.csdn.net/xizheng2018/article/details/129680533