拿下SpringBoot核心功能

参考范围:《学透spring》、几个视频、其他自己百度的零碎知识。

核心功能主要有三点:

起步依赖、自动配置、Spring Boot Actuator。

目录

一,介绍

1、 起步依赖

2、 自动配置

3、Spring Boot Actuator

二,详解

1、起步依赖

1.1 SpringBoot内置的起步依赖

1.2 起步依赖的实现原理

2、自动配置

2.1 加载配置类的流程

2.2 加载自动配置类的流程

2.3 加载配置类的原理

2.3.1 SpringFactories机制:

2.3.2 @Conditional

2.4 SpringBoot配置项加载机制

2.4.1 SpringBoot属性优先级

2.4.2 SpringBoot的配置文件

3、Spring Boot Actuator


一,介绍

1、 起步依赖

起步依赖的目的是解决依赖管理问题:针对一个功能,需要引入那些依赖、它们的版本又是什么、互相之间是否存在冲突、它们的间接依赖项之间是否存在冲突。。。现在我们可以把这些麻烦都交给SpringBoot的起步依赖来解决。

就以web项目的helloworld为例,我们只需在Maven的POM文件中引入org.springframework.boot:spring-boot-starter-web 这个依赖,springboot就知道我们的项目需要Web这个功能,它实际上为我们引入了大量相关的依赖项。通过mvn dependency:tree可以查看Maven的依赖信息,里面就有spring-boot-starter、spring-boot-starter-json、spring-boot-starter-tomcat、spring-web、spring-webmvc这几个jar包,以及它们下面附带的其他jar包(略)。

可以看到,起步依赖是以功能为单位来组织依赖的。要实现某个功能,一共需要哪些依赖,我们自己不清楚,但SpringBoot知道。

2、 自动配置

没有使用SpringBoot时,我们需要配置DispatcherServlet来处理请求,需要配置jackson JSON来处理JSON的序列化,需要配置Log4j2或者Logback来打印日志。。。而SpringBoot自己可以完成所有的配置,我们只需要编写REST接口的逻辑就好了。

这就是SpringBoot的自动配置,它能根据CLASSPATH中存在的类判断出引入了哪些依赖,并为这些依赖提供常规的默认配置,以此来消除模板化的配置。与此同时,SpringBoot仍然给我们留下了很大的自由度,可以对配置进行各种定制,甚至能够排除自动配置。

3、Spring Boot Actuator

如果说前两项的目的是简化Spring项目的开发,那Spring Boot Actuator的目的则是提供一系列在生产环境运行时所需的特性,帮助大家监控并管理应用程序。通过HTTP端点或者JMX,Spring Boot Actuator可以实现健康检查、度量收集、审计、配置管理等功能。

二,详解

1、起步依赖

1.1 SpringBoot内置的起步依赖

SpringBoot官方的起步依赖都遵循一样的命名规范,都以spring-boot-starter-开头,其他第三方的起步依赖都应该避免使用这个前缀。比如MyBatis的mybatis-spring-boot-starter、Druid的druid-spring-boot-starter。

SpringBoot内置了超过50个不同的起步依赖,如果我们想要升级某些依赖,比如指定Jackson的版本,可以像下面这样:

<properties>
    <jackson-bom.version>2.11.0</jackson-bom.version>
</properties>

另外排除依赖示例(用Log4j2代替Logback):

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
</dependencies>

1.2 起步依赖的实现原理

起步依赖背后使用的其实就是Maven的传递依赖机制:假设B依赖于C,而A又依赖于B,那么A无需明确声明对C的依赖,而是通过B依赖于C。因此看似只添加了一个依赖,但实际上通过传递依赖,我们已经引入了一堆的依赖。

2、自动配置

查看@SpringBootApplication注解,里面包含了三个注解:

  • @Configuration:用于定义一个配置类;
  • @EnableAutoConfiguration:开启自动配置,它和@SpringBootApplication都有exclude属性,可以排除一些不想启用的自动配置类。
    • 示例:一般会采用这种设置:@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})。其中DataSourceAutoConfiguration.class,是取消自动配置数据源,因为DataSourceAutoConfiguration.class 会自动查找 application.yml 或者 properties 文件里的 spring.datasource.* 相关属性并自动配置单数据源,如果项目使用的是多数据源,就需要排除。
  • @ComponentScan:扫描指定packages,找到符合条件的类,默认是搜索被@Component修饰的配置类,通过属性basePackages来指定要进行扫描的package,如果未指定package,则默认扫描当前@ComponentScan所修饰的类所在的package。

2.1 加载配置类的流程

1、处理@ComponentScan,递归扫描指定的package,得到一系列配置类。

2、处理注解@Import,递归扫描,根据此注解得到一系列被导入的配置类。

3、处理@Bean方法

4、处理@Import导入的ImportBeanDefinitionRegistrar注册器。

5、加入到一个全局的配置类集合中。

6、注入到IOC容器

加载配置类主要就在于@ComponentScan和@Import。

@ComponentScan在上面已经解释过;@Import是来自Spring框架的一个注解,它的作用是提供了一种显式地从其他地方加载配置类的方式,这样可以避免使用性能较差的组件扫描(ComponentScan)。

@Import支持3种导入的方式:

1、导入普通类

2、导入选择器ImportSelector

3、导入注册器ImportBeanDefinitionRegistrar

示例:

1、导入普通类

public class ConfigA {
    @Bean
    public A a() {
        return new A();
    }
}

public class A {
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
}

通过上述代码,两个类都会注入到IOC容器中。

2、导入选择器ImportSelector

public class ConfigA {
    @Bean
    public A a() {
        return new A();
    }
}

public class A {
}
public class TestImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        return new String[]{"cn.test.A"};
    }
}
@Configuration
@Import(TestImportSelector.class)
public class ConfigB {
}

3、导入注册器ImportBeanDefinitionRegistrar

略。和2类似,实现了ImportBeanDefinitionRegistrar接口,只需要修改第二个类,通过填写beanName进行导入。

2.2 加载自动配置类的流程

知道上述知识后就可以进一步看:普通的配置类需要被扫描到才能生效,但自动配置类并不在我们项目的扫描路径中,它们是怎么被加载上来的呢?

答案就在于@EnableAutoConfiguration上的@Import(AutoConfigurationImportSelector.class),类AutoConfigurationImportSelector是ImportSelector的实现,这个接口的作用是根据特定条件决定可以导入哪些配置类,接口中的selectImports()方法返回的就是可以导入的配置类名。

AutoConfigurationImportSelector通过SpringFactoriesLoader来加载/META-INF/spring.factories里配置的自动配置类列表。(从Spring Boot 2.7开始,AutoConfigurationImportSelector不再从/META-INF/spring.factories加载自动配置类,而是开始使用新的/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,直接在里面添加自动配置类的全限定类名即可。)所用的键是org.springframework.boot.autoconfigure.EnableAutoConfiguration,值是以逗号分割的自动配置类全限定类名(包含了完整包名与类名)清单。

所以,只要在类上加上@SpringBootApplication或@EnableAutoConfiguration后,SpringBoot就会自动加载所有的自动配置类。

总结:@SpringBootApplication可以从三个方面加载配置类:

1、被@SpringBootApplication修饰的类,因为会被@Configuration间接修饰,会成为原配置类。

2、SpringBoot框架会对原配置类所在的package进行组件扫描——默认;以及显式地增加@ComponentScan对其他package进行扫描。

3、SpringBoot框架会导入AutoConfigurationImportSelector来实现自动配置。

2.3 加载配置类的原理

接着2.2往下说,自动配置的实现原理是基于SpringFactories机制,用AutoConfigurationImportSelector找出所有的自动配置类,再根据注解@Conditional条件注解来配置的。

2.3.1 SpringFactories机制:

1、使用约定的配置文件,SpringFactories用的是spring.factories(2.7版本后是 org.springframework.boot.autoconfigure.AutoConfiguration.imports)文件,文件内容是"key=value1,value2,....valueN"的格式,其中key是指定的某个类名,value是逗号隔开的多个类名。

2、使用ClassLoader的getResources来读取配置文件。

3、通过类SpringFactoriesLoader,返回一个类名的集合,根据实际需求对这些类名进行下一步的处理。

自动配置的写法举例:

org.springframework.boot.autoconfigure.EnableAutoConfiguration = learning.test.TestConfiguration

如果制造一个无法通过ComponentScan自动扫描到 learning.test.TestConfiguration 这个类的情况,SpringBoot就会根据spring.factories文件来扫描到TestConfiguration类。

2.3.2 @Conditional

@Conditional:Spring 4.0加入的条件注解,根据特定条件启用相关配置类,即满足特定条件时,才会向IOC容器注册指定的组件,注解中传入的Condition类就是不同条件的判断逻辑。SpringBoot内置了很多条件注解,下面列举org.springframework.boot.autoconfigure.condition包中的一些条件注解:

@ConditionalOnBean:存在特定名称、特定类型、特定泛型参数或带有特定注解的Bean。

@ConditionalOnMissingBean:与前者相反,不存在特定Bean。

@ConditionalOnClass:当classpath中存在特定的类。

@ConditionalOnMissingClass:与前者相反,不存在特定的类。

@ConditionalOnWebApplication:当应用是一个Web应用程序。

@ConditionalOnNotWebApplication:与前者相反,当应用不是一个Web应用程序。

注意:如果有多个上述条件注解,它们之间是and关系。

以spring-boot-starter-data-redis为例,他依赖了spring-boot-starter和spring-data-redis。后者是redis的工具类库,其中定义了RedisTemplate、StringRedisTemplate等常用的类;前者依赖了spring-boot-autoconfigure,是自动配置的jar包,查看项目的配置文件及源码,可以看到存在key为EnableAutoConfiguration的一系列自动配置类,其中与redis相关的有3个——RedisAutoConfiguration、RedisReactiveAutoConfiguration、RedisRepositoriesAutoConfiguration,再查看其中的RedisAutoConfiguration类源码,可以看到类上面标注了@Configuration(proxyBeanMethods = false)、@ConditionalOnClass(RedisOperations.class)、@EnableConfigurationProperties(RedisProperties.class)、@Import({..., ...})。也就是这个配置类的生效条件是存在RedisOperations类,就可以注册这个配置类了。

2.4 SpringBoot配置项加载机制

如果自动配置的东西不满足我们的需要,我们可以自己动手进行配置。

2.4.1 SpringBoot属性优先级

SpringBoot有18种方式来加载属性,且存在覆盖关系,它们之间有优先级,在此暂不详细列举。

2.4.2 SpringBoot的配置文件

默认以application作为主文件名,文件格式可以是.properties、.yml,这两个格式的编写样式不同,但加载机制是相同的,如果同时存在这两个文件,后者的属性优先级更高。SpringBoot会按照如下优先级加载属性:

1、打包后的Jar包以外的application-{profile}.properties;

2、打包后的Jar包以外的application.properties;

3、Jar包内部的application-{profile}.properties;

4、Jar包内部的application.properties;

在SpringBoot 2.4.0之前,上述第2和第3个文件的优先级顺序是反的。

SpringBoot会在如下几处位置寻找application.properties文件,并将其中的内容添加到Spring的Environment中,按优先级排序:

1、当前目录的/config子目录

2、当前目录;

3、CLASSPATH中的/config目录

4、CLASSPATH根目录

3、Spring Boot Actuator

还没学到

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值