Configuration annotations, utilities, and infrastructure for setting up HTTP integration components. These components handle bean initialization, request mapping registration, and integration with Spring's configuration system.
Automatic Configuration:
HttpIntegrationConfigurationInitializer runs automatically when module is on classpathMETA-INF/spring.factories mechanismIntegrationRequestMappingHandlerMapping and DynamicRequestMappingBeanPostProcessorHandler Mapping:
IntegrationRequestMappingHandlerMapping extends RequestMappingHandlerMappingContextRefreshedEvent to scan for endpointsBaseHttpInboundEndpoint beans in application contextRequestMappingInfo for each endpoint's RequestMappingDynamic Registration:
DynamicRequestMappingBeanPostProcessor handles runtime endpoint registrationpostProcessBeforeInitialization()postProcessBeforeDestruction()Framework Detection:
HttpContextUtils.WEB_MVC_PRESENT - checks for Spring MVCHttpContextUtils.WEB_FLUX_PRESENT - checks for Spring WebFluxBean Names:
"integrationRequestMappingHandlerMapping""integrationGraphController"HttpContextUtils constantsConfiguration Properties:
spring.integration.graph.controller.request.mapping.path - graph controller path (default: /integration)application.properties or environment variablesLifecycle:
Edge Cases:
setOrder()Utility class for accessing HTTP integration components from the BeanFactory. Provides constants for identifying web framework presence and bean names for HTTP infrastructure components.
public final class HttpContextUtils {
/**
* Flag indicating if Spring Web MVC DispatcherServlet is present on classpath.
* Used to determine if MVC features are available.
*/
public static final boolean WEB_MVC_PRESENT;
/**
* Flag indicating if Spring WebFlux DispatcherHandler is present on classpath.
* Used to determine if reactive features are available.
*/
public static final boolean WEB_FLUX_PRESENT;
/**
* Bean name for IntegrationRequestMappingHandlerMapping.
* Value: "integrationRequestMappingHandlerMapping"
*/
public static final String HANDLER_MAPPING_BEAN_NAME =
"integrationRequestMappingHandlerMapping";
/**
* Property name for graph controller request mapping path.
* Value: "spring.integration.graph.controller.request.mapping.path"
*/
public static final String GRAPH_CONTROLLER_PATH_PROPERTY =
"spring.integration.graph.controller.request.mapping.path";
/**
* Default path for integration graph controller.
* Value: "/integration"
*/
public static final String GRAPH_CONTROLLER_DEFAULT_PATH = "/integration";
/**
* Bean name for integration graph controller.
* Value: "integrationGraphController"
*/
public static final String GRAPH_CONTROLLER_BEAN_NAME =
"integrationGraphController";
/**
* Converts Spring Integration RequestMapping to Spring Web RequestMapping annotation.
* Transforms programmatic mapping configuration to annotation format.
*
* @param requestMapping the Spring Integration RequestMapping
* @return Spring Web RequestMapping annotation or null if input is null
*/
public static org.springframework.web.bind.annotation.RequestMapping
convertRequestMappingToAnnotation(RequestMapping requestMapping);
}Usage Example - Check Framework Presence:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.http.config.HttpContextUtils;
@Configuration
public class FrameworkDetectionConfig {
@Bean
public HttpEndpointFactory httpEndpointFactory() {
if (HttpContextUtils.WEB_MVC_PRESENT) {
System.out.println("Spring Web MVC is available");
return new MvcEndpointFactory();
} else if (HttpContextUtils.WEB_FLUX_PRESENT) {
System.out.println("Spring WebFlux is available");
return new WebFluxEndpointFactory();
} else {
throw new IllegalStateException(
"Neither Spring MVC nor WebFlux is present");
}
}
}Usage Example - Access Handler Mapping:
import org.springframework.beans.factory.BeanFactory;
import org.springframework.integration.http.inbound.IntegrationRequestMappingHandlerMapping;
@Component
public class HandlerMappingAccessor {
private final BeanFactory beanFactory;
public HandlerMappingAccessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public IntegrationRequestMappingHandlerMapping getHandlerMapping() {
return beanFactory.getBean(
HttpContextUtils.HANDLER_MAPPING_BEAN_NAME,
IntegrationRequestMappingHandlerMapping.class);
}
public void inspectMappings() {
IntegrationRequestMappingHandlerMapping mapping = getHandlerMapping();
// Inspect registered request mappings
mapping.getHandlerMethods().forEach((info, method) -> {
System.out.println("Mapping: " + info);
System.out.println("Handler: " + method);
});
}
}Usage Example - Convert RequestMapping:
import org.springframework.integration.http.inbound.RequestMapping;
import org.springframework.http.HttpMethod;
public class RequestMappingConverter {
public void convertMapping() {
// Create Spring Integration RequestMapping
RequestMapping siMapping = new RequestMapping();
siMapping.setPathPatterns("/api/orders");
siMapping.setMethods(HttpMethod.GET, HttpMethod.POST);
siMapping.setConsumes("application/json");
siMapping.setProduces("application/json");
// Convert to Spring Web annotation format
org.springframework.web.bind.annotation.RequestMapping webMapping =
HttpContextUtils.convertRequestMappingToAnnotation(siMapping);
// Use converted mapping for inspection or processing
if (webMapping != null) {
System.out.println("Paths: " + Arrays.toString(webMapping.path()));
System.out.println("Methods: " + Arrays.toString(webMapping.method()));
System.out.println("Consumes: " + Arrays.toString(webMapping.consumes()));
System.out.println("Produces: " + Arrays.toString(webMapping.produces()));
}
}
}Initializes HTTP integration infrastructure beans, including IntegrationRequestMappingHandlerMapping and DynamicRequestMappingBeanPostProcessor. Automatically configures necessary components for HTTP integration.
public class HttpIntegrationConfigurationInitializer
implements IntegrationConfigurationInitializer {
/**
* Initializes the HTTP integration configuration.
* Registers handler mapping and bean post processor if web framework is present.
*
* @param beanFactory the configurable bean factory
* @throws BeansException if initialization fails
*/
public void initialize(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
}This class is automatically invoked by Spring Integration's infrastructure initialization mechanism. It registers:
IntegrationRequestMappingHandlerMapping - Handler mapping for HTTP inbound endpointsDynamicRequestMappingBeanPostProcessor - Bean post processor for dynamic endpoint registrationInternal Operation:
The initializer:
This happens automatically when spring-integration-http module is on the classpath.
HandlerMapping implementation that detects and registers RequestMappingInfos for HTTP inbound endpoints. Extends Spring MVC's RequestMappingHandlerMapping to integrate Spring Integration endpoints with the web framework.
public final class IntegrationRequestMappingHandlerMapping
extends RequestMappingHandlerMapping
implements ApplicationListener<ContextRefreshedEvent> {
/**
* Handles ContextRefreshedEvent to initialize handler mappings.
* Detects all BaseHttpInboundEndpoint beans and registers their mappings.
* Called automatically when application context is refreshed.
*
* @param event the context refreshed event
*/
public void onApplicationEvent(ContextRefreshedEvent event);
/**
* No-op in favor of onApplicationEvent.
* Overrides superclass initialization to defer until context refresh.
*/
@Override
public void afterPropertiesSet();
}Usage Example - Custom Handler Mapping Configuration:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.http.inbound.IntegrationRequestMappingHandlerMapping;
@Configuration
public class CustomHandlerMappingConfig {
@Bean
public IntegrationRequestMappingHandlerMapping integrationHandlerMapping() {
IntegrationRequestMappingHandlerMapping mapping =
new IntegrationRequestMappingHandlerMapping();
// Set order to process before other handler mappings
mapping.setOrder(0);
// Configure CORS
mapping.setCorsConfigurations(corsConfigurations());
return mapping;
}
private Map<String, CorsConfiguration> corsConfigurations() {
Map<String, CorsConfiguration> configs = new HashMap<>();
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://example.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
configs.put("/api/**", config);
return configs;
}
}Usage Example - Inspect Registered Mappings:
import org.springframework.integration.http.inbound.IntegrationRequestMappingHandlerMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
@Component
public class MappingInspector {
private final IntegrationRequestMappingHandlerMapping handlerMapping;
public MappingInspector(
IntegrationRequestMappingHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
}
public void inspectMappings() {
Map<RequestMappingInfo, HandlerMethod> mappings =
handlerMapping.getHandlerMethods();
System.out.println("Registered HTTP Integration Endpoints:");
mappings.forEach((info, method) -> {
System.out.println(" Patterns: " + info.getPathPatternsCondition());
System.out.println(" Methods: " + info.getMethodsCondition());
System.out.println(" Handler: " + method.getBean());
System.out.println(" ---");
});
}
}BeanPostProcessor that registers and unregisters request mappings for dynamically created HTTP inbound endpoints at runtime. Enables dynamic endpoint creation and destruction.
public class DynamicRequestMappingBeanPostProcessor
implements BeanFactoryAware,
DestructionAwareBeanPostProcessor,
SmartInitializingSingleton {
/**
* Sets the BeanFactory for bean resolution.
*
* @param beanFactory the bean factory
* @throws BeansException if error occurs
*/
public void setBeanFactory(BeanFactory beanFactory) throws BeansException;
/**
* Called after all singletons are instantiated.
* Performs post-initialization tasks.
*/
public void afterSingletonsInstantiated();
/**
* Registers request mapping before bean initialization.
* Detects BaseHttpInboundEndpoint beans and registers their mappings
* with IntegrationRequestMappingHandlerMapping.
*
* @param bean the bean instance
* @param beanName the bean name
* @return the bean (possibly wrapped)
* @throws BeansException if error occurs
*/
public Object postProcessBeforeInitialization(
Object bean, String beanName) throws BeansException;
/**
* Unregisters request mapping before bean destruction.
* Removes endpoint mapping from handler mapping when bean is destroyed.
*
* @param bean the bean instance
* @param beanName the bean name
* @throws BeansException if error occurs
*/
public void postProcessBeforeDestruction(
Object bean, String beanName) throws BeansException;
/**
* Checks if bean requires destruction callback.
* Returns true for BaseHttpInboundEndpoint beans.
*
* @param bean the bean instance
* @return true if destruction callback is needed
*/
public boolean requiresDestruction(Object bean);
}Usage Example - Dynamic Endpoint Creation:
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway;
import org.springframework.integration.http.inbound.RequestMapping;
@Component
public class DynamicEndpointManager {
private final ApplicationContext applicationContext;
private final DefaultListableBeanFactory beanFactory;
public DynamicEndpointManager(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.beanFactory = (DefaultListableBeanFactory)
applicationContext.getAutowireCapableBeanFactory();
}
public void createEndpoint(String path, String channelName) {
// Create bean definition
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(HttpRequestHandlingMessagingGateway.class);
// Configure gateway
builder.addPropertyReference("requestChannel", channelName);
// Create request mapping
RequestMapping mapping = new RequestMapping();
mapping.setPathPatterns(path);
mapping.setMethods(HttpMethod.POST);
builder.addPropertyValue("requestMapping", mapping);
// Generate unique bean name
String beanName = "dynamicEndpoint-" + UUID.randomUUID().toString();
// Register bean
beanFactory.registerBeanDefinition(beanName, builder.getBeanDefinition());
// DynamicRequestMappingBeanPostProcessor automatically registers
// the mapping when the bean is initialized
beanFactory.getBean(beanName);
System.out.println("Created dynamic endpoint at: " + path);
}
public void removeEndpoint(String beanName) {
// DynamicRequestMappingBeanPostProcessor automatically unregisters
// the mapping when the bean is destroyed
beanFactory.destroySingleton(beanName);
System.out.println("Removed dynamic endpoint: " + beanName);
}
}Usage Example - Runtime Endpoint Management:
@RestController
@RequestMapping("/admin/endpoints")
public class EndpointManagementController {
private final DynamicEndpointManager endpointManager;
private final Map<String, String> endpointRegistry = new ConcurrentHashMap<>();
public EndpointManagementController(DynamicEndpointManager endpointManager) {
this.endpointManager = endpointManager;
}
@PostMapping("/create")
public ResponseEntity<String> createEndpoint(
@RequestParam String path,
@RequestParam String channel) {
String endpointId = UUID.randomUUID().toString();
endpointManager.createEndpoint(path, channel);
endpointRegistry.put(endpointId, path);
return ResponseEntity.ok("Created endpoint: " + endpointId);
}
@DeleteMapping("/{endpointId}")
public ResponseEntity<String> removeEndpoint(@PathVariable String endpointId) {
String beanName = endpointRegistry.remove(endpointId);
if (beanName != null) {
endpointManager.removeEndpoint(beanName);
return ResponseEntity.ok("Removed endpoint: " + endpointId);
}
return ResponseEntity.notFound().build();
}
@GetMapping
public Map<String, String> listEndpoints() {
return endpointRegistry;
}
}Minimal configuration for HTTP integration:
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.config.EnableIntegration;
@Configuration
@EnableIntegration
public class BasicHttpConfig {
// HttpIntegrationConfigurationInitializer automatically configures:
// - IntegrationRequestMappingHandlerMapping
// - DynamicRequestMappingBeanPostProcessor
// No additional configuration needed for basic setup
}Configure HTTP integration using properties:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.http.config.EnableIntegrationGraphController;
@Configuration
@ConfigurationProperties(prefix = "app.integration.http")
public class PropertyBasedConfig {
private String graphPath = "/integration";
private List<String> allowedOrigins = new ArrayList<>();
private boolean enableManagement = true;
@Configuration
@EnableIntegrationGraphController
public static class GraphControllerConfig {
// Configured via properties:
// spring.integration.graph.controller.request.mapping.path=${app.integration.http.graphPath}
}
// Getters and setters
public String getGraphPath() { return graphPath; }
public void setGraphPath(String graphPath) { this.graphPath = graphPath; }
public List<String> getAllowedOrigins() { return allowedOrigins; }
public void setAllowedOrigins(List<String> allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}
public boolean isEnableManagement() { return enableManagement; }
public void setEnableManagement(boolean enableManagement) {
this.enableManagement = enableManagement;
}
}Configure handler mapping with custom behavior:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.http.inbound.IntegrationRequestMappingHandlerMapping;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AdvancedHandlerMappingConfig implements WebMvcConfigurer {
@Bean
public IntegrationRequestMappingHandlerMapping customHandlerMapping() {
IntegrationRequestMappingHandlerMapping mapping =
new IntegrationRequestMappingHandlerMapping();
// Set high priority (process first)
mapping.setOrder(0);
// Configure global CORS
CorsConfiguration corsConfig = new CorsConfiguration();
corsConfig.setAllowedOriginPatterns(List.of("*.example.com"));
corsConfig.setAllowedMethods(List.of("*"));
corsConfig.setAllowedHeaders(List.of("*"));
corsConfig.setExposedHeaders(List.of("X-*", "Authorization"));
corsConfig.setAllowCredentials(true);
corsConfig.setMaxAge(3600L);
Map<String, CorsConfiguration> corsConfigurations = new HashMap<>();
corsConfigurations.put("/api/**", corsConfig);
mapping.setCorsConfigurations(corsConfigurations);
// Configure custom path matching
mapping.setUseTrailingSlashMatch(true);
mapping.setUseSuffixPatternMatch(false);
return mapping;
}
}Configure HTTP integration programmatically:
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway;
import org.springframework.integration.http.inbound.RequestMapping;
@Configuration
public class ProgrammaticHttpConfig {
public static class HttpEndpointRegistrar
implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
// Register HTTP gateway bean programmatically
BeanDefinitionBuilder gatewayBuilder = BeanDefinitionBuilder
.genericBeanDefinition(HttpRequestHandlingMessagingGateway.class);
// Configure request mapping
RequestMapping mapping = new RequestMapping();
mapping.setPathPatterns("/api/data");
mapping.setMethods(HttpMethod.POST);
gatewayBuilder.addPropertyValue("requestMapping", mapping);
gatewayBuilder.addPropertyReference("requestChannel", "dataChannel");
BeanDefinition gatewayDefinition = gatewayBuilder.getBeanDefinition();
registry.registerBeanDefinition(
"programmaticGateway",
gatewayDefinition);
}
}
}Configure HTTP integration for different environments:
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.integration.http.config.EnableIntegrationGraphController;
import org.springframework.integration.http.config.EnableControlBusController;
@Configuration
public class MultiEnvironmentConfig {
@Configuration
@Profile("development")
@EnableIntegrationGraphController(
path = "/dev/integration",
allowedOrigins = {"*"}
)
@EnableControlBusController
public static class DevelopmentConfig {
// Full management access in development
}
@Configuration
@Profile("production")
@EnableIntegrationGraphController(
path = "/internal/integration",
allowedOrigins = {"https://admin.production.example.com"}
)
public static class ProductionConfig {
// Restricted management access in production
// Control bus disabled for security
}
@Configuration
@Profile("test")
public static class TestConfig {
// No management endpoints in test environment
}
}Create custom configuration initializer:
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.integration.config.IntegrationConfigurationInitializer;
public class CustomHttpConfigurationInitializer
implements IntegrationConfigurationInitializer {
@Override
public void initialize(ConfigurableListableBeanFactory beanFactory) {
// Check if HTTP integration is needed
if (!HttpContextUtils.WEB_MVC_PRESENT &&
!HttpContextUtils.WEB_FLUX_PRESENT) {
return; // Skip if no web framework present
}
// Register custom components
registerCustomHeaderMapper(beanFactory);
registerCustomConverters(beanFactory);
registerCustomErrorHandler(beanFactory);
System.out.println("Custom HTTP integration configuration initialized");
}
private void registerCustomHeaderMapper(
ConfigurableListableBeanFactory beanFactory) {
if (!beanFactory.containsBean("customHttpHeaderMapper")) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(DefaultHttpHeaderMapper.class);
builder.addPropertyValue("outboundHeaderNames",
new String[]{"Content-Type", "Authorization", "X-*"});
builder.addPropertyValue("inboundHeaderNames",
new String[]{"Content-Type", "X-*"});
((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(
"customHttpHeaderMapper",
builder.getBeanDefinition());
}
}
private void registerCustomConverters(
ConfigurableListableBeanFactory beanFactory) {
// Register custom message converters
}
private void registerCustomErrorHandler(
ConfigurableListableBeanFactory beanFactory) {
// Register custom error handler
}
}Register in META-INF/spring.factories:
org.springframework.integration.config.IntegrationConfigurationInitializer=\
com.example.CustomHttpConfigurationInitializerEnsure proper ordering of handler mappings:
@Configuration
public class OrderedMappingConfig {
@Bean
public IntegrationRequestMappingHandlerMapping integrationHandlerMapping() {
IntegrationRequestMappingHandlerMapping mapping =
new IntegrationRequestMappingHandlerMapping();
// Process integration endpoints before application controllers
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
return mapping;
}
}Configure based on conditions:
@Configuration
public class ConditionalHttpConfig {
@Bean
@ConditionalOnProperty(
name = "app.integration.http.enabled",
havingValue = "true",
matchIfMissing = true
)
public IntegrationRequestMappingHandlerMapping conditionalHandlerMapping() {
return new IntegrationRequestMappingHandlerMapping();
}
@Bean
@ConditionalOnProperty(
name = "app.integration.management.enabled",
havingValue = "true"
)
@EnableIntegrationGraphController
@EnableControlBusController
public class ManagementConfig {
}
}Integrate configuration with health checks:
@Component
public class HttpIntegrationHealthIndicator implements HealthIndicator {
private final ApplicationContext applicationContext;
public HttpIntegrationHealthIndicator(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Health health() {
try {
// Check handler mapping
IntegrationRequestMappingHandlerMapping handlerMapping =
applicationContext.getBean(
HttpContextUtils.HANDLER_MAPPING_BEAN_NAME,
IntegrationRequestMappingHandlerMapping.class);
int mappingCount = handlerMapping.getHandlerMethods().size();
return Health.up()
.withDetail("handlerMappingRegistered", true)
.withDetail("endpointCount", mappingCount)
.withDetail("webFramework",
HttpContextUtils.WEB_MVC_PRESENT ? "MVC" : "WebFlux")
.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.build();
}
}
}