自定义starter

首先、需要确定自定义一个starter需要些什么?

  1. 场景启动器:该项目没有任何的源代码,只是作为引用自定义starter的启动器,
    既之后其他的项目需要使用自定义的starter可以直接通过该启动器导入依赖即可
  2. 自定义配置项目:需要实现的自定义配置类业务逻辑代码,在该项目中编写

简单理解:场景启动器就是一个统一管理自定义starter的仓库,自定义配置项目就是starter导入的依赖

自定starter的具体步骤

1. 创建一个空项目:

spring boot 实现 自定义 starter demo 自定义一个springboot starter_spring


spring boot 实现 自定义 starter demo 自定义一个springboot starter_maven_02


spring boot 实现 自定义 starter demo 自定义一个springboot starter_spring_03


到这里之后,需要创建两个项目,一个是springboot项目(自定义配置项目),另一个是maven项目(场景启动器);这两个项目的创建就不必在演示,下面的两张图需要重复一次,因为要创建两个项目

spring boot 实现 自定义 starter demo 自定义一个springboot starter_自定义_04


spring boot 实现 自定义 starter demo 自定义一个springboot starter_maven_05


创建项目完成之后:

项目如下:

spring boot 实现 自定义 starter demo 自定义一个springboot starter_maven_06


2. 首先进入场景启动器中:既第一个项目(Maven项目)
3. 主要是操作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>org.example</groupId>
    <artifactId>atguigu-hello-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--引入自定义配置的项目,既引入自定义的starter的依赖-->
    <dependencies>
        <dependency>
            <groupId>com.springbootCustmer</groupId>
            <artifactId>atguigu-hello-spring-boot-starter-autoconfigure</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <!--对应自动配置包中的pom.xml的如下代码:
			<groupId>com.springbootCustmer</groupId>
			<artifactId>atguigu-hello-spring-boot-starter-autoconfigure</artifactId>
			<version>0.0.1-SNAPSHOT</version>
			-->
        </dependency>
    </dependencies>
</project>

4. 操作自动配置的项目:既springboot项目(第二个)
5. 操作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.5.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.springbootCustmer</groupId>
	<artifactId>atguigu-hello-spring-boot-starter-autoconfigure</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>atguigu-hello-spring-boot-starter-autoconfigure</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
	</dependencies>
</project>

6. 编写业务逻辑代码:
比如,我们需要一个这样的业务组件:有一个service,service中有一个方法sayHello,需要传递一个参数name(String),sayHello会返回一个欢迎语(前缀 + name + 后缀),前缀和后缀需要从配置文件application中获取。

7. 创建一个service:

spring boot 实现 自定义 starter demo 自定义一个springboot starter_spring boot_07


HelloService中的代码如下:

package com.springbootcustmer.hello.service;

import com.springbootcustmer.hello.bean.HelloProperties;
import org.springframework.beans.factory.annotation.Autowired;

//自定义业务逻辑场景:自动配置starter场景
//注意:不要把该类放入容器中,通过配置类来放,因为在配置类种可以根据条件判断是否将该组件放入容器中
public class HelloService {
	//前缀和后缀存储在HelloProperties类中(bean)
    @Autowired //从容器中自动获取
    HelloProperties helloProperties; //该类中的属性是通过配置文件来设置的

    public String SayHello(String name){
        return helloProperties.getPrefix() + ":" + name + "------>" + helloProperties.getSuffix();
    }
}

8. 由Helloservice的代码可知,我们需要一格bean类,来存储前缀和后缀,且值是从application中获取的(自动绑定配置)

spring boot 实现 自定义 starter demo 自定义一个springboot starter_maven_08


HelloProperties中代码如下:

package com.springbootcustmer.hello.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

//指定配置文件中的前缀,通过前缀获取指定的值,赋予下面的属性
@ConfigurationProperties("sheng.hello") 
public class HelloProperties {
    private String prefix;
    private String suffix;

    public String getPrefix() {
        return prefix;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public String getSuffix() {
        return suffix;
    }

    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
}

9. 我们还需要一个配置类,用来将我们的业务组件放入spring容器中,创建一个配置类

spring boot 实现 自定义 starter demo 自定义一个springboot starter_spring_09


HelloServiceAutoConfiguration中的代码如下:

package com.springbootcustmer.hello.config;

import com.springbootcustmer.hello.bean.HelloProperties;
import com.springbootcustmer.hello.service.HelloService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//自动配置类
@Configuration
@EnableConfigurationProperties(HelloProperties.class)  //开启某个类的自动配置绑定功能,既属性可以在配置文件中设置,且把该类放入容器中
public class HelloServiceAutoConfiguration {
    //这个注解的意义是:在有在容器中没有HelloService这个组件我们才向容器中注入
    //为了避免用户在自己的项目中创建了一个HelloService同名的组件而出现冲突
    //遵循springboot的规则:用户定义大于约定
    @ConditionalOnMissingBean(HelloService.class)
    @Bean  //将该方法作为组件放入容器中
    public HelloService HelloService(){
        HelloService helloService = new HelloService();
        return helloService;
    }
}

如此我们的业务逻辑组件代码编写完成,那么在其他项目中配置场景启动器导入该业务组件依赖,就会自动配置呢?

答案是否定的,不能,为什么,因为在springboot的自动配置原理中,有这么一个文件spring.factories,这个文件中指定了在项目启动时需要加载哪些组件

spring boot 实现 自定义 starter demo 自定义一个springboot starter_maven_10

10. 在静态资源路径(resource)下创建spring.factories文件:

spring boot 实现 自定义 starter demo 自定义一个springboot starter_自定义_11


11. 完成以上操作后,我们需要把自动配置项目打包并放入本地仓库中,因为我们导入依赖,导入的都是包:

注意:自动配置项目和场景启动器都需要打包,如果以后更改了业务逻辑,只需要重新打包自动配置项目且放入本地仓库中即可

spring boot 实现 自定义 starter demo 自定义一个springboot starter_spring boot_12


12. 进行如上操作之后,自定义starter便完成了

测试自定义starter

1. 创建一个springboot项目
2. 在pom.xml中导入自定义starter的依赖

代码如下:

<dependency>
    <groupId>org.example</groupId>
    <artifactId>atguigu-hello-spring-boot-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

3. 查看是否导入了对应的依赖(包)

spring boot 实现 自定义 starter demo 自定义一个springboot starter_java_13


4. 编写一个controller测试HelloService组件是否可用:

spring boot 实现 自定义 starter demo 自定义一个springboot starter_maven_14


5. 在application中配置前缀和后缀:

spring boot 实现 自定义 starter demo 自定义一个springboot starter_spring_15


6. 在浏览器中访问接口:

spring boot 实现 自定义 starter demo 自定义一个springboot starter_spring_16


前缀和后缀与我们配置的完全一致,由此可得自定义starter成功。

从application中自动绑定的属性值中文乱码

解决方法:

spring boot 实现 自定义 starter demo 自定义一个springboot starter_maven_17


spring boot 实现 自定义 starter demo 自定义一个springboot starter_自定义_18


重新创建application文件即可