springboot启动流程

 

 

 

jdk仅提供了事件驱动的规范 木有实现

 

 

springboot启动流程中的核心就是事件驱动

下面我们先来说下事件驱动

事件监听机制

熟悉Spring的同学,spring提供了一套完整的事件监听机制。要了解spring不妨先熟悉一下,观察者模式。Java 从1.0版本,已经有了观察者模式的设计。下面通过一个案例来了解一下Java所提供的观察者模式。

 

观察者模式

观察者模式为,一个被观察者Observable(被观察主题)和多个观察者Observer,被观察者中存储了所有的观察者对象,当被观察者接收到一个外界的消息,会通知其所有的观察者。其实就是一个主题改变,订阅它的观察者都会收到相关的消息。(也可以叫做,发布订阅模式)
JDK 观察者模式
JDK 以上是观察者模式的类图。 观察者(Obsever)、被观察者(Observable)。通过源码可以看出被观察者中会维护观察者对象,观察者注册到被观察者列表后,被观察者发出的通知观察者都将收到改变。而观察者中的unpdate(Observable,Object)方法。就是通过监听被观察者发生的改变,来触发观察者的响应。
模拟老师和学生的一个场景:被观察者(老师)、观察者(学生)。

案例1.

观察者

public class MyObserver implements Observer {
    /**
     * 观察者(学生)name
     */
    private String name;
    public MyObserver(Observable o, String name) {
        o.addObserver(this);
        this.name = name;
    }
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("观察者(学生)" + name + "收到作业!《" + arg + "》"+"目标的观察者数量=" + o.countObservers());
    }
}

被观察者

public class MyObserverable extends Observable {
    //被观察者数据
    private String data;
    public String getData() {
        return data;
    }
    /**
     * 如果有如果改变
     * @param data
     */
    public void setData(String data) {
        if (!this.data.equals(data)) {
            this.data = data;
            //更改变化状态
            setChanged();
        }
        //通知注册的观察者
        notifyObservers(data);
    }
}

测试

public static void main(String[] args) {
        //1.构造被观察目标。(假如现实场景中的老师)
        MyObserverable observerable = new MyObserverable();
        //2.构造2个观察者实现类:添加观察者进观察目标  (现实场景中的学生,每来一个新学生,要加入老师的观察者名录中)
        MyObserver observer1 = new MyObserver(observerable, "tom");
        MyObserver observer2 = new MyObserver(observerable, "jerry");
        //3.被观察者(老师)发布今天的作业任务。其注册的观察者们(学生们)响应。
        observerable.setData("Java从入门到放弃");
    }

结果:

被观察者已上线....
观察者(学生)jerry收到作业!《Java从入门到放弃》目标的观察者数量=2
观察者(学生)tom收到作业!《Java从入门到放弃》目标的观察者数量=2

通过代码看到,被观察者的 通知注册的观察者 notifyObservers(data);,触发消息的通知给观察者们。观测者观察到有变化后,做出改变。update(Observable o, Object arg) {}.

 

Spring事件机制(事件监听机制)

通过上面的观察者模式,我们能够了解到,其中的设计模式及思想。监听者模式有异曲同工之处,监听者模式包含了一个监听者Listener与之对应的事件Event,还有一个事件发布者EventPublish,过程就是EventPublish发布一个事件,被监听者捕获到,然后做出相应的处理。事件监听机制,其实从JDK 1.1开始有的设计模式,其主要的几个基类为 事件源EventObject 、监听者EventListener、发布者(Spring)ApplicationEventPublisher
spring事件驱动模型
下面通过案例演示事件发布订阅。

案例2.

事件源:
Spring的事件源为ApplicationEvent,继承至JDK提供的EventObject 基类。

public class MyContextEvent extends ApplicationEvent {
    public MyContextEvent(Object source) {
        super(source);
        System.out.println("source message->"+source.toString());
    }
}

监听者:
Spring的监听者为ApplicationListener,继承至JDK提供的EventListener 接口。其实EventListener中没有任何方法定义,只是作为监听者标识。

public class MyContextListener implements ApplicationListener<MyContextEvent> {
    @Override
    public void onApplicationEvent(MyContextEvent myContextEvent) {
        System.out.println("listener this MyContextEvent....");
    }
}

这里我们通过Spring容器的事件发布功能来实现,自动以事件的注册发布及监听。
在spring容器事件中AbstractApplicationContext继承至ConfigurableApplicationContext,
ConfigurableApplicationContext类继承至ApplicationContext。IOC容器的核心接口ApplicationContext中继承了,事件发布ApplicationEventPublisher. 其子类AbstractApplicationContext中实现了父接口ApplicationEventPublisher中的publishEvent(ApplicationEvent event)方法。

//AbstractApplicationContext类中的publishEvent方法。
public void publishEvent(ApplicationEvent event) {
        this.publishEvent(event, (ResolvableType)null);
    }

测试

public static void main(String[] args) {
        //获取IOC容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注册监听者
        context.register(MyContextListener.class);
        //刷新容器
        context.refresh();
        //事件发布
        context.publishEvent(new MyContextEvent("publish this event ...."));
    }

结果

source message->publish this event ....
listener this MyContextEvent....

在IOC容器中,添自定义事件的监听者context.register(MyContextListener.class);、
事件发布通过发布自定义事件== context.publishEvent(new MyContextEvent(“publish this event …”));==自定义消息。监听者做出响应。

 

 

接下来我们来看 speingboot的启动流程

从run方法进入

@ComponentScan("com.luban")
@SpringBootApplication
public class Start {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Start.class,args);
        //context.addApplicationListener(new LogoutListener());
    }




}

 

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;//此时为null,可以通过此参数指定类加载器
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //primarySources 就是run方法传进来的class
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //推断应用类型,reactive,servlet
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //初始化classpath下 META-INF/spring.factories中配置的ApplicationContextInitializer
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //初始化classpath下所有配置的 ApplicationListener(META-INF/spring.factories)
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //根据调用栈,推断出 main 方法的类名
    this.mainApplicationClass = deduceMainApplicationClass();
}
static WebApplicationType deduceFromClasspath() {
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}


------
private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
-----
	private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";

-----
	private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
-----
	private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

接着看 //初始化classpath下 META-INF/spring.factories中配置的ApplicationContextInitializer

setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}
//通过getClassLoader 从META-INF/spring.factories获取指定的Spring的工厂实例
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    //默认为Thread.currentThread().getContextClassLoader()/ClassLoader.getSystemClassLoader()
    ClassLoader classLoader = getClassLoader();
    //读取 key 为 type.getName() 的 value
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //反射创建Bean
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

可以自定义事件监听器和初始化干预

 

SpringFactoriesLoader.loadFactoryNames(type, classLoader)又是前面说过的很熟悉的spring  spi机制

这里加载的ApplicationContextInitializer在下图所示

2+5一共七个然后拿到spi中的全路径名 调用createSpringFactoriesInstances反射创建bean 注意这里创建完的bean木有放入ioc容器交由spring管理

private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

接着看 

//初始化classpath下所有配置的 ApplicationListener(META-INF/spring.factories)
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

 

其实与上面一行类似  spring的spi机制

 

一共10+1 = 11个ApplicationListener  同样调用createSpringFactoriesInstances反射创建bean 注意这里创建完的bean同样木有放入ioc容器交由spring管理

 

 

接着看

//根据调用栈,推断出 main 方法的类名
    this.mainApplicationClass = deduceMainApplicationClass();
----
private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// Swallow and continue
		}
		return null;
	}


-------

防止出现出现下图这种写法 所以获取 main方法的类

上面的SpringApplication构造方法初始化并设置了ApplicationContextInitializer、ApplicationListener的bean

 

 

 

 

下面来看run方法

运行spring应用,并刷新ApplicationContext(ConfigurableApplicationContext)

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch(); //记录运行时间
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    configureHeadlessProperty();//java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true,系统变量默认为true
    
    //从META-INF/spring.factories中获取监听器  SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting();//遍历回调SpringApplicationRunListeners的starting方法
    try {   
        //封装命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //构造应用上下文环境,完成后回调SpringApplicationRunListeners的environmentPrepared方法
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        configureIgnoreBeanInfo(environment);//处理需要忽略的Bean
        Banner printedBanner = printBanner(environment);//打印banner
        //根据是否web环境创建相应的IOC容器
        context = createApplicationContext();
        //实例化SpringBootExceptionReporter,用来支持报告关于启动的错误
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                          new Class[] { ConfigurableApplicationContext.class}, context);
        
        //准备上下文环境,将environment保持到IOC容器中
        //执行applyInitializers,遍历回调ApplicationContextInitializer的initialize方法
        //遍历回调SpringApplicationRunListeners的contextPrepared方法
        //遍历回调SpringApplicationRunListeners的contextLoaded方法
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        refreshContext(context);//刷新应用上下文,组件扫描、创建、加载
        
        //从IOC容器获取所有的ApplicationRunner(先调用)和CommandLinedRunner进行回调
        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, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        listeners.running(context);
    }catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

总体

1:获取并启动监听器

2:构造容器环境

3:初始化容器,创建容器

4:报告错误信息

5:刷新应用上下文前的准备阶段

6:刷新容器

7:刷新容器后的扩展接口

 

先看

获取并启动监听器

getRunListeners:加载spring.factories中的监听器EventPublishingRunListener

//从META-INF/spring.factories中获取监听器  SpringApplicationRunListeners
    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));
	}

获取的地方也是一样的  获取到EventPublishingRunListener

 

 

public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    for (ApplicationListener<?> listener : application.getListeners()) {
        this.initialMulticaster.addApplicationListener(listener);
    }
}
//SimpleApplicationEventMulticaster extends  AbstractApplicationEventMulticaster
public void addApplicationListener(ApplicationListener<?> listener) {
    synchronized (this.retrievalMutex) {
        //避免重复  放入set,去掉代理对象
        Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
        if (singletonTarget instanceof ApplicationListener) {
            this.defaultRetriever.applicationListeners.remove(singletonTarget);
        }
        //内部类对象,保存所有的监听器
        this.defaultRetriever.applicationListeners.add(listener);
        this.retrieverCache.clear();
    }
}

其中addApplicationListener方法中

例如 监听器上面加了@Configuration注解那么 就会是创建的aop代理对象  而我们反射获取的是原始对象 那么移除反射对象 加进去原始对象

 

SimpleApplicationEventMulticaster父类AbstractApplicationEventMulticaster中。关键代码为this.defaultRetriever.applicationListeners.add(listener);,这是一个内部类,用来保存所有的ApplicationListener监听器。也就是在这一步,将spring.factories中的监听器( 也就是 上面说的 11个ApplicationListener  )传递到SimpleApplicationEventMulticaster中。

 

启动监听器

listeners.starting();

public void starting() {
    //关键代码,这里是创建application启动事件:ApplicationStartingEvent发布启动事件
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

 并木有放入ioc里面

EventPublishingRunListener这个是springBoot框架中最早执行的监听器,在该监听器执行started()方法时,会继续发布事件,也就是事件传递。这种实现主要还是基于spring的事件机制。继续跟进SimpleApplicationEventMulticaster,有个核心方法:

 

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    //找出匹配该事件的监听器
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        //获取线程池,如果为空则同步处理。这里线程池为空,还未初始化。
        Executor executor = getTaskExecutor();
        if (executor != null) {
            //异步发送事件
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            //同步发送事件
            invokeListener(listener, event);
        }
    }
}
protected Collection<ApplicationListener<?>> getApplicationListeners(
    ....构建缓存
    Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType,                                                                      retriever);
    this.retrieverCache.put(cacheKey, retriever);
    return listeners;
    ...
}
    
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
    ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
    List<ApplicationListener<?>> allListeners = new ArrayList<>();
    Set<ApplicationListener<?>> listeners;
    Set<String> listenerBeans;
    synchronized (this.retrievalMutex) {
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }
    //找出适配监听事件的监听器
    for (ApplicationListener<?> listener : listeners) {
        if (supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
                retriever.applicationListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }
    ...



protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}


-----------

	@SuppressWarnings({"rawtypes", "unchecked"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception and just log a debug message.
				Log logger = LogFactory.getLog(getClass());
				if (logger.isTraceEnabled()) {
					logger.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}

这是springBoot启动过程中,第一处根据类型,执行监听器的地方。根据发布的事件类型从所有监听器中选择对应的监听器进行事件发布

supportsEvent方法如下: 

 

其中 判断是不是自己感兴趣的事件

 

构造容器环境

prepareEnvironment

首先是创建并按照相应的应用类型配置相应的环境,然后根据用户的配置,配置系统环境,然后启动监听器,并加载系统配置文件。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                   ApplicationArguments applicationArguments) {
    //创建并配置相应的环境,获取对应的ConfigurableEnvironment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    //根据用户配置,配置 environment系统环境
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach(environment);
    //发布监听事件, ConfigFileApplicationListener 就是加载项目配置文件的监听器。
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                                                    deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}
//根据环境创建对应ConfigurableEnvironment 这个就是前面 SpringApplication this.webApplicationType = WebApplicationType.deduceFromClasspath();推断出来的类型
private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();//Web程序
        case REACTIVE:
            return new StandardReactiveWebEnvironment();//响应式web环境
        default:
            return new StandardEnvironment();//普通程序
    }
}
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    // 将main 函数的args封装成 SimpleCommandLinePropertySource 加入environment中。
    configurePropertySources(environment, args);
    // 激活相应的配置文件
    configureProfiles(environment, args);
}

 

environmentPrepared

配置文件的配置信息加入environment

最终调用:

	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}
---
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    //ConfigFileApplicationListener加载配置到environment
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            invokeListener(listener, event);
        }
    }
}

 

创建容器

createApplicationContext  就是根据前面设置的类型匹配创建

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
        }catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
             "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
        }
    }
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
----
/**
	 * 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";

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

 

报告错误信息

获取SpringBootExceptionReporter

exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,

                   new Class[] { ConfigurableApplicationContext.class }, context);

该类主要是在项目启动失败之后,打印log

private void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters,
                           Throwable failure) {
    try {
        for (SpringBootExceptionReporter reporter : exceptionReporters) {
            if (reporter.reportException(failure)) {
                //上报错误log
                registerLoggedException(failure);
                return;
            }
        }
    }catch (Throwable ex) {
        // Continue with normal handling of the original failure
    }
    if (logger.isErrorEnabled()) {
        logger.error("Application run failed", failure);
        registerLoggedException(failure);
    }
}

 

刷新容器前的准备阶段

prepareContext:将启动类注入容器,为后续开启自动化配置奠定基础。

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
                            SpringApplicationRunListeners listeners, ApplicationArguments                                                   applicationArguments, Banner printedBanner) {
    //设置容器环境
    context.setEnvironment(environment);
    postProcessApplicationContext(context);//执行容器后置处理
    //执行容器中的 ApplicationContextInitializer 包括spring.factories和通过三种方式自定义的
    applyInitializers(context);
    //向各个监听器发送容器已经准备好的事件
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    //将main函数中的args参数封装成单例Bean,注册进容器
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
         //将 printedBanner 封装成单例,注册进容器
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof DefaultListableBeanFactory) {
        ((DefaultListableBeanFactory) beanFactory)
        .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    if (this.lazyInitialization) {
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }
    
    Set<Object> sources = getAllSources();//拿到启动类
    Assert.notEmpty(sources, "Sources must not be empty");
    //加载启动类,将启动类注入容器
    load(context, sources.toArray(new Object[0]));
    //发布容器已加载事件
    listeners.contextLoaded(context);
}

配置bean 生成器及资源加载器

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    //如果设置了是实例命名生成器,注册到Spring容器中
    if (this.beanNameGenerator != null) {
        context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
            this.beanNameGenerator);
    }
    // 如果设置了资源加载器,设置到Spring容器中
    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());
    }
}

 

这里默认不执行任何逻辑,因为beanNameGeneratorresourceLoader默认为空。springBoot预留的扩展处理方式,配置上下文的 bean 生成器及资源加载器

 

 

加载启动类

load

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    //创建 BeanDefinitionLoader    将上下文context强转为BeanDefinitionRegistry
    BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    loader.load();
}
//createBeanDefinitionLoader进入构造器
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    Assert.notNull(registry, "Registry must not be null");
    Assert.notEmpty(sources, "Sources must not be empty");
    this.sources = sources;
    //注解形式的Bean定义读取器 比如:@Configuration @Bean @Component @Controller @Service等等
    this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
    this.xmlReader = new XmlBeanDefinitionReader(registry);//XML形式的Bean定义读取器
    if (isGroovyPresent()) {
        this.groovyReader = new GroovyBeanDefinitionReader(registry);
    }
    this.scanner = new ClassPathBeanDefinitionScanner(registry); //类路径扫描器
    this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));//扫描器添加排除过滤器
}
private int load(Object source) {
    Assert.notNull(source, "Source must not be null");
    //如果是class类型,启用注解类型
    if (source instanceof Class<?>) {
        return load((Class<?>) source);
    }
    //如果是resource类型,启用xml解析
    if (source instanceof Resource) {
        return load((Resource) source);
    }
    //如果是package类型,启用扫描包,例如:@ComponentScan
    if (source instanceof Package) {
        return load((Package) source);
    }
    //如果是字符串类型,直接加载
    if (source instanceof CharSequence) {
        return load((CharSequence) source);
    }
    throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

发布容器已加载事件

public void contextLoaded(ConfigurableApplicationContext context) {
    for (ApplicationListener<?> listener : this.application.getListeners()) {
        if (listener instanceof ApplicationContextAware) {
            ((ApplicationContextAware) listener).setApplicationContext(context);
        }
        context.addApplicationListener(listener);
    }
    this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}

上面会将spring.factories中的DelegatingApplicationListener放入容器上下文,从而该实例可以监听容器上下文发布的事件,也可以监听springboot中的事件(委派对象)

 

刷新容器

refresh()

调用spring里面的refresh()

synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    /**
    * 刷新上下文环境
    * 初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验
    * 如环境变量中必须设置某个值才能运行,否则不能运行,这个时候可以在这里加这个校验,
    * 重写initPropertySources方法就好了
    */
    prepareRefresh();
    // Tell the subclass to refresh the internal bean factory.
    /**
    * 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,
    */
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    // Prepare the bean factory for use in this context.
    /**
    * 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
    * 设置SPEL表达式#{key}的解析器
    * 设置资源编辑注册器,如PerpertyEditorSupper的支持
    * 添加ApplicationContextAwareProcessor处理器
    * 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
    * 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
    */
    prepareBeanFactory(beanFactory);
    try {
        // Allows post-processing of the bean factory in context subclasses.
        /**
     * 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
     */
        postProcessBeanFactory(beanFactory);
        // Invoke factory processors registered as beans in the context.
        /**
     * 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
     * 执行对应的postProcessBeanDefinitionRegistry方法 和  postProcessBeanFactory方法
     */
        invokeBeanFactoryPostProcessors(beanFactory);
        // Register bean processors that intercept bean creation.
        /**
     * 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
     * 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
     */
        registerBeanPostProcessors(beanFactory);
        // Initialize message source for this context.
        /**
     * 初始化上下文中的资源文件,如国际化文件的处理等
     */
        initMessageSource();
        // Initialize event multicaster for this context.
        /**
     * 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
     */
        initApplicationEventMulticaster();
        // Initialize other special beans in specific context subclasses.
        /**
     * 给子类扩展初始化其他Bean
     */
        onRefresh();
        // Check for listener beans and register them.
        /**
     * 在所有bean中查找listener bean,然后注册到广播器中
     */
        registerListeners();
        // Instantiate all remaining (non-lazy-init) singletons.
        /**
     * 设置转换器
     * 注册一个默认的属性值解析器
     * 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
     * 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
     */
        finishBeanFactoryInitialization(beanFactory);
        // Last step: publish corresponding event.
        /**
     * 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,
     * spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行,如一直轮询kafka
     * 启动所有实现了Lifecycle接口的类
     * 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理,即对那种在spring启动后需要处理的一些类,这些类实现了
     * ApplicationListener<ContextRefreshedEvent> ,这里就是要触发这些类的执行(执行onApplicationEvent方法)另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
     * 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
     */
        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();
    }
}

 

其中 onRefresh 我们平时会调用ServletWebServerApplicationContext 




@Override
	protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start web server", ex);
		}
	}

 

刷新容器后的扩展接口

 

protected void afterRefresh(ConfigurableApplicationContext context,
                            ApplicationArguments args) {
}

 

 

扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理。

 

事件驱动的图

事件驱动.png

 

 

启动流程

启动流程.png

 

 

 

 

 

 

 

 

 

 

 

配置监听器的几种方式:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值