SpringBoot启动过程(面试用,较简洁)

全过程(下文中未标黑分级比较乱,不用管)

  1. SpringApplication类初始化
  2. 执行SpringApplication类的run方法
  • 2.1获取并启动监听器
  • 2.2构造应用上下文环境
  • 2.3初始化应用上下文
  • 2.4刷新应用上下文前的准备阶段,prepareContext()方法。
  • 2.5刷新应用上下文
  • 2.6自动装配
  • 2.7创建bean

1.SpringApplication类初始化过程

创建SpringApplication类后执行其中的run()方法

2.run()方法的执行

2.1获取并启动监听器

监听器是基于反射实现的,可以用于获取系统资源

2.2构造应用上下文环境

应用上下文环境包括计算机的环境,Java环境,Spring的运行环境,Spring项目的配置(在SpringBoot中就是application.properties/yml)等等。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {}

会根据不同的应用类型初始化不同的系统环境实例

2.3初始化应用上下文

在SpringBoot工程中,应用类型分为三种,SpringBoot项目有三种对应的应用上下文

public enum WebApplicationType { NONE, //应用程序不是web应用,也不应该用web服务器去启动 SERVLET, // 应用程序应作为基于servlet的web应用程序运行,并应启动嵌入式servlet web(tomcat)服务器。 //contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"); //web工程 REACTIVE // 应用程序应作为 reactive web应用程序运行,并应启动嵌入式 reactive web服务器。 //contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"); }

应用上下文可以理解成IoC容器的高级表现形式,应用上下文确实是在IoC容器的基础上丰富了一些高级功能。应用上下文对IoC容器是持有的关系。他的一个属性beanFactory就是IoC容器(DefaultListableBeanFactory)。所以他们之间是持有,和扩展的关系。

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory;//代码节选,可以看出上下文持有bean工厂 public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); } }

2.4刷新应用上下文前的准备阶段,prepareContext()方法。

2.4.1prepareContext()方法

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

2.4.1.1跟进this.load(context, sources.toArray(new Object[0]))

protected void load(ApplicationContext context, Object[] sources) { BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources); //创建 BeanDefinitionLoader loader.load(); }

2.4.1.1.1跟进this.getBeanDefinitionRegistry(context), sources)

private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) { if (context instanceof BeanDefinitionRegistry) { return (BeanDefinitionRegistry)context;//将前文创建的上下文强转为BeanDefinitionRegistry } else if (context instanceof AbstractApplicationContext) { return (BeanDefinitionRegistry)((AbstractApplicationContext)context).getBeanFactory();}

2.4.1.1.2createBeanDefinitionLoader()

根据上面得到的BeanDefinitionRegistry,执行createBeanDefinitionLoader()

2.4.1.1.2.1跟进上面的方法,返回了BeanDefinitionLoader

该方法将不同形式声明的bean都放到了加载器对象中

BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) { this.sources = sources; this.annotatedReader = new AnnotatedBeanDefinitionReader(registry); //注解形式的Bean定义读取器 //比如:@Configuration @Bean @Component @Controller @Service等等 this.xmlReader = new XmlBeanDefinitionReader(registry);//XML形式的Bean定义读取器 if (this.isGroovyPresent()) { this.groovyReader = new GroovyBeanDefinitionReader(registry);} this.scanner = new ClassPathBeanDefinitionScanner(registry);//类路径扫描器 this.scanner.addExcludeFilter(new BeanDefinitionLoader.ClassExcludeFilter(sources));//扫描器添加排除过滤器}

2.4.1.1.3执行获取到的BeanDefinitionLoader的load()方法

private int load(Object source) { if (source instanceof Class) { return this.load((Class)source);} // 从Class加载 else if (source instanceof Resource) { return this.load((Resource)source);}// 从Resource加载 else if (source instanceof Package) { return this.load((Package)source);} // 从Package加载 else if (source instanceof CharSequence) {return this.load((CharSequence)source); } // 从 CharSequence 加载 ???}

2.4.1.1.3跟进上文中load方法内的load()

private int load(Class<?> source) { if (this.isEligible(source)) { //isComponent(source)判断主类是不是存在@Component注解 this.annotatedReader.register(new Class[]{source}); //将 启动类的 BeanDefinition注册进 beanDefinitionMap return 1;} else {return 0;}}

2.4.1.1.3 跟进上面方法内的register(),进入doRegisterBean()

private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) { AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); //将指定的类 封装为AnnotatedGenericBeanDefinition BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); // 将该BeanDefinition注册到IoC容器的beanDefinitionMap中}}

2.4.1.1.3.1跟进registerBeanDefinition()方法

该方法会将主类封装成AnnotatedGenericBeanDefinition。

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); // Register bean definition under primary name. primary name 其实就是id吧 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); // 然后就是注册别名}

2.4.1.1.3.1.跟进registerBeanDefinition中的registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())接口,进入DefaultListableBeanFactory类的registerBeanDefinition()方法,该类就是IoC的具体产品。该类中会检查beanDefinition是否存在,不存在就将之存入beanDefinitionMap中。

2.5刷新应用上下文

执行完prepareContext()后,上下文刷新准备完成,开始执行refreshContext(context)进行应用上下文刷新

2.5.1AbstractApplicationContext类的refresh()方法

从refreshContext(context)的refresh()方法向下找到该方法

public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); //刷新上下文环境 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); //这里是在子类中启动 refreshBeanFactory() 的地方 this.prepareBeanFactory(beanFactory); //准备bean工厂,以便在此上下文中使用 try {this.postProcessBeanFactory(beanFactory); //设置 beanFactory 的后置处理 this.invokeBeanFactoryPostProcessors(beanFactory); //调用 BeanFactory 的后处理器,这些处理器是在Bean 定义中向容器注册的 this.registerBeanPostProcessors(beanFactory); //注册Bean的后处理器,在Bean创建过程中调用 this.initMessageSource(); //对上下文中的消息源进行初始化 this.initApplicationEventMulticaster(); //初始化上下文中的事件机制 this.onRefresh(); //初始化其他特殊的Bean this.registerListeners(); //检查监听Bean并且将这些监听Bean向容器注册 this.finishBeanFactoryInitialization(beanFactory); //实例化所有的(non-lazy-init)单件 this.finishRefresh(); //发布容器事件,结束Refresh过程} }}

2.5.1.1obtainFreshBeanFactory()

在初始化应用上下文的过程中,创建了

应用的上下文,并触发了GenericApplicationContext类的构造方法如下所示,创建了beanFactory,也就是创建了DefaultListableBeanFactory类。该方法就是拿到之前创建的beanFactory。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { this.refreshBeanFactory(); //刷新BeanFactory return this.getBeanFactory(); //获取beanFactory}

2.5.1.2 prepareBeanFactory(beanFactory)

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { beanFactory.setBeanClassLoader(this.getClassLoader()); // 配置类加载器:默认使用当前上下文的类加载器 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 配置EL表达式:在Bean初始化完成,填充属性的时候会用到 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment())); // 添加属性编辑器 PropertyEditor beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 添加Bean的后置处理器 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); // 忽略装配指定的(...)类 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); // 将以下类注册到 beanFactory(DefaultListableBeanFactory) 的resolvableDependencies属性中 //ResourceLoader.class\ApplicationEventPublisher.class\ApplicationContext.class beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 将早期后处理器注册为application监听器,用于检测内部bean //如果当前BeanFactory包含loadTimeWeaver Bean,说明存在类加载期织入AspectJ, // 则把当前BeanFactory交给类加载期BeanPostProcessor实现类LoadTimeWeaverAwareProcessor来处理, // 从而实现类加载期织入AspectJ的目的。 if (beanFactory.containsBean("loadTimeWeaver")) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 将 当前环境变量(environment)/系统配置(systemProperties)/系统环境 (systemEnvironment) 注册为单例bean if (!beanFactory.containsLocalBean("environment")) { beanFactory.registerSingleton("environment", this.getEnvironment());}}

2.5.1.3 postProcessBeanFactory(beanFactory);

 postProcessBeanFactory()方法向上下文中添加了一系列的Bean的后置处理器。后置处理器工作的时机是在所有的beanDenifition加载完成之后,bean实例化之前执行。简单来说Bean的后置处理器可以修改BeanDefinition的属性信息。

2.5.1.4invokeBeanFactoryPostProcessors(beanFactory)(重点)

在invokeBeanFactoryPostProcessors()方法中完成了IoC容器初始化过程的三个步骤。

  • 第一步:Resource定位

  在SpringBoot中,包扫描是从主类所在的包开始扫描的,prepareContext()方法中,会先将主类解析成BeanDefinition,然后在refresh()方法的invokeBeanFactoryPostProcessors()方法中解析主类的BeanDefinition获取basePackage的路径。这样就完成了定位的过程。其次SpringBoot的各种starter是通过SPI扩展机制实现的自动装配,SpringBoot的自动装配同样也是在invokeBeanFactoryPostProcessors()方法中实现的。还有一种情况,在SpringBoot中有很多的@EnableXXX注解,细心点进去看的应该就知道其底层是@Import注解,在invokeBeanFactoryPostProcessors()方法中也实现了对该注解指定的配置类的定位加载。常规的在SpringBoot中有三种实现定位,第一个是主类所在包的,第二个是SPI扩展机制实现的自动装配(比如各种starter),第三种就是@Import注解指定的类。(对于非常规的不说了)

  • 第二步:BeanDefinition的载入

        在第一步中说了三种Resource的定位情况,定位后紧接着就是BeanDefinition的分别载入。所谓的载入就是通过上面的定位得到的basePackage,SpringBoot会将该路径拼接成:classpath*:org/springframework/boot/demo/**/*.class这样的形式,然后一个叫做PathMatchingResourcePatternResolver的类会将该路径下所有的.class文件都加载进来,然后遍历判断是不是有@Component注解,如果有的话,就是我们要装载的BeanDefinition。@Configuration,@Controller,@Service等注解底层都是@Component注解,只不过包装了一层罢了。

  • 第三个过程:注册BeanDefinition

   这个过程通过调用上文提到的BeanDefinitionRegister接口的实现来完成。这个注册过程把载入过程中解析得到的BeanDefinition向IoC容器进行注册。通过上文的分析,我们可以看到,在IoC容器中将BeanDefinition注入到一个ConcurrentHashMap中,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的。比如DefaultListableBeanFactory 中的beanDefinitionMap属性。

2.6自动装配

自动装配是使用spring满足bean依赖的一种方法,spring会在应用上下文中为某个bean寻找其依赖的bean。

观察spring的@SpringBootApplication注解,在他的组成注解@EnableAutoConfiguration中执行@Import({AutoConfigurationImportSelector.class},该方法实现了自动装配

2.7创建bean

2.7.1自动装配

在刷新应用上下文的refresh()中,

List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); for (String beanName : beanNames) {...getBean(beanName)//触发依赖注入}

在getBean()中对IoC容器中的BeanDefinition是否存在进行检查,检查是否能在当前的BeanFactory中取得需要的Bean。 如果当前的工厂中取不到,则到双亲BeanFactory中去取。如果当前的双亲工厂取不到,那就顺着双亲BeanFactory 链一直向上查找。

在获取当前Bean的所有依赖Bean,这里会触发getBean的递归调用,知道取到一个没有任何依赖的Bean为止。

最后对创建的Bean进行类型检查,如果没有问题,就返回这个新创建的Bean,这个Bean已经是包含了依赖关系的Bean

2.7.2createBean()的全过程(在启动时全部初始化完)

  1. Bean实例的创建,instanceWrapper = createBeanInstance(beanName, mbd, args);
  2. 为Bean实例设置属性,populateBean(beanName, mbd, instanceWrapper);(依赖注入)
  3. 调用Bean的初始化方法,exposedObject = initializeBean(beanName, exposedObject, mbd);

初始化后bean被spring持有,可以使用上下文来调用,spring中beanfactory是接口,不允许持有bean。

  • 5
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值