前言

今天看到了一道面试题,如何实现一个自定义的 SpringBoot starter,或者说,SpringBoot 如何加载我们自己的 jar 包?其实,仔细想想本质是考察 SpringBoot 的自动配置原理,了解了其自动配置原理即可实现 SpringBoot 自定义 starter

SpringBoot 自动配置原理:https://blog.csdn.net/weixin_38192427/article/details/115178359

SpringBoot 自定义 starter

创建多模块项目

SpringBoot 的官方 starter 命名方式为 spring-boot-starter-xxxspring-boot-starter-quartzSpringBoot 官方建议第三方 starter 的命名方式一般为 xxx-spring-boot-starter

创建一个 custom-spring-boot-starter 项目,项目下面新建两个模块

  • hello-spring-boot-starter(场景启动器,普通 Maven 工程)
  • hello-spring-boot-starter-autoconfigure(自动配置包,需用到 Spring Initializr 创建的 Maven 工程)

项目编码

custom-spring-boot-starter 父模块 Maven 依赖

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.9.RELEASE</version>
	<relativePath></relativePath>
</parent>

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-configuration-processor</artifactId>
	</dependency>
   	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-actuator-autoconfigure</artifactId>
	</dependency>
</dependencies>

hello-spring-boot-starter-autoconfigure 子模块

HelloProperties 属性映射类

@ConfigurationProperties(prefix = "hello")
public class HelloProperties {

    private String username;

    private String password;

    // 省略 get/set 方法......
}
  • @ConfigurationProperties:负责将配置文件里的配置信息绑定映射到实体 bean

HelloService 业务逻辑类

public class HelloService {

    private String username;

    private String password;

    public String haloHello() {
        return "用户名为:" + username + ">>>" + "密码为:" + password;
    }

    // 省略 get/set 方法......
}

HelloServiceAutoConfiguration 配置类

@Configuration
@EnableConfigurationProperties(value = HelloProperties.class)
@ConditionalOnClass(value = HelloService.class)
@ConditionalOnProperty(prefix = "hello", value = "enabled", matchIfMissing = true)
public class HelloServiceAutoConfiguration {

    @Autowired
    private HelloProperties helloProperties;

    @Bean
    @ConditionalOnMissingBean(value = HelloService.class)
    public HelloService helloService() {
        System.out.println("Execute Create New Bean");
        HelloService helloService = new HelloService();
        helloService.setUsername(helloProperties.getUsername());
        helloService.setPassword(helloProperties.getPassword());
        return helloService;
    }
}
  • @EnableConfigurationProperties(value = HelloProperties.class):负责将指定的 bean 注册到Spring 容器中
  • @ConditionalOnProperty(prefix = "hello", value = "enabled", matchIfMissing = true):当配置文件中 hello.enabled = true 时进行自动配置,如果没有设置此值就默认使用 matchIfMissing 指定的值

@Conditional 条件注解

  • @ConditionalOnBean:当给定的 bean 存在时,则实例化当前 bean
  • @ConditionalOnMissingBean:当给定的 bean 不存在时,则实例化当前 bean
  • @ConditionalOnClass:当给定的类名在类路径上存在时,则实例化当前 bean
  • @ConditionalOnMissingClass:当给定的类名在类路径上不存在时,则实例化当前 bean
  • @ConditionalOnExpression:当表达式为 true 的时候,才会实例化一个 bean

创建 spring.factories 文件

在这里插入图片描述
spring.factories 文件内容如下

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  org.example.config.HelloServiceAutoConfiguration
  • 如果有多个自动配置类,则用,隔开
  • ,后不要有空格之类的符号,就只写该类的全路径,不然会出现无法找到此 bean 的错误

Maven 打包

Maven 插件,将该工程 install 到本地 Maven 仓库。记得要把 hello-spring-boot-starter-autoconfiguretest 包删除

自定义 starter 的使用

Maven 依赖

<dependencies>
	<!--引入自定义的starter-->
	<dependency>
		<groupId>org.example</groupId>
       	<artifactId>hello-spring-boot-starter-autoconfigure</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>
   	<!--lombok 插件-->
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<version>1.18.12</version>
		<scope>provided</scope>
	</dependency>
</dependencies>

application.properties 配置文件

在项目 hello-spring-boot-starter 中添加配置文件 application.properties

server.port=8080

hello.username=xiaoming
hello.password=123123

HelloController 测试接口类

@Slf4j
@Controller
public class HelloController {

    @Autowired
    private HelloService helloService;

    @Autowired
    private HelloProperties helloProperties;

    @GetMapping(path = "/hello")
    @ResponseBody
    public String sayHello() {
        log.info("用户名为:" + helloProperties.getUsername());
        log.info("密码为:" + helloProperties.getPassword());
        return helloService.haloHello();
    }
}

测试结果

控制台结果

在这里插入图片描述
postman 接口返回结果

在这里插入图片描述


版权声明:本文为weixin_38192427原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_38192427/article/details/123215170