跨境互联网 跨境互联网
首页
  • AI 工具

    • 绘图提示词工具 (opens new window)
    • ChatGPT 指令 (opens new window)
  • ChatGPT

    • ChatGP T介绍
    • ChatGPT API 中文开发手册
    • ChatGPT 中文调教指南
    • ChatGPT 开源项目
  • Midjourney

    • Midjourney 文档
  • Stable Diffusion

    • Stable Diffusion 文档
  • 其他

    • AIGC 热门文章
    • 账号合租 (opens new window)
    • 有趣的网站
  • Vue

    • Vue3前置
  • JAVA基础

    • Stream
    • Git
    • Maven
    • 常用第三方类库
    • 性能调优工具
    • UML系统建模
    • 领域驱动设计
    • 敏捷开发
    • Java 测试
    • 代码规范及工具
    • Groovy 编程
  • 并发编程&多线程

    • 并发编程
    • 高性能队列 Disruptor
    • 多线程并发在电商系统下的应用
  • 其他

    • 面试题
  • 消息中间中间件

    • Kafka
    • RabbitMQ
    • RocketMQ
  • 任务调度

    • Quartz
    • XXL-Job
    • Elastic-Job
  • 源码解析

    • Mybatis 高级使用
    • Mybatis 源码剖析
    • Mybatis-Plus
    • Spring Data JPA
    • Spring 高级使用
    • Spring 源码剖析
    • SpringBoot 高级使用
    • SpringBoot 源码剖析
    • Jdk 解析
    • Tomcat 架构设计&源码剖析
    • Tomcat Web应用服务器
    • Zookeeper 高级
    • Netty
  • 微服务框架

    • 分布式原理
    • 分布式集群架构场景化解决方案
    • Dubbo 高级使用
    • Dubbo 核心源码剖析
    • Spring Cloud Gateway
    • Nacos 实战应用
    • Sentinel 实战应用
    • Seata 分布式事务
  • 数据结构和算法的深入应用
  • 存储

    • 图和Neo4j
    • MongoDB
    • TiDB
    • MySQL 优化
    • MySQL 平滑扩容实战
    • MySQL 海量数据存储与优化
    • Elasticsearch
  • 缓存

    • Redis
    • Aerospike
    • Guava Cache
    • Tair
  • 文件存储

    • 阿里云 OSS 云存储
    • FastDF 文件存储
  • 基础

    • Linux 使用
    • Nginx 使用与配置
    • OpenResty 使用
    • LVS+Keepalived 高可用部署
    • Jekins
  • 容器技术

    • Docker
    • K8S
    • K8S
  • 01.全链路(APM)
  • 02.电商终极搜索解决方案
  • 03.电商亿级数据库设计
  • 04.大屏实时计算
  • 05.分库分表的深入实战
  • 06.多维系统下单点登录
  • 07.多服务之间分布式事务
  • 08.业务幂等性技术架构体系
  • 09.高并发下的12306优化
  • 10.每秒100W请求的秒杀架构体系
  • 11.集中化日志管理平台的应用
  • 12.数据中台配置中心
  • 13.每天千万级订单的生成背后痛点及技术突破
  • 14.红包雨的架构设计及源码实现
  • 人工智能

    • Python 笔记
    • Python 工具库
    • 人工智能(AI) 笔记
    • 人工智能(AI) 项目笔记
  • 大数据

    • Flink流处理框架
  • 加密区

    • 机器学习(ML) (opens new window)
    • 深度学习(DL) (opens new window)
    • 自然语言处理(NLP) (opens new window)
AI 导航 (opens new window)

Revin

首页
  • AI 工具

    • 绘图提示词工具 (opens new window)
    • ChatGPT 指令 (opens new window)
  • ChatGPT

    • ChatGP T介绍
    • ChatGPT API 中文开发手册
    • ChatGPT 中文调教指南
    • ChatGPT 开源项目
  • Midjourney

    • Midjourney 文档
  • Stable Diffusion

    • Stable Diffusion 文档
  • 其他

    • AIGC 热门文章
    • 账号合租 (opens new window)
    • 有趣的网站
  • Vue

    • Vue3前置
  • JAVA基础

    • Stream
    • Git
    • Maven
    • 常用第三方类库
    • 性能调优工具
    • UML系统建模
    • 领域驱动设计
    • 敏捷开发
    • Java 测试
    • 代码规范及工具
    • Groovy 编程
  • 并发编程&多线程

    • 并发编程
    • 高性能队列 Disruptor
    • 多线程并发在电商系统下的应用
  • 其他

    • 面试题
  • 消息中间中间件

    • Kafka
    • RabbitMQ
    • RocketMQ
  • 任务调度

    • Quartz
    • XXL-Job
    • Elastic-Job
  • 源码解析

    • Mybatis 高级使用
    • Mybatis 源码剖析
    • Mybatis-Plus
    • Spring Data JPA
    • Spring 高级使用
    • Spring 源码剖析
    • SpringBoot 高级使用
    • SpringBoot 源码剖析
    • Jdk 解析
    • Tomcat 架构设计&源码剖析
    • Tomcat Web应用服务器
    • Zookeeper 高级
    • Netty
  • 微服务框架

    • 分布式原理
    • 分布式集群架构场景化解决方案
    • Dubbo 高级使用
    • Dubbo 核心源码剖析
    • Spring Cloud Gateway
    • Nacos 实战应用
    • Sentinel 实战应用
    • Seata 分布式事务
  • 数据结构和算法的深入应用
  • 存储

    • 图和Neo4j
    • MongoDB
    • TiDB
    • MySQL 优化
    • MySQL 平滑扩容实战
    • MySQL 海量数据存储与优化
    • Elasticsearch
  • 缓存

    • Redis
    • Aerospike
    • Guava Cache
    • Tair
  • 文件存储

    • 阿里云 OSS 云存储
    • FastDF 文件存储
  • 基础

    • Linux 使用
    • Nginx 使用与配置
    • OpenResty 使用
    • LVS+Keepalived 高可用部署
    • Jekins
  • 容器技术

    • Docker
    • K8S
    • K8S
  • 01.全链路(APM)
  • 02.电商终极搜索解决方案
  • 03.电商亿级数据库设计
  • 04.大屏实时计算
  • 05.分库分表的深入实战
  • 06.多维系统下单点登录
  • 07.多服务之间分布式事务
  • 08.业务幂等性技术架构体系
  • 09.高并发下的12306优化
  • 10.每秒100W请求的秒杀架构体系
  • 11.集中化日志管理平台的应用
  • 12.数据中台配置中心
  • 13.每天千万级订单的生成背后痛点及技术突破
  • 14.红包雨的架构设计及源码实现
  • 人工智能

    • Python 笔记
    • Python 工具库
    • 人工智能(AI) 笔记
    • 人工智能(AI) 项目笔记
  • 大数据

    • Flink流处理框架
  • 加密区

    • 机器学习(ML) (opens new window)
    • 深度学习(DL) (opens new window)
    • 自然语言处理(NLP) (opens new window)
AI 导航 (opens new window)
  • Spring Data JPA
  • MyBatis

  • Spring

  • SpringBoot

    • SpringBoot高级使用

    • SpringBoot源码剖析

      • 介绍
      • 源码剖析-依赖管理
      • 源码剖析-自动配置
      • 源码剖析-Run方法执行流程
      • 源码剖析-自定义Starter
        • SpringBoot starter机制
        • 自定义starter的案例
        • 自定义starter的命名规则
        • 自定义starter代码实现
          • (1)自定义starter
          • (2)使用自定义starter
        • 热插拔技术
        • 关于条件注解的讲解
      • 源码剖析-内嵌Tomcat
      • 源码剖析-自动配置SpringMVC
    • 资料
  • Jdk

  • Tomcat

  • Netty

  • 若依

  • Traefik

  • Openresty

  • 开源框架
  • SpringBoot
  • SpringBoot源码剖析
Revin
2023-06-15
目录

源码剖析-自定义Starter

# SpringBoot starter机制

SpringBoot中的starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进starter,应用者只需要在maven中引入starter依赖,SpringBoot就能自动扫描到要加载的信息并启动相应的默认配置。starter让我们摆脱了各种依赖库的处理,需要配置各种信息的困扰。SpringBoot会自动通过classpath路径下的类发现需要的Bean,并注册进IOC容器。SpringBoot提供了针对日常企业应用研发各种场景的spring-boot-starter依赖模块。所有这些依赖模块都遵循着约定成俗的默认配置,并允许我们调整这些配置,即遵循“约定大于配置”的理念。

比如我们在springboot里面要引入redis,那么我们需要在pom中引入以下内容

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
1
2
3
4

这其实就是一个starter。

简而言之,starter就是一个外部的项目,我们需要使用它的时候就可以在当前springboot项目中引入它。

为什么要自定义starter

在我们的日常开发工作中,经常会有一些独立于业务之外的配置模块,我们经常将其放到一个特定的包下,然后如果另一个工程需要复用这块功能的时候,需要将代码硬拷贝到另一个工程,重新集成一遍,麻烦至极。如果我们将这些可独立于业务代码之外的功配置模块封装成一个个starter,复用的时候只需要将其在pom中引用依赖即可,再由SpringBoot为我们完成自动装配,就非常轻松了

# 自定义starter的案例

以下案例是开发中遇到的部分场景

▲ 动态数据源。

▲ 登录模块。

▲ 基于AOP技术实现日志切面。

.........

# 自定义starter的命名规则

SpringBoot提供的starter以spring-boot-starter-xxx的方式命名的。

官方建议自定义的starter使用xxx-spring-boot-starter命名规则。以区分SpringBoot生态提供的starter

# 自定义starter代码实现

整个过程分为两部分:

  • 自定义starter
  • 使用starter

# (1)自定义starter

首先,先完成自定义starter

(1)新建maven jar工程,工程名为zdy-spring-boot-starter,导入依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
        <version>2.2.9.RELEASE</version>
    </dependency>
</dependencies>
1
2
3
4
5
6
7

(2)编写javaBean

@EnableConfigurationProperties(SimpleBean.class) 
@ConfigurationProperties(prefix = "simplebean") 
public class SimpleBean {


    private int id;
    private String name;


    public int getId() {
        return id;
    }


    public void setId(int id) {
        this.id = id;
    }


    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    @Override
    public String toString() {
        return "SimpleBean{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

(3)编写配置类MyAutoConfiguration

@Configuration
public class MyAutoConfiguration {




    static {
        System.out.println("MyAutoConfiguration init....");
    }




    @Bean
    public SimpleBean simpleBean(){
        return new SimpleBean();
    }


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

(4)resources下创建/META-INF/spring.factories

注意:META-INF是自己手动创建的目录,spring.factories也是手动创建的文件,在该文件中配置自己的自动配置类

image-20200111123116471

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.itheima.config.MyAutoConfiguration
1
2

上面这句话的意思就是SpringBoot启动的时候会去加载我们的simpleBean到IOC容器中。这其实是一种变形的SPI机制

# (2)使用自定义starter

(1)导入自定义starter的依赖

<dependency>
   <groupId>com.itheima</groupId>
   <artifactId>zdy-spring-boot-starter</artifactId>
   <version>1.0-SNAPSHOT</version>


</dependency>
1
2
3
4
5
6
7

(2)在全局配置文件中配置属性值

simplebean.id=1
simplebean.name=自定义starter
1
2

(3)编写测试方法

//测试自定义starter
@Autowired
private SimpleBean simpleBean;


@Test
public void zdyStarterTest(){
   System.out.println(simpleBean);
}
1
2
3
4
5
6
7
8
9

但此处还有一个问题,如果有一天我们不想要启动工程的时候自动装配SimpleBean呢?可能有的同学会想,那简单啊,我们去pom中把依赖注释掉,的确,这是一种方案,但为免有点Low。

# 热插拔技术

还记得我们经常会在启动类Application上面加@EnableXXX注解吗?

image.png

其实这个@Enablexxx注解就是一种热拔插技术,加了这个注解就可以启动对应的starter,当不需要对应的starter的时候只需要把这个注解注释掉就行,是不是很优雅呢?那么这是如何实现的呢?

改造zdy工程新增热插拔支持类

新增标记类ConfigMarker

public class ConfigMarker {
  
}
1
2
3

新增EnableRegisterServer注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({ConfigMarker.class})
public @interface EnableRegisterServer {
}
1
2
3
4
5

改造MyAutoConfiguration新增条件注解@ConditionalOnBean(ConfigMarker.class),@ConditionalOnBean这个是条件注解,前面的意思代表只有当期上下文中含有ConfigMarker对象,被标注的类才会被实例化。

@Configuration
@ConditionalOnBean(ConfigMarker.class)
public class MyAutoConfiguration {


    static {
        System.out.println("MyAutoConfiguration init....");
    }


    @Bean
    public SimpleBean simpleBean(){
        return new SimpleBean();
    }


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

改造service工程

在启动类上新增@EnableImRegisterServer注解

image-20230615100624340

到此热插拔就实现好了,当你加了@EnableImRegisterServer的时候启动zdy工程就会自动装配SimpleBean,反之则不装配。 让的原理也很简单,当加了@EnableImRegisterServer注解的时候,由于这个注解使用了@Import({ConfigMarker.class}),所以会导致Spring去加载ConfigMarker到上下文中,而又因为条件注解@ConditionalOnBean(ConfigMarker.class)的存在,所以MyAutoConfiguration类就会被实例化。

# 关于条件注解的讲解

  • @ConditionalOnBean:仅仅在当前容器给i中存在某个对象时,才会实例化一个Bean。
  • @ConditionalOnClass:某个class位于类路径上,才会实例化一个Bean。
  • @ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean。基于SpEL表达式的条件判断。
  • @ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean。
  • @ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean。
  • @ConditionalOnNotWebApplication:不是web应用,才会实例化一个Bean。
  • @ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
  • @ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
  • @ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
  • @ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
  • @ConditionalOnResource:当类路径下有指定的资源时触发实例化。
  • @ConditionalOnJndi:在JNDI存在的条件下触发实例化。
  • @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。
上次更新: 2025/04/03, 11:07:08
源码剖析-Run方法执行流程
源码剖析-内嵌Tomcat

← 源码剖析-Run方法执行流程 源码剖析-内嵌Tomcat→

最近更新
01
tailwindcss
03-26
02
PaddleSpeech
02-18
03
whisper
02-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 跨境互联网 | 豫ICP备14016603号-5 | 豫公网安备41090002410995号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式