写一个starter(spring boot)

news2024/9/27 15:21:29

前置知识

自动装配

自动装配的一个重要注解就是@SpringBootApplication。它是一个复合注解,由四个元注解和另外三个注解组成。这三个注解是:

  • @Configuration
  • @EnableAutoConfiguration
  • @ComponentScan
    在这里插入图片描述

@Configuration

@Configuration 是 JavaConfig 形式的基于 Spring IOC 容器的配置类使用的一种注解。所以在启动类里面标注了 @Configuration,意味着它其实也是一个 IoC 容器的配置类。
传统意义上的 Spring 应用都是基于 xml 形式来配置 bean 的依赖关系。但是从 Spring3 开始,Spring 就支持了两种 bean 的配置方式,一种是基于 xml 文件方式,另一种就是 JavaConfig,任何一个标注了@Configuration 的 Java 类定义都是一个JavaConfig 配置类。而在这个配置类中,任何标注了@Bean 的方法,它的返回值都会作为 Bean 定义注册到 Spring 的 IoC 容器,方法名默认成为这个 Bean 的 id。然后通过 spring 容器在启动的时候,把 Bean 进行初始化并且,如果 Bean 之间存在依赖关系,则分析这些已经在 IoC 容器中的 Bean 根据依赖关系进行组装。

@ComponentScan

@ComponentScan 这个注解就是扫包,相当于 xml 配置文件中的 context:component-scan 。它的主要作用就是扫描指定路径下的标识了需要装配的类,自动装配到 Spring 的 IoC 容器中。
标识需要装配的类主要是:@Component、@Repository、@Service、@Controller这类的注解标识的类。(注 @Repository、@Service、@Controller 的底层还是 @Component)。 ComponentScan 默认会扫描当前 package 下的的所有加了相关注解标识的类到 IoC 容器中。

@EnableAutoConfiguration

@EnableAutoConfiguration 是 Spring Boot 的灵魂,是重中之重。从 Spring3.1 开始,提供了一系列的 @Enable 开头的注解,它是在 JavaConfig 框架上更进一步的完善,使用户在使用 Spring 相关的框架避免配置大量的代码从而降低使用的难度。
比如常见的一些 Enable 注解:@EnableWebMvc、@EnableScheduling、@EnableAsync 等等。 每一个涉及到 Enable 开头的注解,都会带有一个 @Import 的注解, @EnableAutoConfiguration 也不例外,我们点进去发现如红框所示。
在这里插入图片描述

@Import 注解是什么意思呢? 它对应 XML 形式下的< import resource/ >,就是导入资源,把多个分布在不同容器下的配置合并在一个配置中。@Import 注解可以配置三种不同的 class :

  1. 普通 Bean 或者带有 @Configuration 的配置文件
  2. 实现 ImportSelector 接口进行动态注入
  3. 实现 ImportBeanDefinitionRegistrar 接口进行动态注入
    这里导入的是第二种 importSelector,这是一种动态注入 Bean 的技术,进入 AutoConfigurationImportSelector 注解,发现它实现了 ImportSelector 接口。
    在这里插入图片描述

找到实现方法selectImports ,该方法的作用就是找到相应的 Bean 注入到容器中。

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!this.isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    } else {
        AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
        return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
}

再从 getAutoConfigurationEntry 方法点进去,这里面做了许多事情,就是把找到的 Bean 进行排除、过滤、去重,我们可以看到 removeDuplicates、remove、filter 等方法。
在这里插入图片描述

那具体这些 Bean 从哪里找呢,从 getCandidateConfigurations 方法点进去,发现了有一个 META-INF/spring.factories 文件。

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()));
    ImportCandidates.load(AutoConfiguration.class, this.getBeanClassLoader()).forEach(configurations::add);
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

原来 SpringFactoriesLoader 的作用就是从 classpath/META-INF/spring.factories 文件中,根据 key来加载对应的类到 Spring IoC 容器中。文件中写了许多的配置项,但是并不是一次性就全部加载所有配置,Spring Boot采用的是按条件加载,主要通过Conditional开头的注解实现。
在这里插入图片描述

自定义一个starter

需求

写一个序列化的插件,并且可以自由的选择 fastjson 还是 gson,如果没选的情况下默认选择fastjson。

步骤

1、创建一个空的maven项目starter-test。
2、添加一个springboot项目的module,名为format-spring-boot-starter。Spring的官方的starter一般命名为spring-boot-starter-{name},第三方starter命名为{name}-spring-boot-starter。

3、pom配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>

<!-- 这个是用来提示用的-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.67_noneautotype2</version>
</dependency>

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.9</version>
</dependency>

3、定义格式化接口

public interface FormatProcessor {
    <T> String format(T t);
}

4、编写Fastjson和Gson实现类

public class FastjsonProcessor implements FormatProcessor {
    @Override
    public <T> String format(T t){
        return "fastjson: " + JSON.toJSONString(t);
    }
}
public class GsonProcessor implements FormatProcessor {
    @Override
    public <T> String format(T t) {
        Gson gson = new Gson();
        String jsonStr = gson.toJson(t);
        return "gson: " + jsonStr;
    }
}

5、写一个配置类,这里用了条件注解,如果 fastjson 和 gson 类存在的情况下才加载对应的实现类,因为在 pom 文件里都引用了,所以这里都会被装载。对同一个接口,有几种不同的实现类时,@Autowired 是按类型注入的,不知道要选哪一个,按照第二点需求,用户在没选的情况下默认选择 fastjson,所以这里给 fastjson 的实现上打上 @Primary。

public class FormatAutoConfiguration {

    @ConditionalOnClass(name = "com.alibaba.fastjson.JSON")
    @Bean
    @Primary
    public FormatProcessor fastjsonProcessor(){
        return new FastjsonProcessor();
    }

    @ConditionalOnClass(name = "com.google.gson.Gson")
    @Bean
    public FormatProcessor gsonProcessor(){
        return new GsonProcessor();
    }
}

6、配置类,用来读取用户的选择,作用和 @Value 一样。

@ConfigurationProperties(prefix = "fg.format")
public class FormatProperties {
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

7、模版调用实现类,这个就是提供给用户直接调用的,例如,常用的 RedisTemplate、JdbcTemplate,构造函数的时候直接传入具体的实现。

public class FormatTemplate {
    private FormatProcessor formatProcessor;

    public FormatTemplate(FormatProcessor formatProcessor) {
        this.formatProcessor = formatProcessor;
    }

    public <T> String doFormat(T obj) {
        return formatProcessor.format(obj);
    }
}

8、主类。@Import 用来导入配置类,就是将该配置类中的 Bean 注入到容器,@EnableConfigurationProperties 这是在将属性类激活,注入到容器中,也可以用 @Bean 的方式,@Configuration 说明这是一个配置类。接下来将 FormatTemplate 注入到容器中,首先是去属性类中去读属性,如果是 fastjson 就返回 fastjson 的实现,如果是 gson 就返回 gson 的实现,如果没读取到,就用前面设置的 @Primary 的默认实现。

@Import(FormatAutoConfiguration.class)
@EnableConfigurationProperties(FormatProperties.class)
@Configuration
public class FGFormatConfiguration {
    @Bean
    public FormatTemplate getFormatTemplate(FormatProperties formatProperties, FormatProcessor formatProcessor) {
        if("fastjson".equals(formatProperties.getType())){
            return new FormatTemplate(new FastjsonProcessor());
        }
        if("gson".equals(formatProperties.getType())){
            return new FormatTemplate(new GsonProcessor());
        }
        return new FormatTemplate(formatProcessor);
    }
}

9、最后一步最关键的就是设置,在 resources 文件夹下创建 META-INF/spring.factories 文件,通过上面的知识,Spring Boot 在启动的时候就是读取该文件下的配置类,从而将 Bean 加载到容器中。

org.springframework.boot.autoconfigure.EnableAutoConfiguration= \
com.example.formatspringbootstarter.FGFormatConfiguration

10、打包 mvn install。如果出现找不到主类情形,可以在pom中进行如下配置

org.springframework.boot spring-boot-maven-plugin com.example.formatspringbootstarter.FGFormatConfiguration

11、测试,新建一个spring boot项目模块,引入配置

<dependency>
    <groupId>com.example</groupId>
    <artifactId>format-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

12、编写测试类,User类可以自己定义,此处省略

@RestController
public class HelloController {
    @Autowired
    FormatTemplate formatTemplate;

    @GetMapping("/hello")
    public String sayHello() {
        User user = new User();
        user.setId(123L);
        user.setUsername("name");
        user.setPassword("abcd");
        return formatTemplate.doFormat(user);
    }
}

13、测试结果(根据application.properties配置不同,输出不同结果,不配置,默认为第一种情况)

  • 第一种情形
    fg.format.type=fastjson
    在这里插入图片描述
  • 第二种情形
    fg.format.type=gson
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/731147.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

红黑树做中文字符输入法,你懂了不?

前言 输入一个字符&#xff0c;匹配中文字符的输入法&#xff0c; 例如输入a&#xff0c;输出&#xff1a;啊阿&#xff0c;然后再输入n&#xff0c;即变成an&#xff0c;输出&#xff1a;鞍氨安俺按暗岸胺案&#xff0c; 要求要有搜索的接口&#xff0c;应该如何设计呢&#…

【JY】这个房子应该做抗震or减隔震?

一个问题的引出 有一个有趣的问题&#xff0c;你家如果在处于地震带高烈度地区的村子里有一块地可盖房子&#xff0c;你会用什么技术建造呢&#xff1f;&#xff08;村镇建筑建造~&#xff09; 抗震 or 减隔震&#xff1f; 正文 对于这个问题&#xff0c;呼声最高的是隔震技术…

【数据结构】24王道考研笔记——树与二叉树

五、树与二叉树 目录 五、树与二叉树树的基本概念二叉树的概念基础概念常考性质存储方式 二叉树遍历及线索二叉树前中后以及层次遍历线索二叉树 树、森林树的存储结构树、森林与二叉树的转换树、森林的遍历 树与二叉树应用哈夫曼树并查集 树的基本概念 树是n个结点的有限集合&…

Oracle体系结构

Oracle体系结构 前言 1、数据库 2、 实例 3、用户 4、表空间 5、数据文件&#xff08;dbf、ora&#xff09; 6、逻辑图 1、数据库 Oracle 数据库是数据的物理存储。这就包括&#xff08;数据文件 ORA 或者 DBF、控制文件、联机日志、参数文件&#xff09;。 其实 Oracle 数据库…

【javaEE面试题(一)用鸡和鸡蛋和房间的样例 讲给面试官听】【3.8千字解析进程和线程-配非常重要的面试题】进程和线程的区别

欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#xff1a;重难点★✔ 蓝色文字表示&#…

Nodejs基于Windows安装教程

一、安装环境 在进行 Node.js 环境的安装之前&#xff0c;您需要先安装并配置好以下环境&#xff1a; 操作系统&#xff1a;Windows 命令行工具&#xff1a;Node.js 是通过命令行工具进行使用和管理的&#xff0c;因此您需要选择一个适合您的命令行工具。在 Windows 上&…

go-zero微服务实战——基本环境搭建

简介 项目架构来源于go-zero实战&#xff1a;让微服务Go起来。此对该项目有所删减&#xff0c;相对简单适合初学者。 省去了项目中每个服务占用独立docker的过程&#xff0c;省略了docker-compose的构建过程。每个服务是一个独立的程序不依赖与容器。 环境搭建 安装goctl …

c++ -- STL

【C/C】STL详解_cstl_沉晓的博客-CSDN博客 Learning Record have done assignment class template An excellent programmer only needs to know how to use containers to improve program encapsulation and reduce coupling, without understanding the underlying pri…

面向对象之创建对象模式和继承模式

目录 工厂函数模式 优点&#xff1a; 缺点&#xff1a; 构造函数模式 优点: 缺点: 原型对象模式 优点: 缺点: 组合模式 instanceof 继承 继承分为三类&#xff0c;分别是:原型链继承、借用构造函数继承、组合继承(原型链继承借用构造函数继承) 组合继承 从…

开发工具VSCODE的使用记录

vscode简介 Visual Studio Code&#xff08;简称“VS Code” [1] &#xff09;是Microsoft在2015年4月30日Build开发者大会上正式宣布一个运行于 Mac OS X、Windows和 Linux 之上的&#xff0c;针对于编写现代Web和云应用的跨平台源代码编辑器&#xff0c; [2] 可在桌面上运行…

ADB 命令结合 monkey 的简单使用,超详细

一&#xff1a;ADB简介 1&#xff0c;什么是adb&#xff1a; ADB 全称为 Android Debug Bridge&#xff0c;起到调试桥的作用&#xff0c;是一个客户端-服务器端程序。其中客户端是用来操作的电脑&#xff0c;服务端是 Android 设备。ADB 也是 Android SDK 中的一个工具&#…

openssl CVE-2016-2107 漏洞检测---OpenSSL Padding Oracle 攻击

openssl CVE-2016-2107 漏洞检测—OpenSSL Padding Oracle 攻击 文章目录 CVE-2016-2107.exe执行1执行2 OpenSSL Padding Oracle 攻击漏洞描述检测方法修复 CVE-2016-2107.exe 执行1 下载CVE-2016-2107.exe https://github.com/FiloSottile/CVE-2016-2107 https://github.com…

2023 7.3~7.9 周报 (论文初读)

上周回顾: (上周还没开始) 本周计划: 本周阅读论文《Deep-Learning Full-Waveform Inversion Using Seismic Migration Images》. 这篇论文是发表于2022的一篇较新的关于DL-FWI的论文, 作者在论文中提出了一些比较新颖的观点和质疑. 这篇论文主基调很符合近几年DL-FWI的味道…

对 MinIO API 进行封装并上传到第三方库 Pyzjr

目录 本文介绍 上一节补充 使用官方的游乐场进行测试和开发 熟悉MinIO的API 创建客户端 操作桶 1、检查桶是否存在&#xff0c;如果不存在就创建一个桶 2、列出所有的存储桶名 3、删除储存桶 4、用于查看存储桶的对象 操作对象 1、删除对象 2、删除zip文件 3、下…

C#基础学习_构造方法

C#基础学习_构造方法 在构造方法中添加初始化内容; 通过使用构造方法,可以简化对象初始化代码。 无参数的构造方法: public Student(){StudentID = 12345;StudentName = "djichsdi";}带参数的构造方法(构造方法同样可以重载&

Python——基础语法

输出语句 #字符串拼接 print("hello word""北岭山脚鼠鼠") #字符转义 print("He said \"Let\s go!\"") #换行 print("hello!\nHi!") #三引号 print(""""北岭山脚鼠鼠 北岭山脚鼠鼠 北岭山脚鼠鼠 北岭山…

ESP32(掌控板) 陀螺仪显示与RGB灯

ESP32&#xff08;掌控板&#xff09; 陀螺仪显示与RGB灯 本程序图形化显示陀螺仪位置&#xff08;注意要换算&#xff09;&#xff0c;根据陀螺仪位置控制RGB灯颜色并有3种颜色组合和关灯可选&#xff0c;通过触摸按键调节亮度。 图形化程序如下 Arduino代码如下 /*!* MindP…

字符集,编码方式和Java程序乱码问题

目录 1&#xff0c;字符编码 2&#xff0c;三大字符集及编码方式 2.1&#xff0c;ASCII字符集及编码方式 2.2&#xff0c;GBK字符集及编码方式 2.3&#xff0c;Unicode字符集及编码方式 3.程序乱码问题 1&#xff0c;字符编码 数字计算机中的存储器唯一可以存储的是比特&a…

绿虫生产效率提升工具怎么安装配置?

一、添加员工 打开绿虫生产效率提升工具后台&#xff0c;输入账号密码登录&#xff0c;登录成功之后&#xff0c;需要先进行员工添加&#xff0c;点击员工管理&#xff0c;导入员工信息&#xff0c;也可使用企微同步。 二、绑定员工 点击终端部署&#xff0c;复制网址或下载安…

多模态系列论文----最详细的多模态论文总结(BLIP、BEIT、CoCa等)

1 多模态概述 多模态指的是多种模态的信息数据&#xff0c;包括&#xff1a;文本、图像、视频、音频等。多模态任务是指需要同时处理两种或多种不同类型的数据的任务。近年来&#xff0c;随着深度学习技术的发展&#xff0c;多模态任务取得了显著的进步。特别是VIT&#xff08…