springboot---四大核心

Starter

简介

springboot项目中几乎项目依赖中基本上全是各种各样的starter, 那么到底什么是starter?

starter是一组方便的依赖描述符,当我们使用它时,可以获得所有需要的Spring和相关技术的一站式服务,典型的如spring-boot-starter-web,引入之后,自动引入所有有关spring web项目相关的依赖。

  • 官方提供的 starter 命名:spring-boot-starter-xxx

            <!--监控依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
    
            <!-- 如果开启了Actuator默认不开放的endpoints,建议一定要加上Spring Security用于endpoint保护,避免重要信息泄露,必须防止未经授权的外部访问。 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
    
  • 非官方的 starter 命名:xxx-spring-boot-starter

            <!-- druid连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${
         druid.version}</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
                <version>3.5.2</version>
            </dependency>
    
  • 其中的 xxx 就是我们想要依赖的组件或者 jar 包。引入之后通过简单的约定配置就可以正常使用。

  • Starter 帮我们封装好了所有需要的依赖,避免我们自己添加导致的一些Jar包冲突或者缺少包的情况。

总结

starter的存在让我们大大简化了项目的开发准备工作,开箱即用。有些starter 包的内容就是 pom 文件,就是一个依赖传递包;而有些Starter还帮我们自动注入了需要的 Bean 实例到 Spring 容器中,不需要我们手动配置。

Autoconfigure

简介

autoconfigure 在我们的开发中并不会被感知,因为它是存在与我们的 starter 中的。所以我们的每个 starter 都是依赖 autoconfigure 的

autoconfigure 内容是配置 Bean 实例到 Spring 容器的实际代码实现包,然后提供给 starter 依赖。所以说配置 Bean 实例到Spring容器中实际是 autoconfigure 做的,因为是 starter 依赖它,所以也可以说是 starter 干的。

所以:autocinfigure 是 starter 体现出来的能力的代码实现

示例

我相信,只要你用过Spring Boot,就会对这样一个现象非常的好奇:

引入一个组件依赖,加个配置,这个组件就生效了。

举个例子来说,比如我们常用的Redis, 在Spring Boot中的使用方式是这样的:

  1. 引入依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
  2. 编写配置

    spring:
      redis:
        database: 0
        timeout: 5000ms
        host: 127.0.0.1
        port: 6379
        password: 123456
    
  3. 直接使用

    @Autowired
    private RedisTemplate redisTemplate;
    

这期间,我们做了什么嘛?我们什么也没有做,那么,这个RedisTemplate对象是怎么注入到Spring容器中的呢?

原理

记得刚开始学自动装配的时候,有两个注解用的很爽,分别是@Autowired和@Resource。当时还记得@Autowired默认装配是byType,可以通过@Qualifile为byName,@Resource默认装配是byName,找不到自动byType。然后还记得,加了@Component注解或其衍生注解之后就能装配了。那么,一个Bean是如何被加载到容器中的?

首先是看一个项目的启动类
在这里插入图片描述

分析这些注解,应该秘密就藏在@SpringBootApplication注解了
在这里插入图片描述
我们点进去源码可以发现,@SpringBootApplication是一个组合注解,其中上面那三个是属于Java提供的元注解,@Inherited是指可继承的(如果@SpringBootApplication注解作用于类A上,然后B继承了A,那么B也具有该注解的功能)。重要的注解是下面这三个@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。

@SpringBootConfiguration
在这里插入图片描述看似很高大上的@SpringBootConfiguration注解,点进去一看,其实他就是继承了@Configuration,说白了,他就是一个配置注解,作用的话,就是表明某个类是一个配置类。

@ComponentScan

在这里插入图片描述这个注解默认会扫描该类所在的包下所有被@Component注解或其衍生注解所标注的类。

@EnableAutoConfiguration
在这里插入图片描述他是自动装配的总开关,意思是开启自动装配。

点进去可以看到有一个没见过的注解@AutoConfigurationPackage,这是什么作用呢?从名字中大致能看出,自动配置包,差不多吧,他的意思就是添加该注解的类所在的包作为 自动配置包进行管理,不太明白?点进去!
在这里插入图片描述

点进去,我们发现,里面有一个@Import({Registrar.class})
在这里插入图片描述

继续点进去,终于看到代码了,大致可以看出来,这是用来注册bean的,这里我们着重看一下registerBeanDefinitions方法,方法里有一个参数是BeanDefinitionRegistry registry,听名字就有那味了,重点来了,这里通过一个构造方法进行设置了packageNamenew PackageImports(metadata).getPackageNames(),接下来我要做什么,想必大家都知道了,点进去这个构造方法。
在这里插入图片描述

到这里终于把包名给set上了,接下来我们可以看看register方法了,温馨提示:刚刚是从register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));的构造方法点进来的(贵人多忘事嘛)。
在这里插入图片描述
这里会走else,这个方法呢,就完成了该包下的bean注入到容器中。

看完了@AutoConfigurationPackage注解,接下来看看这个@Import(AutoConfigurationImportSelector.class),这个是导入自动装配的ImportSelector类。 AutoConfigurationImportSelector
在这里插入图片描述

可以看到他实现了DeferredImportSelector接口
在这里插入图片描述

继续点,可以看到,他继承了ImportSelector接口。
在这里插入图片描述

在ImportSelector中有一个方法,是selectImports方法
在这里插入图片描述

可以清楚的看到,AutoConfigurationImportSelector实现了该方法
在这里插入图片描述

在这里首先是判断了自动装配的开关
在这里插入图片描述

然后获取需要装配的bean
在这里插入图片描述

其中这里的getCandidateConfigurations方法是读取META-INF/spring.factories
在这里插入图片描述

在AutoConfigurationImportSelector下,还有一个重要的静态内部类,该静态内部类的构造器中初始化读取META-INF/spring-autoconfigure-metadata.properties。
在这里插入图片描述

重点是两个配置类
在这里插入图片描述

点进去spring-autoconfigure-metadata.properties,里面是自动装配的一些元数据。
在这里插入图片描述

点进去spring.factories在这里插入图片描述

点进去一个可以发现,里面都是写好的bean,就等被加载呢!
在这里插入图片描述

只要我们按照约定来写spring.factories,那么我们也可以自己定义starter,把我们的bean封装到一个配置类中!

自定义starter

打包

首先需要深思一下什么是打包,现在项目都是分工合作,写好代码运维人员直接从git拉取项目部署,都快忘记了什么是打包。

打包的目的有两种:启动和引入,不同的目的打出来的包截然不同,并且是由maven自己判断的。

maven是怎么判断的:检测项目中是否存在启动类。

  • 没有启动类的项目打出来的包:
    在这里插入图片描述
    在这里插入图片描述
    打包时pom文件中的jar不会下载

  • 存在启动类时打出来的包
    在这里插入图片描述
    在这里插入图片描述
    打包时pom文件中的jar会下载

基于上面的示例可以发现spring项目有无启动类时打出来的包会有很大的差别。其实也好理解,存在启动类的项目,打包自然是为了运行;而没有启动类的包,打包自然是为了被引用。

实践

  1. 创建一个普通的springboot项目,可以命名为demo-spring-boot-starter
  2. 创建好之后,把启动类和test文件夹删掉,因为存在启动类和test文件夹打包出来的项目无法被依赖
  3. 创建需要自动装配的bean
  4. 将bean自动装配
  5. 将这个项目打包到我们本地的maven仓库
  6. 主项目像引入其他依赖一样引入该依赖就可以了
  7. 自定义starter中的bean就可以直接通过自动装配创建对象。

最终形成如下目录:
在这里插入图片描述

  • SpringTest
    package com.lkw.java.demo3.service;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @Description TODO()
     * @Authon lkw
     * @Date 2024/1/30 17:22
     * @Version 1.0
     **/
    
    @Configuration
    public class SpringTest {
         
    
        public String test(){
         
            System.out.println("demo3");
            return "demo3";
        }
    
        @Bean
        public SpringTest springTest(){
         
            return new SpringTest();
        }
    }
    
  • spring.factories
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.lkw.java.demo3.service.SpringTest
    
  • pom.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.6.1</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.lkw.java</groupId>
        <artifactId>demo3</artifactId>
        <version>0.0.1</version>
        <name>demo3</name>
        <description>starter project for Spring Boot</description>
        <properties>
            <java.version>8</java.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
    
            <!--表示两个项目之间依赖不传递;不设置optional或者optional是false,表示传递依赖-->
            <!--例如:project1依赖a.jar(optional=true),project2依赖project1,则project2不依赖a.jar-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-autoconfigure</artifactId>
            </dependency>
        </dependencies>
    
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                    </plugin>
                </plugins>
            </pluginManagement>
    
        </build>
    
    </project>
    

总结

  • 自动装配的实现原理核心是SPI机制。SPI ,全称为 Service Provider Interface(服务提供者接口),是一种服务发现机制。它通过在classpath路径下的META-INF/services文件夹查找文件,自动加载文件中所定义的类。

  • 并不是每个spring-boot-starter-x中都有注入文件。所有spring-boot-starter-x的组件配置都是放在spring-boot-autoconfigura的组件中的

  • 自动装配简述:项目启动时,Spring通过@Import注解导入了AutoConfigurationImportSelector, 然后调用该类selectImports时,从classpath下的META-INF/spring.factories文件中读取key为EnableAutoConfiguration的配置类,然后Spring便会将这些类加载到Spring的容器中,变成一个个的Bean。

CLI

Spring Boot CLI 是一个命令行使用 Spring Boot 的客户端工具;主要功能如下:

  • 运行 groovy 脚本
  • 打包 groovy 文件到 jar
  • 初始化 Spring Boot 项目
  • 其他详见官网:https://docs.spring.io/spring-boot/docs/current/reference/html/cli.html

Actuator

actuator 是 Spring Boot 的监控插件,本身提供了很多接口可以获取当前项目的各项运行状态指标。

  1. 添加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  2. 配置需要开启监控的端点

    management:
      endpoint:
        health: ## 开启健康监控端点
          enabled: true
        beans: ## 开启Bean实例监控端点
          enabled: true
    

    重要端点:

    • health端点:端点会聚合你程序的健康指标,来检查程序的健康情况,端点有很多自动配置的健康指示器:如 redis、rabbitmq、db 等组件。

    • metrics端点:用来返回当前应用的各类重要度量指标,比如:内存信息、线程信息、垃圾回收信息、tomcat、数据库连接池等。

    • loggers端点:暴露了我们程序内部配置的所有 logger 的信息,能够动态修改你的日志等级;只需要发起一个 URL 为http://localhost:8080/actuator/loggers/root的POST请求,POST 报文如下:

      {
               
         "configuredLevel": "DEBUG"  
      }
      
    • info端点:可以用来展示你程序的信息。我理解过来就是一些程序的基础信息。并且你可以按照自己的需求在配置文件application.properties中个性化配置(默认情况下,该端点只会返回一个空的 json 内容。)

    • beans端点:会返回 Spring 容器中所有 bean 的别名、类型、是否单例、依赖等信息

    • heapdump端点:会自动生成一个 Jvm 的堆文件 heapdump。我们可以使用 JDK 自带的 Jvm 监控工具 VisualVM 打开此文件查看内存快照。

    • threaddump端点:主要展示了线程名、线程 ID、线程的状态、是否等待锁资源、线程堆栈等信息。方便我们在日常定位问题的时候查看线程的情况。

    • shutdown端点:属于操作控制类端点,可以优雅关闭 Spring Boot 应用。要使用这个功能首先需要在配置文件中开启:management.endpoint.shutdown.enabled=true

  3. 启动服务并验证

  4. 查看各个监控信息

相关推荐

  1. 业务架构的核心元素

    2024-02-01 12:44:02       11 阅读
  2. springBoot核心

    2024-02-01 12:44:02       7 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-01 12:44:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-01 12:44:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-01 12:44:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-01 12:44:02       20 阅读

热门阅读

  1. Spring Boot(番外):防止反编译之Jar包加密

    2024-02-01 12:44:02       43 阅读
  2. 什么是http状态码?

    2024-02-01 12:44:02       33 阅读
  3. 垃圾回收机制

    2024-02-01 12:44:02       33 阅读
  4. PTA-C语言-找完数(附解析)

    2024-02-01 12:44:02       30 阅读
  5. 每日OJ题_算法_前缀和⑧_力扣1314. 矩阵区域和

    2024-02-01 12:44:02       39 阅读
  6. 原生js创建节点

    2024-02-01 12:44:02       35 阅读
  7. python 中我对类与函数的理解

    2024-02-01 12:44:02       30 阅读
  8. ios app与H5页面交互踩坑

    2024-02-01 12:44:02       27 阅读
  9. 最佳解决Css一隐藏滚动条

    2024-02-01 12:44:02       34 阅读