java 37 lines · 7 steps

Building a Spring Boot rate-limiter auto-config

A Spring Boot auto-configuration wires up a token-bucket rate limiter and registers it as a web interceptor, all conditionally.

Explained by highlit
1@AutoConfiguration
2@EnableConfigurationProperties(RateLimiterProperties.class)
3@ConditionalOnClass(RateLimiter.class)
4public class RateLimiterAutoConfiguration {
5 
6 @Bean
7 @ConditionalOnMissingBean
8 public RateLimiter rateLimiter(RateLimiterProperties properties, ObjectProvider<MeterRegistry> meterRegistry) {
9 TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(
10 properties.getCapacity(),
11 properties.getRefillTokens(),
12 properties.getRefillPeriod());
13 meterRegistry.ifAvailable(limiter::bindMetrics);
14 return limiter;
15 }
16 
17 @Bean
18 @ConditionalOnMissingBean
19 @ConditionalOnProperty(prefix = "app.rate-limiter", name = "enabled", havingValue = "true", matchIfMissing = true)
20 public RateLimitInterceptor rateLimitInterceptor(RateLimiter rateLimiter, RateLimiterProperties properties) {
21 return new RateLimitInterceptor(rateLimiter, properties.getKeyResolver());
22 }
23 
24 @Bean
25 @ConditionalOnMissingBean
26 @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
27 public WebMvcConfigurer rateLimiterWebMvcConfigurer(RateLimitInterceptor interceptor, RateLimiterProperties properties) {
28 return new WebMvcConfigurer() {
29 @Override
30 public void addInterceptors(InterceptorRegistry registry) {
31 registry.addInterceptor(interceptor)
32 .addPathPatterns(properties.getPathPatterns())
33 .order(Ordered.HIGHEST_PRECEDENCE);
34 }
35 };
36 }
37}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Auto-configuration classes let a library contribute beans that back off gracefully when the app already defines its own.
  2. 2Layered @Conditional annotations make wiring depend on classpath, properties, and application type rather than hard assumptions.
  3. 3ObjectProvider lets you consume an optional dependency without forcing it to exist.

Related explainers

typescript
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';
import localeDe from '@angular/common/locales/de';

Locale-aware bootstrapping in Angular

i18n localization dependency-injection
Intermediate 8 steps
typescript
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
 

Validating env config at boot in NestJS

configuration schema-validation environment-variables
Intermediate 8 steps
java
@Component
@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
 

Transparent column encryption in Spring & JPA

encryption aes-gcm jpa-converter
Advanced 10 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { InjectRepository } from '@nestjs/typeorm';

A cache-aside country lookup in NestJS

cache-aside dependency-injection batch-lookup
Intermediate 8 steps
java
package com.acme.billing.config;
 
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;

Feature-flagged beans with Spring @ConditionalOnProperty

feature-flags conditional-beans strategy-pattern
Intermediate 5 steps
typescript
import { Injectable, effect, signal, computed } from '@angular/core';
 
interface Preferences {
  theme: 'light' | 'dark';

A signal-based preferences store in Angular

signals state-management persistence
Intermediate 7 steps

Share this explainer

Here's the card — post it anywhere.

Building a Spring Boot rate-limiter auto-config — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code