java
39 lines · 6 steps
Swapping payment gateways by profile in Spring
One config class defines three PaymentGateway beans, and the active Spring profile picks exactly which one loads.
Explained by
highlit
1package com.example.payments.config;
2
3import com.stripe.StripeClient;
4import org.springframework.beans.factory.annotation.Value;
5import org.springframework.context.annotation.Bean;
6import org.springframework.context.annotation.Configuration;
7import org.springframework.context.annotation.Profile;
8
9@Configuration
10public class PaymentGatewayConfig {
11
12 @Bean
13 @Profile("local")
14 public PaymentGateway sandboxPaymentGateway() {
15 return new StubPaymentGateway();
16 }
17
18 @Bean
19 @Profile("staging")
20 public PaymentGateway stagingPaymentGateway(
21 @Value("${stripe.test-key}") String testKey) {
22 StripeClient client = StripeClient.builder()
23 .setApiKey(testKey)
24 .build();
25 return new StripePaymentGateway(client, false);
26 }
27
28 @Bean
29 @Profile("production")
30 public PaymentGateway livePaymentGateway(
31 @Value("${stripe.live-key}") String liveKey,
32 @Value("${stripe.webhook-secret}") String webhookSecret) {
33 StripeClient client = StripeClient.builder()
34 .setApiKey(liveKey)
35 .setConnectTimeout(5_000)
36 .build();
37 return new StripePaymentGateway(client, true, webhookSecret);
38 }
39}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Binding beans to profiles lets one interface resolve to different implementations per environment without conditional code.
- 2Injecting secrets through @Value keeps keys out of source and scoped to the environment that needs them.
- 3A stub implementation for local development removes any dependency on live external services.
Related explainers
java
public final class Ulid { private static final char[] ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ".toCharArray(); private static final SecureRandom RANDOM = new SecureRandom();
How to generate a ULID in Java
base32-encoding
bit-manipulation
identifiers
Intermediate
8 steps
typescript
import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, timer, throwError } from 'rxjs'; import { switchMap, takeWhile, filter, take, catchError } from 'rxjs/operators';
Polling a job until it finishes in Angular
rxjs
polling
observables
Intermediate
7 steps
php
<?php namespace App\Http\Controllers;
Handling Stripe webhooks in Laravel
webhooks
signature-verification
dependency-injection
Intermediate
7 steps
java
@RestController @RequestMapping("/api/reports") public class ReportController {
Header-driven endpoints in a Spring controller
rest api
request headers
dependency injection
Intermediate
7 steps
php
<?php namespace App\FeatureFlags;
How a feature flag evaluator decides
feature-flags
rollout
hashing
Intermediate
8 steps
typescript
import { Injectable, signal, computed, effect, inject } from '@angular/core'; import { DOCUMENT } from '@angular/common'; export type Theme = 'light' | 'dark';
A signal-based theme service in Angular
signals
reactivity
dependency-injection
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/swapping-payment-gateways-by-profile-in-spring-explained-java-46e1/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.