介绍
★ 自定义自动配置=自动配置类+注册
所谓的自动配置,就是通过一个配置类,然后这个配置类在我们容器中定义了大量的bean,然后这些bean也不是直接定义,它是结合了条件注解,只有在某些特定的条件下,才会生效,这样我们的自动配置就可以根据我们的环境的配置(如yml配置文件),根据我们这个应用程序所使用的环境来决定这些bean的配置是否要生效。
自定义自动配置分为2步:
(1)使用@Configuration和条件注解定义自动配置类。
使用条件注解和@Bean注解在容器中定义整合框架所需要的组件(Bean)。
比如程序要整合MyCustomFrame框架,MyCustomFrame框架所需要核心组件就是WriterTemplate,
因此该自动配置就是负责在容器中自动配置WriterTemplate
(2)在META-INF/spring.factories中注册自动配置类。
使用如下META-INF/spring.factories文件来注册自动配置类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.ljh.mycustomstarter.FrameAutoConfiguration
开发完自己的自动配置及Starter后,并不需要运行该项目,而是应该将Starter安装到本地资源库、甚至公司的中央资源库。
在Spring的Java配置类中,方法名默认将作为bean的id,因此不要让两个方法的方法名相同,这样会造成ID冲突。
★ 自定义Starter组件
官方推荐,一个完整的Spring Boot starter应该包含以下两个组件:
- auto-configure模块,包含自动配置类和META-INF\spring-factories文件。推荐名:xxx-spring-boot-autoconfigure
- Starter模块:负责管理自动配置模块及其他第三方的依赖,简而言之,添加本Starter就能开始使用该自动配置。
推荐名:xxx-spring-boot-starter
Spring Boot官方Starter名叫: spring-boot-stater-xxx
Starter并不包含任何class文件,它只负责管理依赖。
Starter JAR包下只包含xxx-starter.pom文件,该文件指定该Starter负责管理的自动依赖模块和第三方依赖。
【注意】:使用Maven开发Spring Boot的Starter组件时,不要添加spring Boot的Maven插件
——否则该Maven插件总以为你是一个Spring Boot项目,它总会尝试帮你找程序的主类。
代码演示:
需求分析总结:
创建一个自定义的第三方框架 MyCustomFrame , 创建一个自定义的 Starter 组件 MyCustomStarter,创建一个普通项目 CustomFrameTest 来添加 自定义的 starter 组件,进行测试。
测试:根据普通项目的配置,决定信息输出到数据库还是文件。
关系:
第三方框架 MyCustomFrame 作用:提供一个 WriterTemplate 工具类,用来实现一个功能。
功能:如果我们引入这个第三方框架的项目有连接数据库,那么就把要输出的信息输出到数据库,如果没有连接数据库,那么就把要输出的信息输出到指定的文件
自定义 Starter 组件的作用:核心就是提供一个 FrameAutoConfiguration 配置类,用来整合第三方框架 MyCustomStarter 时,需要的一些配置。
简单来说,这个 FrameAutoConfiguration 配置类 提供两个 Bean,根据我们的普通项目CustomFrameTest 是否有连接数据库,进行分析,有连接就返回输出到数据库的Bean,没有连接就返回输出到文件的bean。
文字大概这么描述,具体还得看截图一并分析。
代码截图分析:
开发第三方框架:MyCustomFrame
1、第一步:先创建一个maven项目,作为第三方框架,项目名叫:MyCustomFrame,
这个项目里面只有一个核心的类,WriterTemplate,作用是引入这个第三方框架的项目是否有连接数据库,有就把要输出的信息输出到数据库,如果没有连接数据库,那么就把要输出的信息输出到指定的文件 的功能。
然后把这个框架部署到本地资源库,双击 Ctrl 键,用 mvn install 操作把框架打包并且安装到我们的本地资源库
具体代码看文章最后:
代码:
然后把这个第三方框架 通过 双击 Ctrl 键,输入 mvn install 命令 , 把这个框架打包成jar包,安装到本地的 maven 库里面。
可以理解成我们在项目中添加依赖一样。添加的依赖就会保存在 maven 仓库里面。
这样一个简单的第三方框架就可以了
开发 starter 组件:mycustomstarter
2、第二步:演示如何使用 spring 通过 自动配置来开发一个自动的 starter 组件,让我们的项目可以很简单的通过starter 来整合我这个自定义的第三方框架(MyCustomFrame)
现在开发starter组件
这个starter组件主要就是这两个类:属性处理类和配置类,还有一个注册配置类的文件。
详细:
FrameProperties 属性处理类:
在starter组件添加这个属性处理类,后面这个starter组件被引入到项目后,就可以获取到该项目指定前缀的一些配置文件的属性
FrameAutoConfiguration 配置类:
spring.factories 用来注册自动配置类FrameAutoConfiguration :
pom.xml 文件
到这里 starter组件就开发完成,现在就需要把这个组件也打包成jar包,安装到 maven 仓库里面。
开发完自己的自动配置(MyCustomFrame)及Starter(MyCustomStarter)后,并不需要运行该项目,而是应该将Starter安装到本地资源库、甚至公司的中央资源库。
双击 Ctrl 键,然后输入 mvn install 命令就可以了,就会自动保存到本地的maven仓库
如果修改了这个starter组件,要重新打包的话,我选择先删除target包,再重新编译下,再打包成jar包。
【注意】:使用Maven开发Spring Boot的Starter组件时,不要添加spring Boot的Maven插件
——否则该Maven插件总以为你是一个Spring Boot项目,它总会尝试帮你找程序的主类。
starter 组件不需要 这个 maven 插件,把这个删除掉,不然打包失败
针对自定义starter组件中一些代码的理解:
@Bean 表明在spring 容器中配置这个bean
1、@EnableConfigurationProperties
这里创建了属性处理类,这个类需要用 @EnableConfigurationProperties(value = FrameProperties.class) 这个注解来启用它,不然就会爆红,如图:
还需要配合这个注解,用来解析配置文件的属性
2、@ConditionalOnClass(WriterTemplate.class)
这是一个条件注解,被这个注解修饰的这个 FrameAutoConfiguration 配置类,如果要生效,项目中就必须有WriterTemplate这个类存在,不然就不生效。
因为这个WriterTemplate类是存在第三方框架MyCustomFrame里面的,所以需要引入第三方框架的依赖
3、@AutoConfigureAfter(DataSourceAutoConfiguration.class)
因为这个配置类添加的writerTemplate1这个bean需要Datasource作为参数,但是在加载的时候,可能加载 writerTemplate1 这个bean的时机 比加载 DataSourceAutoConfiguration这个类要快,所以需要添加这个条件注解@AutoConfigureAfter。
作用就是FrameAutoConfiguration这个配置类要在DataSourceAutoConfiguration类加载存在后才能加载。
@ConditionalOnMissingBean:
只有当项目中 没有 WriterTemplate 这个bean时,才自动为项目配置这个Bean,因为如果项目中有开发人员自己自定义开发 WriterTemplate 这个bean,那我们肯定不需要再额外自动配置 WriterTemplate 这个bean
@ConditionalOnSingleCandidate:
另外,Bean上面的这个@ConditionalOnSingleCandidate(DataSource.class)注解,表示只有当spring容器中有且仅有一个 DataSource Bean 的时候,下面这个bean配置方法才生效。
原因:因为下面这个配置必须给它依赖注入唯一的 DataSource ,有多个DataSource 就不行。
4、两个bean的执行顺序。
WriterTemplate1 这个bean是把数据输出数据库表中去
WriterTemplate2 这个bean是把数据输出到指定文件中去
5、WriterTemplate1 这个bean是把数据输出数据库表中去
这个starter组件中的处理类中的配置的WriterTemplate1 这个bean,传入的 DataSource ,应该是 引入这个starter组件的 CustomFrameTest 项目中的yml配置文件中配置的数据库连接。
因为这个数据库连接在项目中只有这一个,应该就算是唯一的。
这个bean的dataSource有且仅有一个,还理解的不够透彻,先把想法记下来。
6、WriterTemplate2 这个bean 的数据的获取,这个bean获取到引入这个starter组件的项目的yml配置文件中的要输出到指定文件中的dest和charset属性。
CustomFrameTest:普通测试项目
3、第3步:
创建一个项目,来使用这个 starter 组件,进行测试。
在启动类中通过类型获取 WriterTemplate 这个bean ,然后调用 write 方法,把要输出的信息作为参数传递过去,然后是输出到数据库还是输出到文件,
就是通过 starter组件+MyCustomFrame框架里面的逻辑来实现了。
从pom文件中可以看出,这个项目引入了starter组件,然后这个starter里面又包含了自定义的第三方框架MyCustomFrame
可以看出这个项目只有启动类和yml配置类,没有写任何逻辑代码,测试是输出到文件还是数据库的代码,都是通过引入 starter 组件来实现的。而starter组件是不需要运行的,是安装在maven库的。
测试:
输出到文件:
这个项目没有连接到数据库,所以是把信息输出到指定文件中去
输出到数据库:
如果要输出到数据库,那么就要有数据库的连接。需要创建对应的 customframe 数据库,然后再pom.xml 文件中添加数据库的连接的依赖。
可以看出因为添加了连接数据库的 jdbc 依赖,所以就是走输出信息到数据库逻辑去了。
打印的文字出自第三方框架这个类
======================================
详细代码:
MyCustomFrame框架
自定义第三方框架MyCustomFrame 里面的 WriterTemplate 工具类代码
package cn.ljh.myCustomFrame;
import lombok.extern.slf4j.Slf4j;
import javax.sql.DataSource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;
/*
* 这个类的作用:
* 如果我们这个项目有连到数据库,那就把我们要输出的信息输出到数据库,
* 如果没有连数据库,那么就把信息输出到文件
*
* 是一个工具类
*/
@Slf4j
public class WriterTemplate
{
private final DataSource dataSource;
private Connection conn;
private final File dest;
private final Charset charset;
private RandomAccessFile raf;
public WriterTemplate(DataSource dataSource) throws SQLException
{
this.dataSource = dataSource;
this.dest = null;
this.charset = null;
if (Objects.nonNull(this.dataSource))
{
log.debug("==========获取数据库连接==========");
this.conn = dataSource.getConnection();
}
}
public WriterTemplate(File dest, Charset charset) throws FileNotFoundException
{
this.dest = dest;
this.charset = charset;
this.dataSource = null;
this.raf = new RandomAccessFile(this.dest, "rw");
}
public void write(String message) throws IOException, SQLException
{
if (Objects.nonNull(this.conn))
{
// 查询当前数据库的customFrame_message表是否存在
ResultSet rs = conn.getMetaData().getTables(conn.getCatalog(), null,
"customFrame_message", null);
// 如果customFrame_message表不存在
if (!rs.next())
{
log.debug("~~~~~~创建customFrame_message表~~~~~~");
conn.createStatement().execute("create table customFrame_message " +
"(id int primary key auto_increment, message_text text)");
rs.close();
}
log.debug("~~~~~~输出到数据表~~~~~~");
// 插入要输出的字符串
conn.createStatement().executeUpdate("insert into " +
"customFrame_message values (null, '" + message + "')");
}
else
{
log.debug("~~~~~~输出到文件~~~~~~");
// 输出到文件
raf.seek(this.dest.length());
raf.write((message + "\n").getBytes(this.charset));
}
}
// 关闭资源
public void close() throws SQLException, IOException
{
if (this.conn != null)
{
this.conn.close();
}
if (this.raf != null)
{
this.raf.close();
}
}
}
自定义第三方框架MyCustomFrame 里面的 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.ljh.customframe</groupId>
<artifactId>MyCustomFrame</artifactId>
<version>1.0.0</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.6</version>
</dependency>
</dependencies>
mycustomstarter 组件
mycustomstarter 组件的 FrameAutoConfiguration 配置类代码
package cn.ljh.mycustomstarter;
import cn.ljh.myCustomFrame.WriterTemplate;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.io.File;
import java.io.FileNotFoundException;
import java.nio.charset.Charset;
import java.sql.SQLException;
//这个配置类的作用就是用来整合第三方框架MyCustomFrame时,所需要的一些配置
// 用 @Configuration 修饰的类就是配置类
@Configuration
//启用这个 FrameProperties 属性处理类,不然属性处理类的@ConfigurationProperties注解会爆红
@EnableConfigurationProperties(value = FrameProperties.class)
//WriterTemplate类 代表了要整合的框架(WriterTemplate)的核心API,
//这个配置类要想生效,需要有这个WriterTemplate类存在
//这个WriterTemplate类是存在第三方框架MyCustomFrame里面的,所以需要引入第三方框架的依赖
//因为有了WriterTemplate这个类,所以 这个 FrameAutoConfiguration 配置类就能生效了,这就是这个类的生效过程
@ConditionalOnClass(WriterTemplate.class)
//指定这个自动配置类需要位于DataSourceAutoConfiguration之后生效
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class FrameAutoConfiguration {
/*
* 使用 条件注解 和 @Bean 注解在容器中定义整合第三方框架(WriterTemplate)所需要的组件
* 项目要整合第三方框架(MyCustomFrame),MyCustomFrame框架所需要的核心组件就是 WriterTemplate
* 因此这个自动配置类就是负责在容器中自动配置 WriterTemplate
*/
//FrameProperties 属性处理类,该属性处理类负责读取整合 MyCustomFrame 框架相关的配置信息
private final FrameProperties frameProperties;
//构造器
public FrameAutoConfiguration(FrameProperties frameProperties) {
this.frameProperties = frameProperties;
}
//配置Bean
//此处需要传入 DataSource 来构建这个 writerTemplate,因此这个自动配置类需要在 DataSource 创建出来之后运行,
//因此应该让这个自动配置类位于 DataSourceAutoConfiguration 之后生效
//这个bean是如果引入starter组件的项目有连接数据库的配置,那么就会返回这个bean
@Bean
//只有当项目中 没有 WriterTemplate 这个bean时,才自动为项目配置这个Bean,
//因为如果项目中有开发人员自己自定义开发 WriterTemplate 这个bean,那我们肯定不需要再额外自动配置 WriterTemplate 这个bean
@ConditionalOnMissingBean
//只有当spring容器中有且仅有一个 DataSource Bean 的时候,下面这个配置才生效
@ConditionalOnSingleCandidate(DataSource.class)
public WriterTemplate writerTemplate1(DataSource dataSource) throws SQLException {
return new WriterTemplate(dataSource);
}
//这个bean是如果引入starter组件的项目没有连接数据库的配置,那么就会返回这个bean
//这个bean主要是获取到引入该starter组件的项目里面的配置文件里面的dest属性和charset属性
//具体是如何输出到数据库或是文件的逻辑,是在第三方框架的WriterTemplate类实现的
@Bean
@ConditionalOnMissingBean
public WriterTemplate writerTemplate2() throws FileNotFoundException {
//创建文件
File file = new File(frameProperties.getDest());
//指定字符
Charset charset = Charset.forName(frameProperties.getCharset());
return new WriterTemplate(file, charset);
}
}
mycustomstarter 组件的 FrameProperties 属性处理类代码
package cn.ljh.mycustomstarter;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
//@ConfigurationProperties 这个注解修饰的类就是属性处理类
//指定该属性处理类只读取配置文件中,以 cn.ljh.frame 开头的配置属性
@ConfigurationProperties(prefix = FrameProperties.FRAME_PREFIX)
@Data
public class FrameProperties {
public static final String FRAME_PREFIX = "cn.ljh.frame";
//定义一些常用信息
private String dest;
private String charset;
}
mycustomstarter 组件的 spring.factories 配置文件
# 注册自动配置类 FrameAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.ljh.mycustomstarter.FrameAutoConfiguration
mycustomstarter 组件的 pom.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 这个名称是符合springboot官方定义starter名的规格 -->
<groupId>cn.ljh.mycustomstarter</groupId>
<artifactId>mycustomframe-spring-boot-starter</artifactId>
<version>1.0.0</version>
<name>mycustomstarter</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<!--
因为 mycustomstarter 这个 starter 组件有添加这个 第三方框架MyCustomFrame 的依赖,
因此在以后的开发中,只需要在项目中添加这个 mycustomstarter 组件 ,
这个starter组件就会帮我们添加被整合的框架 ->第三方框架 MyCustomFrame
-->
<dependency>
<groupId>cn.ljh.customframe</groupId>
<artifactId>MyCustomFrame</artifactId>
<version>1.0.0</version>
</dependency>
<!-- 属性处理类需要的依赖,用来解析配置文件的属性 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
CustomFrameTest
CustomFrameTest 项目里面的pom.xml依赖文章来源:https://www.toymoban.com/news/detail-656879.html
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.ljh</groupId>
<artifactId>CustomFrameTest</artifactId>
<version>1.0.0</version>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<!-- 添加mysql的驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 添加自定义的starter组件 -->
<dependency>
<groupId>cn.ljh.mycustomstarter</groupId>
<artifactId>mycustomframe-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
文章来源地址https://www.toymoban.com/news/detail-656879.html
到了这里,关于27、springboot自定义第三方框架和Starter组件及其测试完整版的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!