We know that SpringBoot Starter is also the starter. It is a major advantage of SpringBoot componentization. Based on this idea, based on this idea, SpringBoot has become very powerful, and the official provides us with many out-of-the-box starters.
Spring Boot Starter is an important feature of Spring Boot, which has the following advantages:
-
Dependency management : Starter automatically handles the dependencies of the project, so that developers do not need to manually add and manage each dependency.
-
Automatic configuration : Starter provides an automatic configuration method, which can automatically configure Spring applications according to your classpath and the properties you define.
-
Simplified development : By providing starters of various services (such as database, security, cache, etc.), the development process is greatly simplified.
-
Reduce Boilerplate Code : Thanks to Starter's automatic configuration and dependency management, developers can focus on business logic rather than configuration and infrastructure code.
-
Rapid Prototyping : Use Starter to quickly create working prototypes.
-
Easy to understand and use : One of the design goals of Spring Boot Starter is to allow non-professional developers to get started quickly.
-
Community support : In addition to the officially provided Starters, there are also a large number of community-provided Starters that can meet various specific needs.
Now I will teach you how to package your own starter to make your own springboot components. Of course, you can also publish your own starter to the maven central warehouse for everyone to use.
Analysis of SpringBoot's own Starter
Let's take the automatic loading of WebMvcAutoConfiguration as an example
There is a requirement for automatic configuration classes to be able to be loaded. The result of source code analysis is that the following configuration needs to be done in \META-INF\spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
In this way, when SpringBoot is started, it will find our introduction, the starter finds \META-INF\spring.factories
the property file, finds the class path that needs to be automatically loaded and configured, and then automatically injects it into the Spring IOC container for us, and we can use it directly in the project.
The automatic loading here also depends on some annotations such as:
@Configuration // 指定这个类是个配置类
@ConditionalOnXXX // 在指定条件成立的情况下自动配置类生效
@AutoConfigureOrder //配置类顺序
@AutoConfigureAfter // 在哪个配置类之后
@Bean //给容器中添加组件
@ConfigurationProperties //结合相关的XXXProperties类 来绑定相关的配置
@EnableConfigurationProperties // 让XXXProperties加入到容器中,别人就可以自动装配
Customize your own starter
After analyzing SpringBoot's official starter, we customize our own starter, (we copy it)
Naming conventions
configuration tips
If in the custom property file, IDEA smart prompt needs to be introduced
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
define starter
Here I take a SpringBoot starter that summarizes the project package since I encapsulated and summarized my work as an example.
<dependency>
<groupId>cn.soboys</groupId>
<artifactId>rest-api-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
It is the start packaged by myself. The central repository has been released.
The current updated version 1.3.0 features are as follows
- Support one-click configuration to customize RestFull API uniform format return
- Support RestFull API error internationalization
- Support global exception handling, global parameter verification processing
- Encapsulation of business error assertion tools, following the principle of returning errors first
- redis working package. Support all key operation tools
- RestTemplate encapsulates POST, GET request tool
- Log integration. Customize the log path, classify according to the log level, support compression and file size segmentation. display by time
- The tool library integrates lombok, hutool, commons-lang3, and guava. No need to import them individually
- Integrated mybatisPlus one-click code generation
rest-api-spring-boot-starter
Warehouse address
github
- Custom configuration properties file
rest-api:
enabled: false
logging:
path: ./logs
i18n:
# 若前端无header传参则返回中文信息
i18n-header: Lang
default-lang: cn
message:
# admin
internal_server_error:
en: Internal Server Error
cn: 系统错误
not_found:
en: Not Found
cn: 请求资源不存在
- Define property configuration class
package cn.soboys.restapispringbootstarter.i18n;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.Map;
import java.util.Optional;
/**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/6/26 11:55
* @webSite https://github.com/coder-amiao
*/
//@PropertySource(value = "classpath:i18n.yaml", factory = YamlPropertySourceFactory.class)
@Configuration
@ConfigurationProperties(prefix = "rest-api.i18n")
@Data
public class I18NMessage {
/**
* message-key:<lang:message>
*/
private Map<String, Map<String, String>> message;
/**
* Default language setting (Default "cn").
*/
private String defaultLang = "cn";
private String i18nHeader = "Lang";
/**
* get i18n message
*
* @param key
* @param language
* @return
*/
public String message(I18NKey key, String language) {
return Optional.ofNullable(message.get(key.key()))
.map(map -> map.get(language == null ? defaultLang : language))
.orElse(key.key());
}
/**
* get i18n message
*
* @param key
* @param language
* @return
*/
public String message(String key, String language) {
return Optional.ofNullable(message.get(key))
.map(map -> map.get(language == null ? defaultLang : language))
.orElse(key);
}
}
- Define BeanAutoConfiguration to automatically load configuration classes
package cn.soboys.restapispringbootstarter.config;
import cn.soboys.restapispringbootstarter.ApplicationRunner;
import cn.soboys.restapispringbootstarter.ExceptionHandler;
import cn.soboys.restapispringbootstarter.ResultHandler;
import cn.soboys.restapispringbootstarter.aop.LimitAspect;
import cn.soboys.restapispringbootstarter.i18n.I18NMessage;
import cn.soboys.restapispringbootstarter.utils.RedisTempUtil;
import cn.soboys.restapispringbootstarter.utils.RestFulTemp;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.List;
/**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/6/27 11:36
* @webSite https://github.com/coder-amiao
*/
@Configuration
@ConditionalOnProperty(name = "rest-api.enabled", havingValue = "true")
public class BeanAutoConfiguration {
@Bean
public I18NMessage i18NMessage() {
return new I18NMessage();
}
@Bean
public ResultHandler resultHandler() {
return new ResultHandler();
}
@Bean
public ExceptionHandler exceptionHandler() {
return new ExceptionHandler();
}
@Bean
public StartupApplicationListener startupApplicationListener() {
return new StartupApplicationListener();
}
@Bean
public RestApiProperties restApiProperties() {
return new RestApiProperties();
}
@Bean
public RestApiProperties.LoggingProperties loggingProperties(RestApiProperties restApiProperties) {
return restApiProperties.new LoggingProperties();
}
@Bean
public ApplicationRunner applicationRunner() {
return new ApplicationRunner();
}
/**
* restTemplate 自动注入
*/
@Configuration
@ConditionalOnProperty(name = "rest-api.enabled", havingValue = "true")
class RestTemplateConfig {
/**
* 第三方请求要求的默认编码
*/
private final Charset thirdRequest = Charset.forName("utf-8");
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 处理请求中文乱码问题
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
}
if (messageConverter instanceof MappingJackson2HttpMessageConverter) {
((MappingJackson2HttpMessageConverter) messageConverter).setDefaultCharset(thirdRequest);
}
if (messageConverter instanceof AllEncompassingFormHttpMessageConverter) {
((AllEncompassingFormHttpMessageConverter) messageConverter).setCharset(thirdRequest);
}
}
return restTemplate;
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setReadTimeout(5000);
return factory;
}
@Bean
public RestFulTemp restFulTemp() {
return new RestFulTemp();
}
}
}
- Autowiring
in project
spring.factories
Configure yourself to load the configuration class
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.soboys.restapispringbootstarter.config.BeanAutoConfiguration,\
cn.soboys.restapispringbootstarter.config.BeanAutoConfiguration.RestTemplateConfig,\
cn.soboys.restapispringbootstarter.utils.RedisTempUtil\
Expanding thinking, we can see that many of the SpringBoot official staters are similar to
@Enablexxx
annotations.
How to achieve this. Myrest-api-spring-boot-starter
1.3.0 has already been implemented, and all functions can be used directly in the startup class or configuration class without configuring a line in application.propertiesEnableRestFullApi
Perfect document use can see me
SpringBoot defines an elegant and globally unified Restful API response framework Ends the Sprinkle Chapter Encapsulates the starter component
This article
At this point, the definition of the starter is finished, and the next step is to package and publish it to the maven central warehouse .
I will continue to share in the next article
Leave your thoughts and pay attention to public programmers for three hours
Continue to output high-quality content and hope to bring you a little inspiration and help