Ark provides two starters for Spring Boot:
| Starter | Stack | Auto-configures |
|---|---|---|
ark-spring-boot-starter |
Spring MVC (sync) | JsonSerializer + HttpTransport + ArkClient.Builder + ArkProperties + TlsResolver |
ark-spring-boot-starter-webflux |
Spring WebFlux (reactive) | JsonSerializer + ReactorHttpTransport + ReactorArkClient.Builder + ArkWebFluxProperties + TlsResolver |
Both starters support @RegisterArkClient declarative clients, per-client configuration, TLS/SSL, trust-all, headers, interceptors, and GraalVM native image.
<dependency>
<groupId>xyz.juandiii</groupId>
<artifactId>ark-spring-boot-starter</artifactId>
</dependency>JsonSerializer-JacksonSerializerusing Spring'sObjectMapperHttpTransport-ArkJdkHttpTransportwith defaultHttpClientArkClient.Builder- prototype-scoped, pre-configured with serializer + transport
All beans use @ConditionalOnMissingBean - define your own to override.
@Configuration
public class HttpClientsConfig {
@Bean
public Ark oauthClient(ArkClient.Builder arkBuilder) {
return arkBuilder
.baseUrl("https://oauth.provider.com")
.build();
}
@Bean
public Ark apiClient(ArkClient.Builder arkBuilder) {
return arkBuilder
.baseUrl("https://api.myservice.com")
.requestInterceptor(req ->
req.header("Authorization", "Bearer " + tokenService.getToken()))
.build();
}
}@Service
public class UserService {
private final Ark apiClient;
public UserService(@Qualifier("apiClient") Ark apiClient) {
this.apiClient = apiClient;
}
public User findById(String id) {
return apiClient.get("/users/" + id)
.retrieve()
.body(User.class);
}
}Override the default JDK transport:
@Bean
public HttpTransport httpTransport() {
return new ArkJdkHttpTransport(HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.build());
}<dependency>
<groupId>xyz.juandiii</groupId>
<artifactId>ark-spring-boot-starter-webflux</artifactId>
</dependency>JsonSerializer-JacksonSerializerusing Spring'sObjectMapperReactorHttpTransport-ArkReactorNettyTransportwith default Reactor NettyHttpClientReactorArkClient.Builder- prototype-scoped, pre-configured with serializer + transportArkWebFluxProperties- type-safe configuration (@ConfigurationProperties)TlsResolver- SSL bundle resolution (auto-detectsSslBundles)- Auto-discovery of
@RegisterArkClientinterfaces with reactive proxy creation
All beans use @ConditionalOnMissingBean - define your own to override.
@Configuration
public class HttpClientsConfig {
@Bean
public ReactorArk apiClient(ReactorArkClient.Builder arkBuilder) {
return arkBuilder
.baseUrl("https://api.example.com")
.build();
}
}@RestController
public class UserController {
private final ReactorArk client;
@GetMapping("/users/{id}")
public Mono<User> getUser(@PathVariable String id) {
return client.get("/users/" + id)
.retrieve()
.body(User.class);
}
}@RegisterArkClient(configKey = "user-api")
@HttpExchange("/users")
public interface UserApi {
@GetExchange("/{id}")
Mono<User> getUser(@PathVariable String id);
@GetExchange
Flux<User> listUsers();
@PostExchange
Mono<User> createUser(@RequestBody User user);
}@RestController
public class UserController {
private final UserApi userApi;
public UserController(UserApi userApi) {
this.userApi = userApi;
}
@GetMapping("/users/{id}")
public Mono<User> getUser(@PathVariable String id) {
return userApi.getUser(id);
}
}# application.properties
ark.logging.level=BODY
ark.client.user-api.base-url=https://api.example.com
ark.client.user-api.http-version=HTTP_2
ark.client.user-api.connect-timeout=5
ark.client.user-api.read-timeout=15
ark.client.user-api.trust-all=false
ark.client.user-api.headers.Authorization=Bearer ${TOKEN}
ark.client.user-api.tls-configuration-name=my-cert
# TLS bundle
spring.ssl.bundle.pem.my-cert.truststore.certificate=classpath:certs/ca.crtSame configuration structure as the sync starter. See Declarative Spring Clients for full annotation details.
Note: Retry is not configured via properties for reactive clients - use Reactor's built-in
.retryWhen()instead. See Retry & Backoff.
For manual package scanning (instead of auto-discovery):
@SpringBootApplication
@EnableArkWebFluxClients(basePackages = "com.example.clients")
public class MyApplication { }The starter provides type-safe configuration via @ConfigurationProperties:
# application.properties
# Global logging level: NONE, BASIC, HEADERS, BODY
ark.logging.level=BODY
# Per-client configuration (key matches @RegisterArkClient configKey)
ark.client.user-api.base-url=https://api.example.com
ark.client.user-api.http-version=HTTP_2
ark.client.user-api.connect-timeout=5
ark.client.user-api.read-timeout=15
ark.client.user-api.tls-configuration-name=my-cert
ark.client.user-api.trust-all=false
ark.client.user-api.headers.X-Api-Key=${API_KEY}
ark.client.user-api.retry.max-attempts=3
ark.client.user-api.retry.delay=500See Retry & Backoff for full retry configuration.
@RegisterArkClient(configKey = "user-api")
@HttpExchange("/users")
public interface UserApi {
@GetExchange("/{id}")
User getUser(@PathVariable String id);
}Properties take precedence over annotation values.
Configure SSL bundles in application.properties:
spring.ssl.bundle.pem.my-cert.truststore.certificate=classpath:certs/ca.crt
ark.client.user-api.tls-configuration-name=my-certThe starter auto-detects SslBundles and creates a TlsResolver that resolves SSL contexts from Spring's SSL bundle registry.
With @RegisterArkClient, proxy beans are auto-created:
@RegisterArkClient(configKey = "user-api", baseUrl = "${api.users.url:https://fallback.com}")
@HttpExchange("/users")
public interface UserApi {
@GetExchange("/{id}")
User getUser(@PathVariable String id);
}Just inject it:
@Service
public class UserService {
private final UserApi userApi;
public UserService(UserApi userApi) {
this.userApi = userApi;
}
}See Declarative Spring Clients for full details.