likes
comments
collection
share

Spring Boot 自定义组件实践

作者站长头像
站长
· 阅读数 86

定义 starter

首先需要定义我们自己的 starter

导入依赖和 artifactId定义

这里说下 artifactId的命名问题,Spring 官方 Starter 通常命名为 spring-boot-starter-{name} 如 spring-boot-starter-web,Spring 官方建议非官方 Starter 命名应遵循 {name}-spring-boot-starter 的格式。举个例子:mybatis-spring-boot-starterdubbo-spring-boot-starter.

<modelVersion>4.0.0</modelVersion>
<groupId>com.ssm</groupId>
<artifactId>example-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>

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

添加配置

resources/META-INF下创建 spring.factories 文件。参考如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ssm.xyz.config.ExampleAutoConfigure

spring.factories 在哪里读取的呢?大家可能有这个问题。

在我们的 Spring-Boot 的启动类上定义了@SpringBootApplication注解包含了@EnableAutoConfiguration 然后这个注解内部包含

@Import({AutoConfigurationImportSelector.class}) 通过这个AutoConfigurationImportSelector读取了所有依赖 jar 的 spring.factories文件配置的注解类。

关键点就是@Import这个注解。这个注解可以导入selector,也可以直接导入configruration类。

业务实现

说一实现,我们通自定义 ExampleService可以对字符串进行统一的 wrap操作为字符串添加一个固定的前缀,其实本质就是替换一个 StringUtil 工具方法。

public class StringUtil {
  public static String wrap(String str) {return "PrefixXXX" + str;}
}

下面我们开始组件定义方式的功能实现, ExampleAutoConfigure用来初始化组件内的 Bean ExampleServicePropertiesExampleService:

package com.ssm.xyz.config;

@Configuration
@ConditionalOnClass(ExampleService.class)
@EnableConfigurationProperties(ExampleServiceProperties.class)
public class ExampleAutoConfigure {

    @Autowired
    private ExampleServiceProperties properties;

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "example.service",value = "enabled",havingValue = "true")
    ExampleService exampleService (){
        return  new ExampleService(properties.getPrefix());
    }

}

配置文件接受,这里使用的是 @ConfigurationProperties方法读取配置,会去读取 example.service前缀的配置如果通过属性文件设置的话,我们可以配置 example.service.prefix = zhangsan hello

@ConfigurationProperties("example.service")
public class ExampleServiceProperties {

    private String prefix;
}

ExampleService#wrap() 本方法是核心代码,主要是实现组件的核心逻辑,如果后续其他业务,可以修改这个 wrap 方法

public class ExampleService {

    private String prefix;

    public ExampleService(String prefix {
        this.prefix = prefix;
    }

    public String wrap(String word) {
        return prefix + word + suffix;
    }
}

使用 starter

上面我们完成了自定义 starter 的开发,下面我们只需要导入我们的 starter 然后我们 Spring-Boot 在启动的时候就会自动会我们读取配置,然后进行初始化,注入到我们使用的地方。在业务开发的时候我们就可以直接使用。

导入组件依赖

使用 starter 之前需要导入依赖(导入组件之前需要提前对定义的组件进行 deploy 不然可能出现无法以依赖的问题,这个也是我们经常容易犯的一个错误):

<dependency>
  <groupId>com.ssm</groupId>
  <artifactId>example-spring-boot-starter</artifactId>
  <version>1.0-SNAPSHOT</version>
</dependency>

测试类文件

为了方便和简单,我就把 Controller 和 Application 放在一起,我们对外暴露一个 /input 接口, 对传入的 word 进行 wrap 。代码操作如下:

@SpringBootApplication
@RestController
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Autowired
    private ExampleService exampleService;

    @GetMapping("/input")
    public String input(@RequestParam("word") String word){
        return exampleService.wrap(word);
    }

}

访问地址:http://127.0.0.1:8080/input?word=word! 输出结果

hello word!

Spring Boot 自定义组件总结

组件定义权衡的问题,如果我们是一个本地运行程序比如:通过 IP库逆向解析为地址信息、或者发邮件消息推送等组件。个人觉得可以把这些能力封装成一个服务,通过封装 client-sarter 方式提供给业务方使用。这样可以让服务划分指责更加清晰,而且保证提供组件不会增加原始服务的运行负担,保证微服务

还有一个问题就是组件粒度的问题,这个需要结合具体的业务场景和需求,感觉是一个仁者见仁智者见智问题。

参考文档

转载自:https://juejin.cn/post/7057520086810116127
评论
请登录