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,一经查实,立即删除!

相关文章

【阅读笔记】《一个聪明的投资者》

格雷厄姆传记 全名&#xff1a;一个聪明的投资者——本杰明格雷厄姆 作者&#xff1a;[美]Joe Carlen 翻译&#xff1a;李莉、吴传珍 笔记 CH1 家族没落 CH2 安全边际 在牛市时&#xff0c;其他人被高收益蒙蔽了双眼&#xff0c;但格雷厄姆主要关心本金的安全&#xff0c;其…

地物波谱库共享网站汇总

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…

HTML 怎么解决上下标问题呢?

当我们阅读内容时&#xff0c;经常会遇到特殊格式的文本&#xff0c;如化学式的下标和数学公式的上标&#xff0c;sub 标签和sup 标签就是用来解决这个问题的。 1. 基础语法 什么是 sub 和sup标签 sub 标签用于定义下标文本&#xff0c;而 sup 标签用于定义上标文本。 这些…

每日一题(洛谷2386):盘子里放苹果-dfs

题目描述 把 m 个同样的苹果放在 n 个同样的盘子里&#xff0c;允许有的盘子空着不放&#xff0c;问共有多少种不同的分法。&#xff08;5,1,15,1,1 和 1,1,51,1,5 是同一种方法&#xff09; 输入格式 第一行是测试数据的数目 t&#xff0c;以下每行均包括二个整数 m 和 n&a…

通过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 环境中调试代码既具有挑…

JavaSE函数

函数 / 方法&#xff1a;是一个解决特定问题的代码块&#xff0c;该代码块可以被反复使用 1、定义函数 语法格式&#xff1a; 访问修饰符 方法返回值类型 方法名称([参数列表]) [抛出异常] {方法体;[return 返回值;] } 访问修饰符&#xff1a; public 这是公共&#xff0c;…

Android中的本地广播与全局广播

文章目录 1. 概念介绍2. 本地广播3. 全局广播 1. 概念介绍 前文我们介绍了Android中的广播&#xff0c;按注册方式分为静态广播和动态广播&#xff1b;按接收顺序分为有序广播与无序广播 本文我们按照广播的传播范围&#xff0c;将广播分为本地广播和全局广播 本地广播&#x…

算法——排序

快速排序&#xff1a; http://t.csdnimg.cn/iGs34 void QuickSort(int array[], int low, int high) {int i low; int j high;if(i > j) {return;}int temp array[low];while(i ! j) {while(array[j] > temp && i < j) {j--;}while(array[i] < temp &…

算法设计-杨辉三角

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 杨辉三角形又称Pascal三角形&#xff0c;它的第i1行是(ab)i的展开式的系数。 它的一个重要性质是&#xff1a;三角形中的每个数字等于它两肩上的数字相加。 下面给出了杨辉三角形的…

超详细的fiddler教程

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

sparksql的shuffle分区数设置

SparkSQL的shuffle默认分区数设置 在SparkSQL中当Job中产生Shuffle时&#xff0c;默认的分区数(spark.sql.shuffle.partitions)为200,在实际项目中要合理的设置&#xff0c;特别是本地场景&#xff0c;一般支持不了200个分区。 可以设置在&#xff1a; 配置文件&#xff1a;c…

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

滑动窗口 本篇文章中会带大家从零基础到学会利用滑动窗口的思想解决算法题&#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…

对java元空间的理解

Java 8 引入了元空间&#xff08;Metaspace&#xff09;&#xff0c;取代了之前的永久代&#xff08;Permanent Generation&#xff09;。以下是我对 Java 元空间的理解&#xff1a; 存储类元数据&#xff1a;元空间用于存储类的元数据信息&#xff0c;如类名、方法信息、字段信…

LeetCode6. Z 字形变换(Java)

将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 "PAYPALISHIRING" 行数为 3 时&#xff0c;排列如下&#xff1a; P A H N A P L S I I G Y I R 之后&#xff0c;你的输出需要从左往右…

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;可由面积比…