SpringBoot2入门自动配置原理及源码分析

目录
  • SpringBoot自动配置
    • 一、@SpringBootApplication
      • 1. @SpringBootConfiguration
      • 2. @ComponentScan
      • 3. @EnableAutoConfiguration
    • 二、自动配置示例
      • 1. 未生效的自动配置
      • 2. 生效的自动配置
    • 三、小结

SpringBoot自动配置

之前为什么会去了解一些底层注解,其实就是为了后续更好的了解 springboot 底层的一些原理,比如自动配置原理。

一、@SpringBootApplication

从 MainApplication 中的@SpringBootApplication开始。

进入@SpringBootApplication,可以看到这是一个合成注解(红框中是要关注的)。

1. @SpringBootConfiguration

这个注解干嘛的?

直接点进去,发现有一个@Configuration注解,那这不就是个配置类嘛。

进而也说明了,MainApplication 也是一个配置类。

2. @ComponentScan

这个已经很熟悉了,可以指定扫描哪些 Spring 注解。

只不过这里,加了一些其他的过滤条件,暂时不关注。

3. @EnableAutoConfiguration

这个是最重要的注解了,听名字就不一般,开启自动配置。

点进去,发现也是一个合成注解(红框需要关注)。

(1)@AutoConfigurationPackage

听名字像是自动配置包?依旧点进去。

可以看到原来是导入了一个叫Registrar的组件,继续点进 Registrar

这里是利用Registrar()给容器中导入一系列组件,也就是批量注册组件

在这里打个断点,debug 启动一下。

registerBeanDefinitions()方法中有个传参:

metadata,是注解的元信息,可以看到这个注解是被标注在com.pingguo.boot.MainApplication

而在registerBeanDefinitions()方法体内,new 了一个AutoConfigurationPackages.PackageImports(),里面传入的是元注解,通过getPackageNames()获取到包名。

AutoConfigurationPackages.register(
    registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0])
);

在 idea 中可以单独执行下片段代码(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames()

选中右击,再点击 Evaluate。

得到的结果就是com.pingguo.boot。为什么是这个?因为注解标注在MainApplication类,而这个类就属于com.pingguo.boot

拿到包名之后,封装到数组里,也就是上述代码片段中的toArray(new String[0]),最后注册进去。

所以,这里的Registrar()就是把指定的包下的所有组件批量注册到容器中。

(2)@Import(AutoConfigurationImportSelector.class)

上面指定好默认包规则之后,就需要去导入需要的包了,利用的是AutoConfigurationImportSelector,继续点进去看。

这里有个selectImports方法,这个方法决定了要具体导入哪些,返回的是一个数组。

方法体内,又是调用了getAutoConfigurationEntry()方法来获取配置入口,进而再通过getConfigurations()方法获取具体配置,最终转成数组返回。

显然getAutoConfigurationEntry()是个重点。

往下翻一点,就是getAutoConfigurationEntry()的实现,在这里打个断点(把上面的断点取消掉)。

debug重新运行一下,往下走到getCandidateConfigurations()

这里是获取所有候选配置,目前可以看到这里是共有 127 个。

为什么是这 127 个?其实是在配置文件里写死了,在 springboot 启动时候,给容器加载的所有场景的配置类。

定义的位置是在这:\spring-boot-autoconfigure\2.3.4.RELEASE\spring-boot-autoconfigure-2.3.4.RELEASE.jar!\META-INF\spring.factories

虽然这些一股脑的在启动时候会去加载到容器,但是最终会按需开启配置。

比如点开aop,看到@ConditionalOnClass({Advice.class})这个条件,是当存在Advice类时候才导入组件,但实际上这里并没有Advice

这就是基于 springboot 的按条件装配@Conditional,根据规则最终实现按需装配。

二、自动配置示例

分别用最终未生效、和生效的自动配置来加深理解。

1. 未生效的自动配置

比如 cache。

可以看到CacheAutoConfiguration上是加了几个条件装配的。

(1)@ConditionalOnClass({CacheManager.class})

在 idea 中使用ctrl+N搜索一下CacheManager,发现是存在的,那么这个条件满足。

(2)@ConditionalOnBean({CacheAspectSupport.class})

这个条件是要求容器中存在CacheAspectSupport这个组件才可以。

现在来判断一下是否存在这个组件,在 main 方法里增加测试代码:

... ...
      String[] beanNamesForType = run.getBeanNamesForType(CacheAspectSupport.class);
      System.out.println("==CacheAspectSupport类型组件的数量==" + beanNamesForType.length);
... ...

运行查看输出。

发现数量等于 0,也就是不存在该类型的组件。

也就是说@ConditionalOnBean({CacheAspectSupport.class})这个条件不满足,所以整个类CacheAutoConfiguration里的配置都不生效。

2. 生效的自动配置

之前写过 web 的demo,那么 web 相关的配置自然是生效的,找到它。

这里有不少后缀是**AutoConfiguration的配置,直接来看DispatcherServletAutoConfiguration

@Configuration(proxyBeanMethods = false):表示是一个配置类。

@ConditionalOnWebApplication(type = Type.SERVLET):条件是否为一个 web 应用,而且是原生 SERVLET 类型的(因为springboot2还有webflux),当前满足条件。

@ConditionalOnClass({DispatcherServlet.class}):条件是否导入了DispatcherServlet类,这里也是有的。

还有 2 个注解直接没见过,这里不用太多关注,了解一下:

@AutoConfigureOrder:这个配置类的配置优先级顺序。@AutoConfigureAfter:表示在xx之后才配置这个类,这里就是在配置完ServletWebServerFactoryAutoConfiguration.class后,再配置当前的类。

所以,类上的几个条件都是满足的,就可以进一步到类中了,继续往下找:

看到DispatcherServletConfiguration类上也有条件:

@Conditional({DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition.class}):

别看这么长,其实就是上面的一个类

@ConditionalOnClass({ServletRegistration.class}): 这个也存在。

@EnableConfigurationProperties({WebMvcProperties.class}):

这个很熟悉了,使用前面刚学习完不久,它并不是条件装配,而是用来绑定外部配置文件的,点进去。

可以看到,会与配置文件中前缀是spring.mvc的所有属性进行绑定。

另外,还可以自动把组件注册到容器中去。

这里可以试一下,在 main 方法里增加输出:

String[] beanNamesForType1 = run.getBeanNamesForType(WebMvcProperties.class);
    System.out.println("==WebMvcProperties类型组件的数量==" + beanNamesForType1.length);

运行一下,果然是有一个:

到此,说明DispatcherServletConfiguration这个配置类也是生效的。

继续往下就看到方法dispatcherServlet(),而且是加了@Bean注解,就是给容器中注册DispatcherServlet类型的组件。

这里的经过是:

new 一个DispatcherServlet()对象dispatcherServlet。接着对dispatcherServlet一通 set 设置。最后返回这个对象dispatcherServlet

在之前学习 springMVC 时候,还要手动去设置关于DispatcherServlet的一堆东西。而在 springboot 里已经在底层设置好了,并且注册到容器中去了,所以我们能直接使用。

三、小结

随着进一步跟着源码来理解自动配置的原理,使得自己更深的体会到 springboot 的优点。

那么多东西不需要我们手动去配置了,并不是说用不上,而是在底层springboot已经帮我们完成好了配置。

当然,目前的重点还是学会使用 springboot,但是带着之前对 springboot 的疑问来学习,还是更有收获的。

(0)

相关推荐

  • SpringBoot2零基础到精通之自动配置底层分析及小技巧

    目录 1 自动配置底层分析 1.1 ​自动配置注解解析 1.2 修改默认配置 1.3 总结 1.4 最佳实践 2 开发小技巧 2.1 Lombok简化开发 2.2 伪热更新 2.3 创建Spring Initailizr项目 1 自动配置底层分析 1.1 ​自动配置注解解析 @SpringBootApplication注解是SpringBoot的核心注解,他是由以下三个注解总和而成. @SpringBootConfiguration 该注解底层有一个@Configuration注解,标明当前类是

  • springBoot2.X配置全局捕获异常的操作

    springBoot2.X配置全局捕获异常 先来看一段代码:当传入的id是0的时候,就会报异常. @RestController public class HelloController { @GetMapping("/getUser") public String getUser(int id) { int j = 1 / id; return "SUCCESS" + j; } } 访问时: 我们知道这个页面要是给用户看到,用户可能不知道这是什么. 方法一:将异常

  • Springboot2.0配置JPA多数据源连接两个mysql数据库方式

    目录 1. 目录结构及配置 2. 配置文件 3. DataSourceConfigurer类 4. 主数据源配置 5. 从数据源配置 6.User实体类模板 7.dao层模板 8.service模板 9.IBaseService接口 1. 目录结构及配置 pom.xml(不要乱放太多,会引起jar冲突,亲身体验) <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://m

  • SpringBoot2.1.x,创建自己的spring-boot-starter自动配置模块操作

    一)spring-boot-starter命名规则 自动配置模块命名规则:xxx-spring-boot,如:aspectlog-spring-boot 启动器命名规则:xxx-spring-boot-starter,如:aspectlog-spring-boot-starter 如两者只有一个模块:建议以xxx-spring-boot-starter方式命名. springboot建议以xxx前缀的方式对自己的自动配置命名的. 二)spring-boot-starter条件注解 注解 说明 @

  • Springboot2.6.x的启动流程与自动配置详解

    目录 一.Springboot启动流程 1. 第一步对SpringApplication的初始化 2. 第二步SpringApplication具体的启动方案 3.refreshContext:核心启动tomcat流程 二.Springboot自动配置原理 1. @SpringBootApplication 2自动配置流程 3.额外注解学习 总结 一.Springboot启动流程 所有的SpringBoot工程,都有自己的启动类,这个启动类身上有一个固定注解@SpringBootApplicat

  • springboot2.1.3配置sftp自定义sftp连接池的详细过程

    项目地址 项目地址:https://gitee.com/xuelingkang/spring-boot-demo 完整配置参考com.example.ftp包 maven: <!-- sftp --> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </de

  • SpringBoot2入门自动配置原理及源码分析

    目录 SpringBoot自动配置 一.@SpringBootApplication 1. @SpringBootConfiguration 2. @ComponentScan 3. @EnableAutoConfiguration 二.自动配置示例 1. 未生效的自动配置 2. 生效的自动配置 三.小结 SpringBoot自动配置 之前为什么会去了解一些底层注解,其实就是为了后续更好的了解 springboot 底层的一些原理,比如自动配置原理. 一.@SpringBootApplicati

  • SpringBoot 自动配置原理及源码解析

    初始化一个Springboot项目,在主启动类会有这么一个注解:@SpringBootApplication,自动装配的秘密全在主启动类这个注解里面了 点进去一层会发现有三个子注解组成,分别是 @SpringBootConfiguration.@ComponentScan和@EnableAutoConfiguration 接下来分别解释这三个注解在整个自动装配过程中的作用 1.@SpringBootConfiguration 点进去发现它是@Configure,代表当前是一个配置类,意思就是当前

  • Nacos配置中心集群原理及源码分析

    目录 Nacos集群工作原理 配置变更同步入口 AsyncNotifyService AsyncTask 目标节点接收请求 NacosDelayTaskExecuteEngine ProcessRunnable processTasks DumpProcessor.process Nacos作为配置中心,必然需要保证服务节点的高可用性,那么Nacos是如何实现集群的呢? 下面这个图,表示Nacos集群的部署图. Nacos集群工作原理 Nacos作为配置中心的集群结构中,是一种无中心化节点的设计

  • java编程Reference核心原理示例源码分析

    带着问题,看源码针对性会更强一点.印象会更深刻.并且效果也会更好.所以我先卖个关子,提两个问题(没准下次跳槽时就被问到). 我们可以用ByteBuffer的allocateDirect方法,申请一块堆外内存创建一个DirectByteBuffer对象,然后利用它去操作堆外内存.这些申请完的堆外内存,我们可以回收吗?可以的话是通过什么样的机制回收的? 大家应该都知道WeakHashMap可以用来实现内存相对敏感的本地缓存,为什么WeakHashMap合适这种业务场景,其内部实现会做什么特殊处理呢?

  • 深入理解框架背后的原理及源码分析

    目录 问题1 问题2 总结 近期团队中同学遇到几个问题,想在这儿跟大家分享一波,虽说不是很有难度,但是背后也折射出一些问题,值得思考. 开始之前先简单介绍一下我所在团队的技术栈,基于这个背景再展开后面将提到的几个问题,将会有更深刻的体会. 控制层基于SpringMvc,数据持久层基于JdbcTemplate自己封装了一套类MyBatis的Dao框架,视图层基于Velocity模板技术,其余组件基于SpringCloud全家桶. 问题1 某应用发布以后开始报数据库连接池不够用异常,日志如下: co

  • java并发容器CopyOnWriteArrayList实现原理及源码分析

    CopyOnWriteArrayList是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器",Java并发包中类似的容器还有CopyOnWriteSet.本文会对CopyOnWriteArrayList的实现原理及源码进行分析. 实现原理 我们都知道,集合框架中的ArrayList是非线程安全的,Vector虽是线程安全的,但由于简单粗暴的锁同步机制,

  • Java并发编程之ReentrantLock实现原理及源码剖析

    目录 一.ReentrantLock简介 二.ReentrantLock使用 三.ReentrantLock源码分析 1.非公平锁源码分析 2.公平锁源码分析 前面<Java并发编程之JUC并发核心AQS同步队列原理剖析>介绍了AQS的同步等待队列的实现原理及源码分析,这节我们将介绍一下基于AQS实现的ReentranLock的应用.特性.实现原理及源码分析. 一.ReentrantLock简介 ReentrantLock位于Java的juc包里面,从JDK1.5开始出现,是基于AQS同步队列

  • 深入解析spring AOP原理及源码

    目录 @EnableAspectJAutoProxy 找切面 代理对象的创建 代理方法的执行 ExposeInvocationInterceptor#invoke 环绕通知的执行 前置通知的执行 后置通知的执行 返回后通知的执行 异常通知的执行 @EnableAspectJAutoProxy @EnableAspectJAutoProxy注解用于开启AOP功能,那么这个注解底层到底做了什么呢? 查看@EnableAspectJAutoProxy的源码,发现它使用@Import注解向Spring容

  • SpringCloud Gateway加载断言predicates与过滤器filters的源码分析

    我们今天的主角是Gateway网关,一听名字就知道它基本的任务就是去分发路由.根据不同的指定名称去请求各个服务,下面是Gateway官方的解释: https://spring.io/projects/spring-cloud-gateway,其他的博主就不多说了,大家多去官网看看,只有官方的才是最正确的,回归主题,我们的过滤器与断言如何加载进来的,并且是如何进行对请求进行过滤的. 大家如果对SpringBoot自动加载的熟悉的话,一定知道要看一个代码的源码,要找到META-INF下的spring

  • springBoot2.6.2自动装配之注解源码解析

    目录 前言 一.@SpringBootConfiguration 二.@ComponentScan 三.@EnableAutoConfiguration 3.1@AutoConfigurationPackage 3.2 @import 四.按需装配 前言 自动装配的核心即@SpringBootApplication注解中三大注解核心 @SpringBootApplication @SpringBootConfiguration @ComponentScan @EnableAutoConfigur

随机推荐