欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > spring容器的启动流程

spring容器的启动流程

2024/10/25 13:18:59 来源:https://blog.csdn.net/qq_64064246/article/details/140036278  浏览:    关键词:spring容器的启动流程

        spring容器的启动流程是一个面试中比较难答的题目。这块内容比较复杂,回答的时候如果想到什么回答什么,很容易把面试官绕晕。因此比较好的回答方式就是,先理清一个大致的启动流程,再根据面试官的问题细说小点。

这里我们从AnnotationConfigApplicationContext着手分析源码:

说明:这里通过AnnotationConfigApplicationContext扫描com.test包下所有被注解修饰的bean对象,创建了一个applicationContext对象(spring容器)。

这里的类A被@Component注解标识了,因此会被放进applicationContext上下文中。再通过getBean方法,就可以获取A的实例对象。

注意:关于spring容器的启动有很多种方式,比如说ClassPathApplicationContext,通过XML的方式启动一个spring容器。但没有annotation这种注解式开发更方便。


1 构造方法

跟进AnnotationConfigApplicationContext的构造方法可以看到:

1.1 this 方法

跟进这个this方法:

说明:

  1. StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create"); 这行代码主要用于启动一个名为"spring.context.annotated-bean-reader.create"的启动步骤,它是用于计算和监控Spring应用的启动时间,主要用于性能的跟踪监控。

  2. this.reader = new AnnotatedBeanDefinitionReader(this); 这行代码创建了一个AnnotatedBeanDefinitionReader实例,并将其赋值给AnnotationConfigApplicationContextreader成员变量。AnnotatedBeanDefinitionReader类主要用于从注解化的类中读取Bean定义信息,它是Spring处理注解主要的类。

  3. createAnnotatedBeanDefReader.end(); 这行代码结束了"spring.context.annotated-bean-reader.create"的启动步骤,主要用于性能的跟踪监控。

  4. this.scanner = new ClassPathBeanDefinitionScanner(this); 这行代码创建了一个ClassPathBeanDefinitionScanner实例,并将其赋值给AnnotationConfigApplicationContextscanner成员变量。ClassPathBeanDefinitionScanner类主要用于从classpath下的类文件中扫描Bean定义信息


1.2 scan 方法

详细解释如下:

  1. Assert.notEmpty(basePackages, "At least one base package must be specified"); 这行代码用于判断方法参数basePackages是否为空。如果为空,它将抛出一个IllegalArgumentException异常,消息为"At least one base package must be specified"。

  2. StartupStep scanPackages = this.getApplicationStartup().start("spring.context.base-packages.scan").tag("packages", () -> {return Arrays.toString(basePackages);}); 这行代码启动一个名为"spring.context.base-packages.scan"的启动步骤,并标记了"packages"标签(其值为传入的basePackages)。这也是用于计算和监控Spring应用启动时间、性能跟踪。

  3. this.scanner.scan(basePackages); 这行代码使用之前在构造函数里面初始化的scanner(一个ClassPathBeanDefinitionScanner实例)来扫描指定的包basePackages。在这个过程中,scanner将查找所有包及其子包下的类,如果这个类符合Spring Bean的定义(比如被@Component, @Service, @Repository, @Controller等注解标注的类),那么scanner就会将这个类作为一个Bean定义并注册到Spring上下文。

  4. scanPackages.end(); 这行代码结束了之前启动的"spring.context.base-packages.scan"步骤。同样地,这个步骤也主要用于性能跟踪。

简单来说,scan方法就是:用于扫描指定的基础包,以查找并注册Bean定义。


1.3 refresh 方法(重难点)

public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {// 开启一个启动步骤记录器,用于记录开始刷新上下文StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 刷新前预处理,准备刷新上下文this.prepareRefresh();// 获取在容器初始化时创建的BeanFactory(我们后面取类都通过这个BeanFactory中加载出来)ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();// 准备Bean工厂,BeanFactory的预处理工作,回向容器中添加一些组件this.prepareBeanFactory(beanFactory);try {// 处理Bean工厂(子类重写该方法,可以实现在BeanFactory创建并预处理完成后做进一步的设置)this.postProcessBeanFactory(beanFactory);// 开启一个启动步骤记录器,用于记录开始处理Bean后置处理器StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");// 在BeanFactory初始化之后执行BeanFactory的后置处理器this.invokeBeanFactoryPostProcessors(beanFactory);// 注册Bean后置处理器。它的主要作用就是干预Spring初始化Bean的流程,完成代理、自动注入、循环依赖等功能。this.registerBeanPostProcessors(beanFactory);// 结束Bean后置处理器步骤记录beanPostProcess.end();// 初始化Messagesource组件,主要是用于国际化this.initMessageSource();// 初始化应用事件广播器this.initApplicationEventMulticaster();// 执行刷新回调方法(留给子类重写的方法,在容器刷新时可以自定义一些逻辑)this.onRefresh();// 注册监听器(有了监听器之后,就可以接收上面事件广播器广播的消息了)this.registerListeners();// 完成Bean工厂的初始化,主要作用是初始化所有剩下的单例Beanthis.finishBeanFactoryInitialization(beanFactory);// 完成刷新,发布容器刷新完成的事件this.finishRefresh();} //以下是容器启动失败的场景,可以不过多深究catch (BeansException var10) {// 如果在上下文初始化过程中遇到异常,记录警告日志并取消刷新尝试if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);}// 销毁所有Beanthis.destroyBeans();// 取消刷新this.cancelRefresh(var10);// 抛出异常throw var10;} finally {// 重置公共缓存this.resetCommonCaches();// 结束刷新步骤记录contextRefresh.end();}}}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com