花絮#

几年前接触过SpringBoot,跑过Demo,当时刚入行,连Spring都没搞明白,更别说SpringBoot了,就是觉得,哇塞,好厉害,然后一脸懵逼。

工作中没有用到,又没有去主动学习它。觉得很恐惧,这么厉害的东西,肯定是很深奥,很复杂吧!。

这种心理也造成了一定程度上,对某些事物的望而却步,其实只要向前迈出了步子,一步步慢慢来,才发现,以前的那种恐惧心理是多么的幼稚、胆怯、可笑!

序言#

SpringBoot本身并没有多大的花样,所有的知识点其实还都是Spring Framework的。

SpringBoot之前,使用Spring可以说,并不是那么的方便,其实也主要是在搭建一个基于Spring Framework的项目时这个困扰。Spring本身的配置,整合SpringMVC,整合Struts2,整合mybatis,整合Hibernate,整合SpringSecurity等等,如果是Web应用还有个web.xml需要配置。什么都要你去配置一下,第一步就是去找怎么配置,记住这么配置是如何配的,其实并没有切实的意义,毕竟又不是经常需要去搭建一个项目。正因为不常这么配置,不值得记住如何配置,导致每次实际用到时,很麻烦,到处去找如何配置的XML配置文件。

SpringBoot的出现,正是为了解决这个问题,让你可以不去做任何配置的情况下,运行一个Spring应用,或者Web应用。需要做的仅仅是引入SpringBootmaven或者gradle依赖即可。

SpringBoot要做的就是,让你开箱即用!

将使用Spring的成本降到尽可能低,为用户带来了极大的便利。

当然SpringBoot做的也不仅仅只有这些,不过这里仅讨论下它的自动化配置,不讨论其他的。

如果了解Spring@Configuration这个注解的处理过程,会更加容易理解SpringBoot的自动化配置。

如果没有,可以参考这篇解释

穷其林#

这第一件事,就是找门,门都找不到,那不是没门吗!

既然想找门,就得从程序的启动入口去找,任何SpringBoot程序都会用到这么两个

@SpringBootApplication
public class Application{public static void main(String[] args){SpringApplication.run(Application.class, args);}
}

看到这个后,如果好奇其实现,应该会首先查看SpringApplication#run方法,实际调用的是这个重载的静态方法。

// org.springframework.boot.SpringApplication
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return new SpringApplication(primarySources).run(args);
}public ConfigurableApplicationContext run(String... args) {···省略···try {···省略···context = createApplicationContext();exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);// 真正启动应用程序上下文前的一些准备动作// 这里会去将Application.class,注册到org.springframework.context.annotation.AnnotatedBeanDefinitionReader// 也就是去把Application.class注册成一个BeanDefinition实例// 不过Application必须要是一个@ComponentprepareContext(context, environment, listeners, applicationArguments, printedBanner);// 刷新上下文,这个过程中主要就是Bean的实例化和属性赋值绑定// 如果是Web环境,涉及到Web相关的一些东西,但是本质上还是各种Bean的实例化// 和Bean之间依赖关系的处理,代理Bean的生成(涉及到AspectJ的Advice处理)等等refreshContext(context);}return context;
}

BeanDefinition实例有了,就能去启动上下文,处理Bean容器了,容器启动完成后,整个SpringBoot程序基本启动完成!

等等! 是不是少了什么?

这里就注册了一个BeanDefinition,那么多@Component@Configuration@Service@Controller怎么办?

先留着疑问,且待后面解答!

遇山口#

林尽水源,便得一山,山有小口,仿佛若有光。

注意到上面的准备阶段,被注册的Bean必须要被@Component注解,现在Application.class仅有一个注解@SpringBootApplication

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {···省略···
}

挨个查看几个注解的定义后,会发现@SpringBootConfiguration@Component所注解,这就解释了为什么被@SpringBootApplication所注解的Application.class类可以被作为一个Bean注册到BeanDefinitionRegistry

除此之外,还有个令人惊喜的名称:@EnableAutoConfiguration,看名字就看出来它是做啥的了。

没错,SpringBoot的所谓自动配置,就是它在起作用。

这里暂时不讨论@ComponentScan

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {···省略···
}

这个注解又使用了两个注解,分别是@AutoConfigurationPackage@Import

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {}

可以发现,这两个注解最终都指向了同一个注解@Import

@ImportAnnotation时代的<import/>,作用是向BeanDefinitionRegistry注册Bean的。

所以@EnableAutoConfiguration这个注解一共注册了两个Bean,分别是:AutoConfigurationPackages.Registrar.classAutoConfigurationImportSelector.class

先说说AutoConfigurationPackages.Registrar的用处

这个类就干一个事,注册一个Bean,这个Bean就是org.springframework.boot.autoconfigure.AutoConfigurationPackages.BasePackages,它有一个参数,这个参数是使用了@AutoConfigurationPackage这个注解的类所在的包路径。有了这个包路径后,就会扫描这个包下的所有class文件,然后将需要注册到Bean容器的类,给注册进去。

具体可以参见这里 org.springframework.boot.autoconfigure.AutoConfigurationPackages#register
这里就解释了为什么有时候主配置类放的位置不对,导致有些类没被Spring容器纳入管理

桃花源#

经历了一番折腾,就要进入桃花源了

AutoConfigurationImportSelector就是那最后一层窗户纸

// org.springframework.boot.autoconfigure.AutoConfigurationImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}// 为了加载spring-boot-autoconfiguration包下的配置文件META-INF/spring-autoconfigure-metadata.properties// 这里配置的主要是一些SpringBoot启动时用到的一些@ConditionOnClass的配置AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);// 这里的AutoConfigurationEntry,就包含了所有的导入的需要被实例化的BeanAutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);// 返回这些被导入Bean的类全限定名数组return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}··· 省略 ···// 获取所有的需要导入的Bean,这些被导入的Bean就是各个组件需要自动化配置的启动点List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);··· 省略 ···return new AutoConfigurationEntry(configurations, exclusions);}protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {// 使用SpringFactoriesLoader#loadFactoryNames方法,从所有的包及classpath目录下,// 查找META-INF/spring.factories文件,且名称为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;}
}

最终这些配置在META-INF/spring.factories中需要自动配置的类,就会被注册到Spring Bean容器中,然后被实例化,调用初始化方法等!

这些做自动配置的类,基本都会通过实现各种Aware接口,获取到Spring Framework中的BeanFactoryApplicationContext等等所有的一些框架内的组件,用于后面使用。

之后完成自己框架的一些初始化工作,主要就是将原先和Spring整合时,需要手动配置的那些,在这里通过编程式的方式,给做了。

这样,就完成了所谓的自动化配置,全程不需要我们的任何参与。

PS: 这个仅仅是做了一个通用的配置,让用户可以在不做任何配置的情况下能直接使用。但是一些个性化的配置,还是需要通过配置文件的方式,写入配置。对于这部分配置的处理,SpringBoot也都给揽下了

总结#

整体看下来,SpringBoot干的这些,更像是一个体力活,将于Spring集成的那么多三方库的配置,使用代码全部实现了一遍,其使用的核心功能,依然是Spring Framework的那些东西。

但是这个体力活是为使用者省下的,也让Spring Framework更加的具有活力了。

同时微服务的兴起,也是Spring为了顺势而必须作出的一个改变,也可以说为Spring在微服务领域立下了汗马功劳!

springboot自动配置_揭秘SpringBoot自动化配置相关推荐

  1. quartz配置_基于spring-boot 2.x +quartz 的CRUD任务管理系统

    基于spring-boot 2.x + quartz 的CRUD任务管理系统,适用于中小项目. 开发环境 JDK1.8.Maven.Eclipse 技术栈 SpringBoot 2.0.1.thyme ...

  2. sso 服务端配置_使用身份传播配置服务提供商启动的SSO

    sso 服务端配置 关于本系列 这个由三部分组成的系列文章"使用带有WebSphere Liberty的SAML 2.0进行跨域单点登录"介绍了在混合云环境中使用IBM®Cloud ...

  3. linux中python编译器的配置_方舟编译器环境配置及源码编译过程详解

    1)首先将方舟编译器源代码包下载到本地. https://www.openarkcompiler.cn/download/OpenArkCompiler-0.2.tar.gz 2)Ubuntu系统中方 ...

  4. python查看电脑配置_怎么看电脑配置_怎么查看电脑配置好坏|信息【图文】-太平洋IT百科...

    怎么看电脑配置?怎么查看电脑配置好坏和配置信息?查看电脑配置有两种方法,一种是查看电脑中的设备管理器,但这种方法通常无法完整地查看到电脑的配置信息;另外一种方法是使用软件查看,例如鲁大师.驱动精灵等. ...

  5. java 微信退款配置_微信支付退款配置

    微信支付退款配置 1.微信支付配置 第一步,登录商城后台,设置->交易设置->支付配置 ,选择微信支付,点击配置进入到微信支付参数配置界面. 从应用ID和应用密钥下面的提示可以看出,微信支 ...

  6. python查看电脑配置_怎么查看电脑配置

    怎么查看电脑配置 导语:正准备买笔记本或者看到组装好了的电脑,或者已经买好电脑的朋友,想知道电脑的配置参数.电脑的配置高低,我们可以通过以下方式来判断,一起来看看吧! 一.打开电脑 在桌面上[我的电脑 ...

  7. dubbo yml配置_利用springboot+dubbo,构建分布式微服务,全程注解开发(一)

    随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 一.先来一张图 说起 Dubbo,相信大家都不 ...

  8. maven netty 配置_使用Springboot整合开发Netty(一个表白的小案例)

    写了很久的java并发包里面的文章,今天换一个口味.很早之前学的Netty,由于最近项目经常使用到,遇到了很多坑,因此想通过一个体系教程说一下这个高性能异步通信框架Netty,这也是netty的第一篇 ...

  9. springboot多环境配置_编辑 SpringBoot|第五章:多环境配置

    多环境配置 在开发应用时,常用部署的应用是多个的,比如:开发.测试.联调.生产等不同的应用环境,这些应用环境都对应不同的配置项,比如swagger一般上在生产时是关闭的:不同环境数据库地址.端口号等都 ...

最新文章

  1. python数据分析的主要流程-python 数据分析概述
  2. java框架核心技术_你必须掌握的 21 个 Java 核心技术!(干货)
  3. websocket与socket.io
  4. 伯克利、OpenAI等提出基于模型的元策略优化强化学习
  5. java工具类_非常实用的Java工具类,拿走不谢(一)
  6. Java I/O系统(一)
  7. HDU 2181 哈密顿绕行世界问题
  8. php命令行路径,命令行 – PHP命令行php.ini路径错误
  9. 初次涉足手机广告联盟行业
  10. NTP服务器的相关配置
  11. “非主流”数据库合集,简介
  12. for循环-结束循环
  13. 2019年下半年软件设计师备考指南
  14. 编译OpenCV:opencv/3rdparty/openjpeg/openjp2/opj_stdint.h:48:2: error: #error unsupported platform
  15. aws iam php,AWS实战 - IAM角色的简单使用
  16. PHP-MySQL停车场车位管理系统(附源码
  17. 详解音视频直播平台搭建中的低延时
  18. 读《软件测试》(美)Ron Patton笔记之一(2) 软件开发过程
  19. 2022-4-16 CGI服务器原理示例代码《Linux高性能服务器》笔记
  20. mvc中 html是否单选按钮,c# – 如何使用Html.EditorFor在MVC3中渲染单选按钮?

热门文章

  1. liblfds 测试
  2. Web服务器网管交流一下
  3. 基础知识—循环语句-循环控制
  4. linux提示桌面正在处理文件,linux系统下桌面配置文件.desktop的几个小问题
  5. 专访丨HashData创始人简丽荣:云原生与大数据时代,湖仓一体代表了未来
  6. 八大看点丨第十届数据技术嘉年华精彩抢先速览
  7. 不会使用Spring的配置文件,赶紧把这个甩给他
  8. 面试官问我:如何在 Python 中解析和修改 XML
  9. 面试官:请讲一下Redis主从复制的功能及实现原理
  10. 教师节送什么老师最开心?程序员三招解决家长送礼难题!