Springboot基础之——自定义starter

引言

在实际开发中,经常会定义一些公共的组件,提供给各个项目团队使用。而在SpringBoot项目中,一般会将这些公共组件封装成SpringBoot的starter。

如果想要自定义starter的话,就要先了解自动配置原理。

1 自动配置原理

1.1 什么是自动配置?

遵循约定大于配置的原则,在boot程序启动后,起步依赖中的一些bean对象会自动注入到ios容器中。

先引入一个例子:

假设现在有一个自己写的jar包,里面有两个类CountryProvince,我们先将这个jar包导入项目,然后建一个Config类,然后在Config类里面配置属性,利用@Bean注册这个类,然后在启动类上用@Import导入config类,这样country和promise就注入到IOC容器里了。
在这里插入图片描述
那么,这样算是自动配置吗?这么繁琐,显然不是。

我们先来通过翻看源码的方式来了解springboot的自动配置是怎么一回事。

程序引入spring-boot-starter-web起步依赖,启动后,会自动往ioc容器中注入DispatcherServlet,这里我们就来看看,它是如何自动装配的吧。

去看看@SpringBootApplication
在这里插入图片描述

  • @Target(ElementType.TYPE), @Retention(RetentionPolicy.RUNTIME), @Documented, @Inherited: 这些都是注解的元信息,分别表示了该注解可以被应用于类、在运行时保留、生成 Javadoc 文档、并且可以被子类继承。
  • @ComponentScan:用于指定 Spring 在哪些包中寻找组件类(带有 @Component 注解的类),并且可以通过 excludeFilters 属性排除特定的组件。在这里,使用了两个自定义的过滤器 TypeExcludeFilter 和 AutoConfigurationExcludeFilter 来排除特定类型的组件。
  • @SpringBootConfiguration(重点)
    在这里插入图片描述
  • @EnableAutoConfiguration
    在这里插入图片描述
    要看懂这里首先我们要了解Bean是如何注册的

首先呢是注册自定义的Bean,主要就是通过@Compnent注解和它的衍生注解:
在这里插入图片描述
然后,当我们要注册的bean来自第三方时,是不能去修改第三方的类去加上以上的注解的,所以我们可以通过@Bean注解来实现。如:

@Configration
public class MyConfig{@Beanpublic `第三方bean` 返回值(){return new `第三方bean`;}
}

@Bean:将方法返回值交个IOC容器管理,称为IOC容器的bean对象,也可以放在启动类注册,但是我们一般想让启动类的职责单一,所以会自己建一个配置类而不是在启动类注册。
@Configration:表明该类是一个配置类。

如果MyConfig在启动类的同一级包或者子包下,就可以自动扫描上,但是如果不在同一级包或者同一级包的子包下,就必须要用@Import导入:

@Import(MyConfig.class)

如果有多个配置类,就需要多次导入,这样很繁琐,不够简洁,所以我们导入ImportSelector接口实现类:

public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{"com.lly.springbootAutoConfig.config.MyConfig"};}
}

这样即使有多个配置类,只要将它写在这个字符串数组中,然后在启动类导入用@Import导入这一个类就可以了。但是这样的话,耦合性就太高了,我们可以使用一个配置文件来降低耦合性。
在这里插入图片描述

public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {//读取配置文件的内容List<String> imports = new ArrayList<>();//将配置文件每一行的内容作为需要导入的类的类的全限定名InputStream is = MyImportSelector.class.getClassLoader().getResourceAsStream("myConfig.imports");BufferedReader br = new BufferedReader(new InputStreamReader(is));String line = null;while (true){try {if (!((line = br.readLine())!=null)) break;} catch (IOException e) {throw new RuntimeException(e);}finally {if (br!=null){try {br.close();} catch (IOException e) {throw new RuntimeException(e);}}}imports.add(line);}return imports.toArray(new String[0]);}
}

那么如果我们想让让我们的代码看着更高级一些呢?

  • 我们可以使用组合注解,自定义一个注解,封装@Import注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MyImportSelector.class)
public @interface EnableMyConfig {
}

最后再在启动类上添加这个注解就可以了,这样都不能直接看出来用的哪个类,不明觉厉,是不是很高级,maybe吧。

再让我们来了解一下SpringBoot提供的设置注解条件生效的注解@Conditional
在这里插入图片描述

最后,让我们回到@EnableAutoConfiguration
结合以上Bean是如何注册的是不是就能理解那张图了,这样就实现了DispatcherServlet的自动装配。

再回到我们之前的例子,要达到自动配置的效果:

  1. 首先,配置类要由我们的jar包来提供
  2. 提供一个自动配置类,使用@AutoConfiguration表示这个类为自动配置类,使用@Import注解将配置类导入进来
  3. 提供.imports配置文件
  4. 将自动配置类的全类名,配置到.imports配置文件里
    在这里插入图片描述

测试:

@SpringBootApplication
public class SpringbootAutoConfigApplication {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(SpringbootAutoConfigApplication.class, args);System.out.println(context.getBean("dispatcherServlet"));System.out.println(context.getBean("province"));}
}

结果:

org.springframework.web.servlet.DispatcherServlet@295bf2a
Province{name='null', direction='null'}

1.2 SpringBoot自动装配原理

总结:
SpringBoot自动装配的原理:首先在主启动类添加了@SpringBootApplication注解,这个注解组合了@EnableAutoConfiguration注解,而它又组合了@Import注解,导入了AutoConfigrationImportSelector类,这个类实现了selectImports方法,这个方法经过层层调用,最终会读取META-INF目录下的后缀名为.imports的文件,在文件中读取到了全类名之后,会解析注册条件,也就是@Conditional及其衍生注解,把满足注册条件的Bean对象自动注入到IOC容器中。

2 自定义starter

我们先参考一下mybatis的starter,一般情况下,起步依赖会有两个工程组成:
在这里插入图片描述
一般会在starter中引入autoconfigure,在使用时只要引入starter就相当于把autoconfigure引入进来了。当我们把这两个工程提供好了之后,自定义的starter也就制作好了。

2.1 自定义mybatis的starter

步骤

  1. 创建dmybatis-spring-boot-autoconfigure模块,提供自动配置功能,并自定义配置文件META-INF/spring/xxx.imports.
  2. 创建dmybatis-spring-boot-starter模块,在starter中引入自动配置模块。
2.1.1 dmybatis-spring-boot-autoconfigure模块:
  1. 在dmybatis-spring-boot-autoconfigure中引入依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>3.1.2</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jdbc</artifactId><version>3.0.0</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.13</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>3.0.0</version></dependency>
  1. 编写自动配置类
@AutoConfiguration//表明当前类是一个自动配置类
public class MybatisAutoConfig {/*** SqlSessionFactoryBean* @param dataSource 导入jdbc起步依赖时自动注入的* @return*/@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean;}/*** MapperScannerConfigure* @param beanFactory* @return*/@Beanpublic MapperScannerConfigurer mapperScannerConfigurer(BeanFactory beanFactory){MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();//扫描的包:启动类所在的包及其子包//springboot的核心启动依赖提供了对应的apiList<String> packages = AutoConfigurationPackages.get(beanFactory);String p = packages.get(0);mapperScannerConfigurer.setBasePackage(p);//扫描的注解mapperScannerConfigurer.setAnnotationClass(Mapper.class);return mapperScannerConfigurer;}
}
  1. 提供.imports配置文件,并将自动配置类的全类名,配置到.imports配置文件里
    在这里插入图片描述
2.1.2 dmybatis-spring-boot-starter模块
  • dmybatis-spring-boot-starter模块提供依赖管理的功能。
  1. 引入依赖
<dependency><groupId>com.lly</groupId><artifactId>dmybatis-spring-boot-autoconfigure</artifactId><version>1.0-SNAPSHOT</version></dependency><!--在dmybatis-spring-boot-autoconfigure里引入过的依赖在这里再引入一遍,方便以后对里面引入的依赖进行排除exclusion--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>3.1.2</version></dependency><!--jdbc起步依赖,会自动注入dataSource--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jdbc</artifactId><version>3.0.0</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.13</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>3.0.0</version></dependency>

:在 Maven 中,exclusion(排除)指的是在依赖关系中排除特定的传递性依赖。当你引入一个依赖库时,有时候你可能不希望引入这个库所依赖的某些其他库,这时就可以使用 exclusion 来排除这些传递性依赖。
在 Maven 的 pom.xml 文件中,你可以在依赖声明中使用 元素来排除传递性依赖。例如:

<dependency><groupId>org.sample</groupId><artifactId>sample-artifact</artifactId><version>1.0</version><exclusions><exclusion><groupId>org.unwanted</groupId><artifactId>unwanted-artifact</artifactId></exclusion></exclusions>
</dependency>

上述示例中,sample-artifact 依赖会被引入,但是其中排除了对 unwanted-artifact 的传递性依赖。
通过使用 exclusion,你可以更精确地控制项目中所引入的依赖,避免不必要的冲突或版本问题。

2.2 测试

starter结构:
在这里插入图片描述

  1. 导入依赖:
<!--mysql驱动依赖--><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><!--自定义的mybatis起步依赖--><dependency><groupId>com.lly</groupId><artifactId>dmybatis-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency>
  1. 数据库准备
    在这里插入图片描述3. 配置yml
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/testusername: rootpassword: root
  1. 实体类
public class Teachers {private Integer tid;private String tpwd;private String tname;private String tacademy;//省略get,set方法
}
  1. mapper
@Mapper
public interface TeachersMapper {@Select("select * from teachers where tid = #{id}")public Teachers findById(Integer id);
}
  1. Service接口及其实现
public interface TeachersService {public Teachers findById(Integer id);
}
@Service
public class TeachersServiceImpl implements TeachersService {@Autowiredprivate TeachersMapper teachersMapper;@Overridepublic Teachers findById(Integer id) {return teachersMapper.findById(id);}
}
  1. Controller
@RestController
public class TeachersController {@Autowiredprivate TeachersService teachersService;@RequestMapping("/findById")public Teachers findById(Integer id){return teachersService.findById(id);}
}
  1. 启动测试
    在这里插入图片描述
    这样我们自定义starter就成功了。

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

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

相关文章

地物波谱库共享网站汇总

ENVI自5.2版本重新梳理了原有的标准波谱库&#xff0c;新增一些物质波谱&#xff0c;在ENVI5.6中存放在…\Harris\ENVI56\ resource\speclib&#xff0c;分别存放在四个文件夹中&#xff0c;储存为ENVI波谱库格式&#xff0c;有两个文件组成&#xff1a;.sli和.hdr。 ENVI保留…

代码随想录——搜索插入位置(Leetcode35)

题目链接 class Solution {public int searchInsert(int[] nums, int target) {int len nums.length;int left 0;int right len - 1;int index -1;while(left < len / 2){if(nums[left] target || target < nums[left]){index left;break;}else{left;}if(nums[ri…

通过Caliper进行压力测试程序,且汇总压力测试问题解决

环境要求 第一步. 配置基本环境 部署Caliper的计算机需要有外网权限;操作系统版本需要满足以下要求:Ubuntu >= 16.04、CentOS >= 7或MacOS >= 10.14;部署Caliper的计算机需要安装有以下软件:python 2.7、make、g++(gcc-c++)、gcc及git。第二步. 安装NodeJS # …

高效 CUDA 调试:将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具

高效 CUDA 调试&#xff1a;将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具 NVIDIA Compute Sanitizer 是一款功能强大的工具&#xff0c;可以节省您的时间和精力&#xff0c;同时提高 CUDA 应用程序的可靠性和性能。 在 CUDA 环境中调试代码既具有挑…

超详细的fiddler教程

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Fiddler&#xff08;中文名称&#xff1a;小提琴&#xff09;是…

【算法题】三道题理解算法思想--滑动窗口篇

滑动窗口 本篇文章中会带大家从零基础到学会利用滑动窗口的思想解决算法题&#xff0c;我从力扣上筛选了三道题&#xff0c;难度由浅到深&#xff0c;会附上题目链接以及算法原理和解题代码&#xff0c;希望大家能坚持看完&#xff0c;绝对能有收获&#xff0c;大家有更好的思…

win11 安装SIBR 3dgs

1.安装显卡驱动 下载地址&#xff1a; 官方驱动 | NVIDIA下载适用于 GeForce、TITAN、NVIDIA RTX、数据中心、GRID 等 NVIDIA 产品的新驱动。https://www.nvidia.cn/Download/index.aspx?langcn 2.安装cuda 下载地址&#xff1a;如果无法打开&#xff0c;切换.com为.cn&am…

JavaScript基础练习题之计算数组元素的和与平均值

一、如何使用JavaScript计算数组元素的和与平均值&#xff1f; 二、正确的源程序 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>计算数组元素的和与平均值</title></head><body><h1>计算数组元…

两直线交点算法 C

求两直线交点算法 有中间交点 CD在AB异侧 且AB在CD异侧 AB在CD异侧 但 CD在AB同侧 无中间交点 A B A C A B A D \nobreak AB \times AC \newline AB \times AD ABACABAD 异号 叉乘后相乘小于零 等于零的几种情况 A B C与AB共线 D与AB共线 求交点&#xff0c;可由面积比…

iOS - LLVM的中间代码(IR)

文章目录 iOS - LLVM的中间代码&#xff08;IR&#xff09;1. 转为汇编代码2. 中间代码&#xff08;IR&#xff09;2.1 Objective-C在变为机器代码之前&#xff0c;会被LLVM编译器转换为中间代码&#xff08;Intermediate Representation&#xff09;2.2 可以使用以下命令行指令…

武忠祥《660题》高效刷题包+资料分享

660题的难度书虽然比较难&#xff0c;对于基础的考察比较深入&#xff0c;所以&#xff0c;有没有一种可能&#xff0c;做题太慢&#xff0c;是因为基础不好导致的&#xff01; 所以再继续做下去&#xff0c;就没有什么意义了&#xff0c;因为这就像是用一把钝刀去砍树&#x…

VS2022 使用ClaudiaIDE设置自定义图片背景

ClaudiaIDE的下载 第一步&#xff0c;如下图所示&#xff0c;点击&#xff1a;扩展——管理扩展。 第二步&#xff0c;如下图所示&#xff0c;点击&#xff1a;联机——右上角输入ClaudiaIDE搜索——点击下载。 下载后关闭所有VS窗口&#xff0c;然后等待弹出一个安装窗口&…

小米汽车正式发布:开启智能电动新篇章

随着科技的不断进步&#xff0c;汽车产业正经历着前所未有的变革。智能电动汽车作为这一变革的重要方向&#xff0c;正吸引着越来越多的目光。在这个充满机遇和挑战的时代&#xff0c;小米汽车凭借其卓越的技术实力和深厚的市场底蕴&#xff0c;终于迈出了坚实的一步。今天&…

Exception in thread “main“ com.fasterxml.jackson.databind.JsonMappingException:

问题&#xff1a;jaskson反序列化超出最大长度 Caused by: com.fasterxml.jackson.core.exc.StreamConstraintsException: String length (5043456) exceeds the maximum length (5000000) 场景&#xff1a;前端传递过大base64 原因&#xff1a; jaskon默认已经限制了最大长…

免费|Python|【需求响应】一种新的需求响应机制DR-VCG研究

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序对应文章《Contract Design for Energy Demand Response》&#xff0c;电力系统需求响应&#xff08;DR&#xff09;用来调节用户对电能的需求&#xff0c;即在预测的需求高于电能供应时&#xff0c;希…

chrome 控制台不能粘贴

描述&#xff1a;chrome 控制台不能粘贴 解决方案&#xff1a;setting-Experiments-Filter中输入past&#xff0c;取消勾选

国际伦敦金行情分析中的趋势分析方法

国际伦敦金行情走势复杂多变。近期&#xff0c;金价曾经一度刷新历史的新高点至2222&#xff0c;但就在当天&#xff0c;金价又快速下跌跌超过30美元。不过这么多变的伦敦金行情也为我们的交易创造了空间&#xff0c;有空间就等于有机会&#xff0c;只要我们能够掌握国际伦敦金…

HCIP作业3

第一步 给PC1配置&#xff1a; 先给PC2配置&#xff1a; 第二部 给R1的接口配置ip [R1]int g0/0/0 [R1-GigabitEthernet0/0/0]ip add 192.168.1.252 24 [R1-GigabitEthernet0/0/0]int g0/0/1 [R1-GigabitEthernet0/0/1]ip ad 100.1.1.1 24 给R2的接口配置IP [R2]int g0/0/…

Java:接口应用(Comparable接口与比较器)

目录 1.引例2.Comparable接口使用3.Comparable接口的局限性4.使用comparaTo实现排序5.比较器&#xff08;Comparator接口&#xff09; 1.引例 class Student{private String name;private int age;public Student(String name, int age) {this.name name;this.age age;} } p…