网易首页 > 网易号 > 正文 申请入驻

项目开发框架原理总结

0
分享至

SpringBoot原理总结

  • 几个重要的事件回调机制
  • ApplicationContextInitializer
  • 使用分析
  • SpringBoot内置的ApplicationContextInitializer
  • 扩展实现方式
  • 编程方式
  • 添加配置方式
  • spring.factories方式
  • 启动流程
  • 事件监听机制
  • SpringBoot自定义starter
  • 总结

几个重要的事件回调机制

ApplicationContextInitializer

  • ApplicationContextInitializer来源于Spring框架主要作用就是在ConfigurableApplicationContext类型或者子类型的ApplicationContextrefresh之前允许对ConfigurableApplicationContext的实例做进一步的设置和处理
  • ApplicationContextInitializer接口:是在Spring容器刷新之前执行的一个回调函数是在ConfigurableApplicationContextrefresh()方法之前,即在Spring框架内部执行ConfigurableApplicationContextrefresh()方法或者SpringBootrun()方法之前调用作用是初始化SpringConfigurableApplicationContext的回调接口
  • 通常用于需要对应用上下文进行初始化的web应用程序中: 比如根据上下文环境注册属性或者激活概要文件

使用分析

  • ApplicationContextInitializer接口的典型应用场景:对web应用程序的应用上下文进行初始化比如:注册属性源property sources针对上下文的环境信息environment激活相应的profile
  • 在一个SpringBoot的应用程序中:classpath上有很多jar包,有些jar包需要在ConfigurableApplicationContextrefresh()方法调用之前对应用上下文做一些初始化动作因此会提供自己的ApplicationContextInitializer实现类,然后配置在自己的META-INF/spring.factories属性文件中这样相应的ApplicationContextInitializer实现类就会被SpringApplicationinitialize()方法发现
  • SpringApplicationinitialize()方法,在SpringApplication的构造函数内执行,从而确保在SpringApplicationrun()方法之前完成
  • 然后在应用上下文创建之后,应用上下文刷新之前的准备阶段被调用

SpringBoot内置的ApplicationContextInitializer

  • 使用SpringBoot web应用默认使用的ApplicationContextInitializer的实现:DelegatingApplicationContextInitializer:使用环境属性context.initializer.classes指定的初始化容器initializer进行初始化工作,如果没有指定则不进行任何操作使得可以在application.properties中可以自定义实现类配置ContextIdApplicationContextInitializer:参照环境属性,设置Spring应用上下文的IDID值的设置会参照环境属性:spring.application.namevcap.application.namespring.config.namespring.application.indexvcap.application.instance_index如果这些属性都没有,ID使用applicationConfigurationWarningApplicationContextInitializer:对于一般配置错误在日志中做出警告ServerPortInfoApplicationContextInitializer:将内置servlet容器实际使用的监听端口写入到environment环境属性中这样属性local.server.port就可以直接通过@Value注入到测试中或者通过环境属性environment获取SharedMetadataReaderFactoryContextInitializer:创建一个SpringBootConfigurationClassPostProcessor共用的CachingMetadataReaderFactory对象实现类为ConcurrentReferrenceCachingMetadataReaderFactoryConditionEvaluationReportLoggingListener:ConditionEvaluationReport写入日志
  • ApplicationContextInitializerSpring中允许在上下文刷新之前做自定义操作,如果需要对Spring的上下文进行深度整合,可以借助ApplicationContextInitializer进行很好的实现
  • spring-test包里有一个注解org.springframework.test.context.ContextConfiguration中有一个属性可以指定ApplicationContextInitializer辅助集成测试时自定义对上下文进行预处理

扩展实现方式

编程方式

  • 先定义ApplicationContextInitializer:

// @Order(66) - @Order的值越小就越早执行. 标注在类上, 不是方法上@Order(66)public class customerApplicationContextInitializer implements ApplicationContextInitializer {@Overridepublic void initialize(ConfigurableApplicationContext applicationContext) {// 输出容器中有多少个beanSystem.out.println("Bean的数量为: " + applicationContext.getBeanDefinitionCount());/** 输出容器中所有bean的beanName */ System.out.println(applicationContext·getBeanDefinitionCount + "个Bean的名称:"); String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanDefinitionNames) { System.out.println(beanName); }}}

  • 在启动类中手动增加initializer:

@SpringBootApplication@EnableConfigServer@EnableDiscoveryClientpublic class ConfigServer {public static void mian(String[] args) {SpringApplication springApplication = new SpringApplication(ConfigServer·class);// 添加自定义的ApplicationContextInitializer实现类的实例用来注册ApplicationContextInitializerspringApplication.addInitializers(new customerApplicationContextInitializer());ConfigurableApplicationContext applicationContext = springApplication.run(args);applicationContext.close();}}

添加配置方式

  • 添加配置的方式是通过DelegatingApplicationContextInitializer初始化类中的initialize()方法获取到application.propertiescontext.initializer.class对应的类并执行对应的initialize()方法
  • 只需要将实现了ApplicationContextInitializer的类添加到application.properties即可先定义一个实现了ApplocationContextInitializer的类然后在application.properties中定义:context.initializer.class= com.oxford.customerApplicationContextInitializer

spring.factories方式

  • SpringApplicationRunListenerApplicationContextInitializer,SpringApplicationRunListener需要配置在META-INF/spring.factories中
  • ApplicationRunner
  • CommandLineRunnerApplicationRunner,CommandLineRunner需要放在IOC容器中

启动流程

  • 创建SpringApplication对象调用initialize(sources)方法创造对象保存主配置类判断当前是否为一个web应用从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer,然后保存起来从从类路径下找到META-INF/spring.factories配置的所有ApplicatListener从多个配置类中找到有main方法的主配置类
  • 运行run方法

public ConfigurableApplicationContext run(String··· args) { StopWatch stopWatch = new StopWatch(); stopWatch.start();// 停止监听 ConfigurableApplicationContext context = null;// 声明一个IOC容器 Collection

exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); Banner printedBanner = this.printBanner(environment); context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext·class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this·logStartupInfo) { (new StartupInfoLogger(this·mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }

  • 获取SpringApplicationRunListeners,从类路径下META-INF/spring.factories
  • 回调所有的获取SpringApplicationRunListener.starting()方法
  • 封装命令行参数
  • 准备环境prepareEnvironment,创建环境完成后回调SpringApplicationRunListeners.environmentPrepared():表示环境准备完成

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { ConfigurableEnvironment environment = this.getOrCreateEnvironment(); this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared((ConfigurableEnvironment)environment); this.bindToSpringApplication((ConfigurableEnvironment)environment); if (!this·isCustomEnvironment) { environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass()); } ConfigurationPropertySources.attach((Environment)environment); return (ConfigurableEnvironment)environment; }

  • 创建ApplicationContext:决定创建web的IOC还是普通的IOC

protected ConfigurableApplicationContext createApplicationContext() { Class contextClass = this.applicationContextClass; if (contextClass == null) { try { switch(this·webApplicationType) { case SERVLET: contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"); break; case REACTIVE: contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"); break; default: contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext"); } } catch (ClassNotFoundException var3) { throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3); } } return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass); }

  • 准备上下文环境prepareContext:将environment保存到IOC中,并且调用applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法.然后回调SpringApplicationRunListener的contextPrepared方法

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); this.postProcessApplicationContext(context); this.applyInitializers(context); listeners.contextPrepared(context); if (this·logStartupInfo) { this.logStartupInfo(context.getParent() == null); this.logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this·allowBeanDefinitionOverriding); } Set sources = this.getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); this.load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); }

  • prepareContext运行完成以后回调所有的SpringApplicationRunListeners的contextLoaded()方法
  • 刷新容器refreshContext,IOC容器初始化.在web应用中还会创建嵌入式的tomcat.在refreshContext,是扫描,创建.加载所有组件的地方(配置类,组件,自动配置)

private void refreshContext(ConfigurableApplicationContext context) { this.refresh(context); if (this·registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException var3) { } } }

  • 调用callRunner()从IOC容器中获取所有的ApplicationRunner和CommandLineRunner.先回调ApplicationRunner,后回调CommandLineRunner
  • 最后回调SpringApplicationRunListeners的listeners.running(context)
  • 整个SpringBoot应用启动完成以后返回启动的IOC容器

事件监听机制

  • ApplicationContextInitializer

public class HelloApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) { System.out.println("ApplicationContextInitializer...initialize"+configurableApplicationContext); }}

  • SpringApplicationRunListener

public class HelloSpringApplicationRunListener implements SpringApplicationRunListener { @Override public void starting() { System.out.println("SpringApplicationRunListener...starting..."); } @Override public void environmentPrepared(ConfigurableEnvironment environment) { Object o=environment.getSystemProperties().get("os.name"); System.out.println("SpringApplicationRunListener...environmentPrepared..."); } @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener...contextPrepared..."); } @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener...contextLoaded..."); } @Override public void started(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener...started..."); } @Override public void running(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener...running..."); } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { System.out.println("SpringApplicationRunListener...failed..."); }}

  • ApplicationContextInitializer,SpringApplicationRunListener需要配置在META-INF/spring.factories中

org.springframework.context.ApplicationContextInitializer=\com.web.springboot.listener.HelloApplicationContextInitializerorg.springframework.context.SpringApplicationRunListener=\com.web.springboot.listener.HelloSpringApplicationRunListener

  • ApplicationRunner

@Component// 容器中的类public class HelloApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("ApplicationRunner...run..."); }}

CommandLineRunner

@Component// 容器中的类public class HelloCommandLineRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("CommandLineRunner...run"+ Arrays.asList(args)); }}

  • ApplicationRunner,CommandLineRunner需要放在IOC容器中-@Component

SpringBoot自定义starter

  • starter:这个场景需要的依赖是什么?如何编写自动配置?@Configuration // 指定这个类是一个自动配置类 @ConditionalOnXxx() // 在指定条件成立的情况下自动配置类生效 @AutoConfigureOrder() // 指定自动配置类的顺序 @AutoConfigureAfter() // 指定自动配置在特定的类之后 @Bean // 给容器中添加组件 (@ConfigurationProperties 结合相关 XxxProperties类来绑定相关的配置 )@EnableConfigurationProperties // 让XxxProperties类生效加入到容器中
  • 配置自动装配Bean:将标注@Configuration的自动配置类,放在classpath下的META-INF/spring.factories文件中才能加载org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
  • 模式启动器: 启动器是一个空jar文件,仅提供辅助性依赖管理,依赖导入,这些依赖用于自动装配或者其它类库.官方命名空间: - 前缀: spring-boot-starter- - 模式: spring-boot-starter-模块名 自定义命名空间: - 前缀: -spring-boot-starter- - 模式: 模块名-spring-boot-starter专门写一个自动配置模块启动器依赖自动配置模块,使用时只需要引入启动器( starter )
  • 总结官方文档源码

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
22天巨变,哈维与巴萨主席决裂!解读4大原因:拉总被打脸

22天巨变,哈维与巴萨主席决裂!解读4大原因:拉总被打脸

叶青足球世界
2024-05-17 15:43:02
LV总监空降成都,全身穿搭价值3000万,网友辣评:像农民工赶火车

LV总监空降成都,全身穿搭价值3000万,网友辣评:像农民工赶火车

动物的温情故事
2024-05-16 04:15:23
彻底倒向美囯?拒绝中方移民,驱离中方工人,中方大怒:永不合作

彻底倒向美囯?拒绝中方移民,驱离中方工人,中方大怒:永不合作

星辰故事屋
2024-04-27 19:04:44
大理:鼓励收购存量房作为保障房或人才房,去化周期超24个月的县市不再新建保障房

大理:鼓励收购存量房作为保障房或人才房,去化周期超24个月的县市不再新建保障房

澎湃新闻
2024-05-16 13:12:33
为扳倒市委书记,他豁出一切:被坐牢、被砍、妻子被杀,结果如何

为扳倒市委书记,他豁出一切:被坐牢、被砍、妻子被杀,结果如何

阿胡
2024-03-01 15:51:53
房子滞销,下猛药了

房子滞销,下猛药了

越女事务所
2024-05-17 16:30:15
新加坡新任总理夫人因高颜值上热搜!黑裙配金链太美,堪比女明星

新加坡新任总理夫人因高颜值上热搜!黑裙配金链太美,堪比女明星

时尚丽人风行
2024-05-17 19:34:30
大逆转!紫薇力擒德约终结者晋级决赛,冲击大师赛第6冠

大逆转!紫薇力擒德约终结者晋级决赛,冲击大师赛第6冠

大秦壁虎白话体育
2024-05-18 00:23:33
范大将军首度执掌教鞭!官方:40岁范佩西出任荷甲海伦芬主帅

范大将军首度执掌教鞭!官方:40岁范佩西出任荷甲海伦芬主帅

直播吧
2024-05-17 17:00:25
纪实:禽兽赵志勇强占25名初中生,14名未满14岁,下场大快人心

纪实:禽兽赵志勇强占25名初中生,14名未满14岁,下场大快人心

小胡子谈汇
2024-05-17 19:27:54
东方卫视迎来一部谍战大片!马上播出,女演员都好漂亮,超期待

东方卫视迎来一部谍战大片!马上播出,女演员都好漂亮,超期待

荆钰波爱唱歌
2024-05-17 03:27:01
几千年都没有变过!

几千年都没有变过!

吴女士
2024-04-26 11:16:12
普京为出访准备充足,虽然中国很安全,但他还留了一个“护身符”

普京为出访准备充足,虽然中国很安全,但他还留了一个“护身符”

小小包工头阿汾
2024-05-17 20:25:11
两性科普:女生小妹妹肥大的几个分型

两性科普:女生小妹妹肥大的几个分型

坟头长草
2024-05-17 12:27:17
安徽一厅干被查!数天前曾参加公开活动

安徽一厅干被查!数天前曾参加公开活动

鲁中晨报
2024-05-17 19:47:04
五旬男子健身时不慎被绳索吊住离世 当地政府工作人员:他去年就做过“吊脖”,有人曾劝阻

五旬男子健身时不慎被绳索吊住离世 当地政府工作人员:他去年就做过“吊脖”,有人曾劝阻

红星新闻
2024-05-16 18:23:11
炸裂!汽车女主播擦边直播,多次展露隐私部位,直播间录屏被曝光

炸裂!汽车女主播擦边直播,多次展露隐私部位,直播间录屏被曝光

阿芒娱乐说
2024-05-15 19:38:35
美国发出邀请,王毅外长已交底,APEC峰会,中方的答案引高度关注

美国发出邀请,王毅外长已交底,APEC峰会,中方的答案引高度关注

大崔Muisc
2024-05-17 14:19:46
有人吐槽江浙地区没有夜生活:娱乐场所早早就关门,晚上8点大街上空无一人

有人吐槽江浙地区没有夜生活:娱乐场所早早就关门,晚上8点大街上空无一人

可达鸭面面观
2024-05-16 20:59:49
记者扮男客潜入采耳店,偷拍服务全过程:女技师、柔式按摩别有洞天

记者扮男客潜入采耳店,偷拍服务全过程:女技师、柔式按摩别有洞天

古今档案
2024-05-07 13:04:58
2024-05-18 05:56:49
攻城狮Chova
攻城狮Chova
一位攻城狮的自我修养
98文章数 28关注度
往期回顾 全部

科技要闻

京东拼增长,大力出奇迹

头条要闻

媒体:菲律宾在南海闹事时 美国航母紧急"撤"到新加坡

头条要闻

媒体:菲律宾在南海闹事时 美国航母紧急"撤"到新加坡

体育要闻

中超疯狂星期五!5场28球,单场5球起步

娱乐要闻

《庆余年2》首播口碑出炉!有好有坏

财经要闻

重磅!楼市王炸来了 多部门出手救楼市

汽车要闻

内饰与配置全新升级 全新途观L PRO将于5月30日上市

态度原创

手机
教育
家居
数码
军事航空

手机要闻

vivo X100s首销战报出炉,蓝厂真赌对了

教育要闻

英国毕业生工签审查结果出炉:建议继续保留!附PSW签证申请指南

家居要闻

遇见交响 音乐流动在设计之中

数码要闻

驰为 CoreBox 迷你主机发布:i5-13500H、2.5G 网口,1999 元起

军事要闻

印防长称印度将开始建第三艘母

无障碍浏览 进入关怀版