带你一行一行分析SpringBoot原码解析

摘要:
1、 注1。此源代码分析基于2.3.3。发布版本2。本文主要分析Spring的自动配置2。源代码分析1。创建一个常见的spring-boot项目,如下所示:只有一个配置文件和一个启动类。您可以点击查看,如下所示:实际上,@Configuration和@SpringBootConfiguration具有相同的功能@Target@Retention @ Documented@Configurationpublic@InterfaceSpringBootConfiguration{@AliasForooleanproxyBeanMethods()defaulttrue;}@ComponentScan也比较复杂,如下图所示:这就是为什么所有代码都应该放在启动类的包和子包中的原因。

一.说明

 1.本次源码解析是基于2.3.3.RELEASE版本的

 2.本文主要分析Spring的自动配置

二.原码分析

1.创建一个普通的springboot项目如下:

带你一行一行分析SpringBoot原码解析第1张

 只有一个配置文件和一个启动类。

带你一行一行分析SpringBoot原码解析第2张

配置文件中只配了一个redis,配置其他组件都行,这里以redis为例展开说明自动注入。

2.打开启动类

对于springboot来说,最强大的地方就是没有复杂的配置文件,创建springboot后只有一个启动类,那就从启动类入手,Ctrl + 左键 点击

@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 {

  可以看到,

@SpringBootApplication注解上面又有七个注解,其实,这种包含了很多注解的注解就是组合注解。前四个是元注解(在JDK 1.5中提供了4个标准的用来对注解类型进行注解的注解类,我们称之为 meta-annotation(元注解)),我们先分析前四个注解:

  • @Target : 描述注解的使用范围,括号里有个ElementType.TYPE,点进去,如下:

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

Target注解用来说明那些被它所注解的注解类可修饰的对象范围:注解可以用于修饰 packages、types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数),在定义注解类时使用了@Target 能够更加清晰的知道它能够被用来修饰哪些对象,它的取值范围定义在ElementType 枚举中。

  • @Retention 同理,点击去 RetentionPolicy类,它的主要作用是:用来限定那些被它所注解的注解类在注解到其他类上以后,可被保留到何时,一共有三种策略,定义在RetentionPolicy枚举中。

    public enum RetentionPolicy {
     
        SOURCE,    // 源文件保留
        CLASS,       // 编译期保留,默认值
        RUNTIME   // 运行期保留,可通过反射去获取注解信息
  •  @Documented ,它的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息
  • @Inherited,这是个比较重要的注解,它表示注解会被子类自动继承。

接下来就剩三个注解了,其中@EnableAutoConfiguration是最核心的注解,我们放到最后面说,先说其他两个注解:

  •     @SpringBootConfiguration : 它的作用就是:继承自@Configuration,二者功能也一致,标注当前类是配置类, 并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。可以点击去看下,如下:其实,@Configuration和 @SpringBootConfiguration 是具有相同功能的。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
  • @ComponentScan,也是比较复杂的,点进去,如下图:带你一行一行分析SpringBoot原码解析第3张

  这也就是为什么,所有的代码都要放在启动类所在的包及子包里面。

接下来就是最重要的注解了,@EnableAutoConfiguration ,先点进去,如下:

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

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    /**
     * Exclude specific auto-configuration classes such that they will never be applied.
     * @return the classes to exclude
     */
    Class<?>[] exclude() default {};

    /**
     * Exclude specific auto-configuration class names such that they will never be
     * applied.
     * @return the class names to exclude
     * @since 1.3.0
     */
    String[] excludeName() default {};

}

  前四个注解就不说了,

    @AutoConfigurationPackage的作用是导入自定义的类的,

    @Import(AutoConfigurationImportSelector.class)是导入框架本身的一些类的

  在这里,这两个注解仅仅是找到需要导入的类,并没有实例化,实例化依然需要spring容器去做。

先看@AutoConfigurationPackage,点进去,如下图:

带你一行一行分析SpringBoot原码解析第4张

 有个Registrar,点进去,如下图:

带你一行一行分析SpringBoot原码解析第5张

 从方法名可以看出是个注册的方法,打上断点,启动,当代码停住后,Alt + F8,查看new PackageImports(metadata).getPackageNames().toArray(new String[0])的值,如下图:

带你一行一行分析SpringBoot原码解析第6张

 从上图可以看出,这个方法其实就是就是把自定义包下的类扫描并注册到容器中。

再看@Import(AutoConfigurationImportSelector.class),它是注入框架本身使用的和自动配置相关的类,点击去,找到getCandidateConfigurations方法。

带你一行一行分析SpringBoot原码解析第7张

 注释的意思的是;找到可能的自动配置的类名,进入loadFactoryNames方法,

带你一行一行分析SpringBoot原码解析第8张

 继续进入loadSpringFactories,

带你一行一行分析SpringBoot原码解析第9张

 图中有个FACTORIES_RESOURCE_LOCATION,点进去,

带你一行一行分析SpringBoot原码解析第10张

 原来是一个文件,也就是说,springboot框架本省要导入的类就在这个文件中,那么这个spring.factories在哪呢?

接下来打开pom文件,找到spring-boot-starter-web,点进去,

带你一行一行分析SpringBoot原码解析第11张

 找到spring-boot-starter,点进去

带你一行一行分析SpringBoot原码解析第12张

 就能发现有一个spring-boot-autoconfigure,表示自动配置,如图。

带你一行一行分析SpringBoot原码解析第13张

打开pom文件引入的包,在工程窗口,如下图:

带你一行一行分析SpringBoot原码解析第14张

 找到:spring-boot-autoconfigure,如下图:

带你一行一行分析SpringBoot原码解析第15张

 发现有一个spring.properties文件,打开:

带你一行一行分析SpringBoot原码解析第16张

 发现,类似于redis这种组件所对应的类就在这个文件中。

到此为止,springboot只是将可能用到的类加载进来了,但是仅仅知识加载了类名,怎么能根据我们在yml文件中的配置来使用呢?也就是说,springboot怎么能知道我们要使用哪些类,不使用哪些类呢,比如我们现在要是用redis,首先我们需要在yml文件中配置redis的连接信息,如下图:

带你一行一行分析SpringBoot原码解析第17张

 想到这里,我们就应该想到,springboo肯定是通过加载这个yml文件开读取的,接下来跟原码:

打开启动类,进入run方法,只要是run方法,就一直往下走,直到org.springframework.context.ConfigurableApplicationContext这个方法,如下图:

带你一行一行分析SpringBoot原码解析第18张

 进入:prepareEnvironment方法这个方法表示环境的准备,如下图;

带你一行一行分析SpringBoot原码解析第19张

 进入environmentPrepared,表示添加监听:

带你一行一行分析SpringBoot原码解析第20张

 进入environmentPrepared方法,表示初始化:继续往下走,方法顺序为

multicastEvent->

multicastEvent->

multicastEvent->

invokeListener(listener, event))->

doInvokeListener——>如图:

带你一行一行分析SpringBoot原码解析第21张

 进入onApplicationEvent接口的配置文件实现类  ConfigFileApplicationListener

带你一行一行分析SpringBoot原码解析第22张

 进入实现方法:

带你一行一行分析SpringBoot原码解析第23张

 再按下顺序往下走:

onApplicationEnvironmentPreparedEvent ->

postProcessEnvironment->如图:

再进入postProcessEnvironment的实现类:ConfigFileApplicationListener

带你一行一行分析SpringBoot原码解析第24张

 实现方法如下:

带你一行一行分析SpringBoot原码解析第25张

 再进入addPropertySources方法:

带你一行一行分析SpringBoot原码解析第26张

 在进入load方法:

带你一行一行分析SpringBoot原码解析第27张

 再进入load方法:

带你一行一行分析SpringBoot原码解析第28张

 再进入load方法:

带你一行一行分析SpringBoot原码解析第29张

 点击getFileExtensions()进入接口,

带你一行一行分析SpringBoot原码解析第30张

 这个接口有两个实现类,分别是properties和yml,太熟悉了,这不就是配置文件吗,这个接口其实就是配置文件的扩展名,

重新进入load方法:

带你一行一行分析SpringBoot原码解析第31张

 进入loadForFileExtension方法:

 带你一行一行分析SpringBoot原码解析第32张

 再进入load方法:

带你一行一行分析SpringBoot原码解析第33张

 再进入loadDocuments方法:

带你一行一行分析SpringBoot原码解析第34张

 再进入load接口方法:

带你一行一行分析SpringBoot原码解析第35张

 发现又有两个实现类,进入yml的实现类:

带你一行一行分析SpringBoot原码解析第36张

 ····················终于完了,这是最后一个方法了,在犯法最后一行打上断点:启动:

带你一行一行分析SpringBoot原码解析第37张

 把配置文件中的所有信息都加载进来了。

但是。。。,这也只是把配置文件加载进来了,那么redis怎么起作用呢?

打开前面说的spring.properties文件找到  RedisAutoConfiguration类,进入这个类,如下

带你一行一行分析SpringBoot原码解析第38张

 要使redis起作用,图中的四个注解不可少,进入注解括号中的RedisProperties类:

带你一行一行分析SpringBoot原码解析第39张

 发现,又是熟悉的感觉,这不就对饮配置文件中的属性吗?

再看RedisTemplate<Object, Object> template = new RedisTemplate<>(); 这行代码,直接就new了一个对象,这就是创建了一个RedisTemplate,因此,我们就可以使用RedisTemplate来操作redis了。

所以springboot,也就是通过这种方式进行类的自动装配的。

免责声明:文章转载自《带你一行一行分析SpringBoot原码解析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇纯前端版本号策略url、 src 和href 标签的区别下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

spring 4 @RestController 小试

在建立好基本的spring框架后,可以尝试实现一下简单的rest风格请求 1、需要引入的包,部分pom.xml文件 <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-...

一步步学习SpringBoot(一) 快速搭建一个web

适应读者 前端工程师(java系的公司) 前端架构师(java系的公司) java工程师 测试工程师(java系的公司) 什么是SpringBoot? Spring Boot便是一个社区反馈推动的项目. Spring Boot可以说是至少近5年来Spring乃至整个Java社区最有影响力的项目之一。Spring Boot主要包含以下特性:直接嵌入Tom...

SpringBoot入门 (三) 日志配置

上一篇博文记录了再springboot项目中读取属性文件中配置的属性,本文学习在springboot项目中记录日志。   日志记录在项目中是很常见的一个功能了,对排查问题有很大帮助,也可以做分类分析及统计。SpringBoot内部使用的是Commons Logging做日志的记录,但是对其他的日志框架也提供了默认的配置,如:Java util Loggin...

Spring知识点整理---(IOC,DI)

1.Spring的基本应用 1.1Spring概述 1.1.1什么是Spring Spring是由Rod Johnson组织和开发的一个分层的Java SE/EE full-stack(一站式)轻量级开源框架,它以IoC(Inversion of Control,控制反转)和 AOP(Aspect OrientedProgramming,面向切面编程)为内...

基础概念总结(spring security、Quartz、JUnit测试)

1、Spring Security 的大体框架和原理 (1)在web.xml中配置过滤器,这样就可以控制这个项目的每个请求。 (2)在applicationContext.xml配置,其中http标签配置如何截用户请求,和配置用户认证(固定用户、使用数据库管理用户)。 (3)过滤器最上层为HttpSessionContextIntegrationFilt...

spring cloud fegin 原理解析

一、 SpringCloud 中 Feign 核心原理 如果不了解 SpringCloud 中 Feign 核心原理,不会真正的了解 SpringCloud 的性能优化和配置优化,也就不可能做到真正掌握 SpringCloud。 本章从Feign 远程调用的重要组件开始,图文并茂的介绍 Feigh 远程调用的执行流程、Feign 本地 JDK Proxy...