← Назад к вопросам

Как создать собственный Spring Boot Starter?

3.0 Senior🔥 21 комментариев
#Spring Boot и Spring Data

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Создание собственного Spring Boot Starter

Spring Boot Starter - это удобный способ упаковать и переиспользовать готовый функционал в разных проектах. Рассмотрю пошаговый процесс создания.

Структура Starter-а

Spring Boot Starter состоит из двух частей:

  1. spring-boot-starter-{name} - POM файл с зависимостями
  2. spring-boot-{name}-autoconfigure - автоконфигурация и основной код

Шаг 1: Создание автоконфигурационного модуля

Создай Maven модуль spring-boot-elasticsearch-autoconfigure:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>spring-boot-elasticsearch-autoconfigure</artifactId>
    <version>1.0.0</version>
    <name>Spring Boot Elasticsearch AutoConfigure</name>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.0</version>
        <relativePath/>
    </parent>
    
    <dependencies>
        <!-- Spring Boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        
        <!-- Auto-configuration support -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        
        <!-- Conditional compilation support -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- Your library -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.17.0</version>
        </dependency>
    </dependencies>
</project>

Шаг 2: Создание Properties класса

package com.example.elasticsearch;

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

@Component
@ConfigurationProperties(prefix = "app.elasticsearch")
public class ElasticsearchProperties {
    
    private String host = "localhost";
    private int port = 9200;
    private String protocol = "http";
    private String username;
    private String password;
    private long connectionTimeout = 5000;
    private long socketTimeout = 30000;
    
    // Getters and setters
    public String getHost() { return host; }
    public void setHost(String host) { this.host = host; }
    
    public int getPort() { return port; }
    public void setPort(int port) { this.port = port; }
    
    public String getProtocol() { return protocol; }
    public void setProtocol(String protocol) { this.protocol = protocol; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    
    public long getConnectionTimeout() { return connectionTimeout; }
    public void setConnectionTimeout(long connectionTimeout) { 
        this.connectionTimeout = connectionTimeout; 
    }
    
    public long getSocketTimeout() { return socketTimeout; }
    public void setSocketTimeout(long socketTimeout) { 
        this.socketTimeout = socketTimeout; 
    }
}

Шаг 3: Создание AutoConfiguration класса

package com.example.elasticsearch;

import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

@AutoConfiguration
@ConditionalOnClass({RestHighLevelClient.class})
@EnableConfigurationProperties(ElasticsearchProperties.class)
public class ElasticsearchAutoConfiguration {
    
    private final ElasticsearchProperties properties;
    
    public ElasticsearchAutoConfiguration(ElasticsearchProperties properties) {
        this.properties = properties;
    }
    
    @Bean
    @ConditionalOnMissingBean
    public RestHighLevelClient restHighLevelClient() {
        RestClientBuilder builder = RestClient.builder(
            new HttpHost(
                properties.getHost(),
                properties.getPort(),
                properties.getProtocol()
            )
        );
        
        // Добавить authentication если указаны credentials
        if (properties.getUsername() != null) {
            BasicCredentialsProvider credentialsProvider = 
                new BasicCredentialsProvider();
            credentialsProvider.setCredentials(
                AuthScope.ANY,
                new UsernamePasswordCredentials(
                    properties.getUsername(),
                    properties.getPassword()
                )
            );
            
            builder.setHttpClientConfigCallback(httpClientBuilder ->
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
            );
        }
        
        // Установить timeouts
        builder.setRequestConfigCallback(requestConfigBuilder ->
            requestConfigBuilder
                .setConnectTimeout((int) properties.getConnectionTimeout())
                .setSocketTimeout((int) properties.getSocketTimeout())
        );
        
        return new RestHighLevelClient(builder);
    }
    
    @Bean
    @ConditionalOnMissingBean
    public ElasticsearchTemplate elasticsearchTemplate(
            RestHighLevelClient client) {
        return new ElasticsearchTemplate(client);
    }
}

Шаг 4: Создание сервиса

package com.example.elasticsearch;

import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.springframework.stereotype.Service;

@Service
public class ElasticsearchTemplate {
    
    private final RestHighLevelClient client;
    
    public ElasticsearchTemplate(RestHighLevelClient client) {
        this.client = client;
    }
    
    public void indexDocument(String index, String id, String document) 
            throws Exception {
        IndexRequest request = new IndexRequest(index)
            .id(id)
            .source(document, org.elasticsearch.common.xcontent.XContentType.JSON);
        
        client.index(request, RequestOptions.DEFAULT);
    }
    
    public RestHighLevelClient getClient() {
        return client;
    }
}

Шаг 5: Регистрация AutoConfiguration

Создай файл src/main/resources/META-INF/spring.factories (или spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports):

Spring Boot 2.7+:

com.example.elasticsearch.ElasticsearchAutoConfiguration

Spring Boot < 2.7:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.elasticsearch.ElasticsearchAutoConfiguration

Шаг 6: Создание Starter POM

Создай отдельный модуль spring-boot-starter-elasticsearch:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>spring-boot-starter-elasticsearch</artifactId>
    <version>1.0.0</version>
    <name>Spring Boot Elasticsearch Starter</name>
    <description>Spring Boot Starter for Elasticsearch</description>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.0</version>
        <relativePath/>
    </parent>
    
    <dependencies>
        <!-- Autoconfigure module -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>spring-boot-elasticsearch-autoconfigure</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
</project>

Шаг 7: Использование Starter в другом проекте

<dependency>
    <groupId>com.example</groupId>
    <artifactId>spring-boot-starter-elasticsearch</artifactId>
    <version>1.0.0</version>
</dependency>
# application.yml
app:
  elasticsearch:
    host: elasticsearch.local
    port: 9200
    protocol: https
    username: elastic
    password: password123
    connectionTimeout: 10000
    socketTimeout: 60000
@RestController
@RequestMapping("/api")
public class DocumentController {
    
    private final ElasticsearchTemplate template;
    
    public DocumentController(ElasticsearchTemplate template) {
        this.template = template;
    }
    
    @PostMapping("/documents")
    public ResponseEntity<Void> createDocument(
            @RequestParam String index,
            @RequestParam String id,
            @RequestBody String content) throws Exception {
        
        template.indexDocument(index, id, content);
        return ResponseEntity.created(URI.create("/documents/" + id)).build();
    }
}

Conditional Annotations

Используй для более гибкой конфигурации:

@ConditionalOnClass(RestHighLevelClient.class)
// Bean создается только если класс в classpath

@ConditionalOnMissingBean
// Bean создается только если нет другого bean-а этого типа

@ConditionalOnProperty(prefix = "app.elasticsearch", name = "enabled", 
                      havingValue = "true", matchIfMissing = true)
// Bean создается только если свойство включено

@ConditionalOnWebApplication
// Только для web приложений

Best Practices

  1. Используй sensible defaults
private String host = "localhost";
private int port = 9200;
  1. Позволяй пользователям переопределить конфигурацию
@ConditionalOnMissingBean
public RestHighLevelClient restHighLevelClient() { ... }
  1. Документируй все свойства
@ConfigurationProperties(prefix = "app.elasticsearch")
public class ElasticsearchProperties {
    // properties с javadoc
}
  1. Включи spring-boot-configuration-processor для IDE support

  2. Тестируй автоконфигурацию

@SpringBootTest
public class ElasticsearchAutoConfigurationTest {
    
    @Autowired
    private RestHighLevelClient client;
    
    @Test
    public void testClientCreated() {
        assertNotNull(client);
    }
}
  1. Используй META-INF/spring.factories для регистрации

  2. Версионирование: используй semantic versioning

Spring Boot Starter - это мощный способ создать переиспользуемые компоненты и поделиться ими с другими разработчиками или командами.