写一个starter(spring boot)

前置知识

自动装配

自动装配的一个重要注解就是@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 {@Overridepublic <T> String format(T t){return "fastjson: " + JSON.toJSONString(t);}
}
public class GsonProcessor implements FormatProcessor {@Overridepublic <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@Primarypublic FormatProcessor fastjsonProcessor(){return new FastjsonProcessor();}@ConditionalOnClass(name = "com.google.gson.Gson")@Beanpublic 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 {@Beanpublic 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 {@AutowiredFormatTemplate 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.hqwc.cn/news/13207.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

神经网络之VGG

目录 1.VGG的简单介绍 1.2结构图 3.参考代码 VGGNet-16 架构&#xff1a;完整指南 |卡格尔 (kaggle.com) 1.VGG的简单介绍 经典卷积神经网络的基本组成部分是下面的这个序列&#xff1a; 带填充以保持分辨率的卷积层&#xff1b; 非线性激活函数&#xff0c;如ReLU&a…

web安全php基础_php变量命名及其作用域

php变量命名规则 php变量命名规则 变量以 $ 符号开始&#xff0c;后面跟着变量的名称变量名必须以字母或者下划线字符开始变量名只能包含字母数字字符以及下划线&#xff08;A-z、0-9 和 _ &#xff09;变量名不能包含空格变量名是区分大小写的&#xff08;$y 和 $Y 是两个不…

SELECT * 会导致查询效率低的原因

SELECT * 会导致查询效率低的原因 前言一、适合SELECT * 的使用场景二、SELECT * 会导致查询效率低的原因2.1、数据库引擎的查询流程2.2、SELECT * 的实际执行过程2.3、使用 SELECT * 查询语句带来的不良影响 三、优化查询效率的方法四、总结 前言 因为 SELECT * 查询语句会查…

【如何成功加载 HuggingFace 数据集】不使用Colab,以ChnSentiCorp数据集为例

【如何成功加载 HuggingFace 数据集】不使用Colab&#xff0c;以ChnSentiCorp数据集为例 前置加载数据集尝试一&#xff1a;标准加载数据库代码尝试二&#xff1a;科学上网尝试三&#xff1a;把 Huggingface 的数据库下载到本地尝试3.5 创建 state.json彩蛋 前置 Huggingface …

MySQL用户管理

目录 用户管理 用户 用户信息 创建用户 删除用户 修改用户密码 数据库的权限 给用户授权 回收权限 用户管理 如果我们只能使用root用户&#xff0c;这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理。 用户 用户信息 MySQL中的用户&#xff0c;都存储…

手写操作系统--进入保护模式的开篇

之前我们讲的主引导扇区以及内核加载器等内容。都是在实模式下运行的。在实模式下寻址范围仅有1M&#xff0c;是远远不够我们用的。我们想要更大的内存空间&#xff0c;就得进入保护模式&#xff0c;实模式是一个历史遗留问题&#xff0c;本身是没有这个名字的。是因为有了保护…

Keil环境下CANopenNode移植到STM32问题记录(一)---printf重定向问题

文章目录 问题描述问题结决思考&#xff1a;相关文章 在直接将CANopenSTM32的示例工程直接移植到Keil环境下。 如果移植工程未实现printf函数重定向&#xff0c;则要注释掉log_printf下面的printf函数&#xff0c;使日志打印失效 /* Printf function of CanOpen app */ #define…

vue3的getCurrentInstance()方法拿到的实例对象中的proxy

getCurrentInstance方法拿到的是当前组件的实例对象 实例对象中的成员proxy是一个代理对象&#xff0c;可以通过访问代理对象来间接访问当前组件的实例对象 这样就不需要this&#xff0c;也可以操作当前组件的实例对象了 proxy对象就相当于当前组件的实例对象 proxy对象会对…

FPGA实验五:信号发生器设计

目录 一、实验目的 二、设计要求 三、实验代码 1.代码原理分析 2.代码设计思路 3.IP核的设计与配置 四、实验结果及分析 1、引脚锁定 2、仿真波形及分析 &#xff08;1&#xff09;关于波形一些指标的介绍 &#xff08;2&#xff09;对波形转换功能的验证 &#xf…

【CPU】关于x86、x86_64/x64、amd64和arm64/aarch64

为什么叫x86和x86_64和AMD64? 为什么大家叫x86为32位系统&#xff1f; 为什么软件版本会注明 for amd64版本&#xff0c;不是intel64呢&#xff1f; x86是指intel的开发的一种32位指令集&#xff0c;从386开始时代开始的&#xff0c;一直沿用至今&#xff0c;是一种cisc指令…

Haskell 入门学习(一)之安装试用 Haskell

Haskell 入门学习&#xff08;一&#xff09;之安装试用 Haskell 文章目录 Haskell 入门学习&#xff08;一&#xff09;之安装试用 Haskell前言&#xff1a;安装Windows 安装Linux、MacOs 使用 VSCode 进行代码编写创建一个简单的项目使用 Cabal 管理项目项目大致结构运行项目…

python验证公网ip与内网ip

公网IP和内网IP都是用于标识网络设备的地址&#xff0c;但它们有着不同的作用和特点。 公网IP是由互联网服务提供商&#xff08;ISP&#xff09;分配给用户设备的唯一标识符。它是全球范围内唯一的&#xff0c;并且可以被其他网络设备使用来寻找和连接特定的设备。公网IP通常用…