Java MVC Configuration and MVC XML Namespace provide a default configuration suitable for most applications and a configuration API to customize it.

You do not need to understand the underlying beans produced by MVC Java Configuration and the MVC namespace.

Activating an MVC Configuration

In a Java configuration, you can use the @EnableWebMvc annotation to enable an MVC configuration, as shown in the following example:

Java

@Configuration
@EnableWebMvc
public class WebConfig {
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig

In the XML configuration, you can use the <mvc:annotation-driven> element to activate the MVC configuration, as shown in the following example:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <mvc:annotation-driven/>
</beans>
        

The following example registers a number of Spring MVC infrastructure beans and adapts to the dependencies available in the classpath (for example, payload converters for JSON, XML, etc.).

MVC Configuration API

In Java configuration, you can implement the WebMvcConfigurer interface, as shown in the following example:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// Implement configuration methods...
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    // Implement configuration methods...
}

In XML, you can validate <mvc:annotation-driven/> attributes and subelements. You can view the Spring MVC XML Schema or use the code completion feature in your IDE to find out which attributes and subelements are available.

Type conversion

By default, formatters are installed for various number and date types, along with customization support via @NumberFormat and @DateTimeFormat for fields.

To register custom formatters and converters in the Java configuration, use the following:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // ...
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addFormatters(registry: FormatterRegistry) {
        // ...
    }
}

To do the same in XML configuration, use the following:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <mvc:annotation-driven conversion-service="conversionService"/>
    <bean id="conversionService"
          class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="org.example.MyConverter"/>
            </set>
        </property>
        <property name="formatters">
            <set>
                <bean class="org.example.MyFormatter"/>
                <bean class="org.example.MyAnnotationFormatterFactory"/>
            </set>
        </property>
        <property name="formatterRegistrars">
            <set>
                <bean class="org.example.MyFormatterRegistrar"/>
            </set>
        </property>
    </bean>
</beans>

By default, Spring MVC respects the request locale when parsing and formatting date values. This is true for forms where dates are represented as strings with "input" form fields. However, for the "date" and "time" form fields, browsers use a fixed format defined in the HTML specification. For such cases, date and time formatting can be configured as follows:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setUseIsoFormat(true);
        registrar.registerFormatters(registry);
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addFormatters(registry: FormatterRegistry) {
        val registrar = DateTimeFormatterRegistrar()
        registrar.setUseIsoFormat(true)
        registrar.registerFormatters(registry)
    }
}

Validation

Default , if a Validation Bean is present in the classpath (for example, Hibernate Validator), the LocalValidatorFactoryBean is registered as a global validator for use with the @Valid annotation and the Validated property on arguments to controller methods.

In your Java configuration, you can configure a global Validator instance, as shown in the following example:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public Validator getValidator() {
        // ...
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun getValidator(): Validator {
        // ...
    }
}

The following example shows how to get the same configuration in XML:


<?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <mvc:annotation-driven validator="globalValidator"/>
</beans>

Note that it is also possible to register Validator implementations locally, as shown in the following example:

Java

@Controller
public class MyController {
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new FooValidator());
    }
}
Kotlin

@Controller
class MyController {
    @InitBinder
    protected fun initBinder(binder: WebDataBinder) {
        binder.addValidators(FooValidator())
    }
}        
If it is necessary that LocalValidatorFactoryBean was injected somewhere, create a bean and mark it with the @Primary annotation to avoid conflicts with what was declared in the MVC configuration.

Interceptors

In your Java configuration, you can register interceptors to apply to incoming requests, as shown in the following example:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleChangeInterceptor());
        registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
    }
}        
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addInterceptors(registry: InterceptorRegistry) {
        registry.addInterceptor(LocaleChangeInterceptor())
        registry.addInterceptor(ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**")
    }
}        

The following example shows how to get the same configuration in XML:


<mvc:interceptors>
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/admin/**"/>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
Mapped interceptors are not ideal for use as a security layer due to the potential for inconsistency with the annotated path matching controller, which can also transparently negotiate slashes and path extensions, along with other path matching options. Many of these options are now outdated, but the potential for inconsistency remains. In general, we recommend using Spring Security, which includes a special MvcRequestMatcher for Spring MVC path matching, and also has a security firewall that blocks many unwanted characters in URL paths.

Content Types

The method can be configured , which Spring MVC defines the requested media types from the request (such as the Accept header, URL path extension, request parameter, and others).

By default, only the header is checked Accept.

If you need to use URL-based content type resolution, consider using a request parameters strategy instead of path extensions.

In a Java configuration, you can configure the resolution of the requested content type, as shown in the following example:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.mediaType("json", MediaType.APPLICATION_JSON);
        configurer.mediaType("xml", MediaType.APPLICATION_XML);
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureContentNegotiation(configurer: ContentNegotiationConfigurer) {
        configurer.mediaType("json", MediaType.APPLICATION_JSON)
        configurer.mediaType("xml", MediaType.APPLICATION_XML)
    }
}

The following example shows , how to get the same configuration in XML:

 
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="mediaTypes">
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>

Message Converters

You can configure HttpMessageConverter in your Java configuration by overriding configureMessageConverters() (to replace the default converters created by Spring MVC) or by overriding extendMessageConverters() (to customize default converters or add additional converters to the default converters).

The following example adds XML and Jackson JSON converters with ObjectMapper configured instead of the standard ones:

Java

@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .indentOutput(true)
                .dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
                .modulesToInstall(new ParameterNamesModule());
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfiguration : WebMvcConfigurer {
    override fun configureMessageConverters(converters: MutableList<HttpMessageConverter<*>>) {
        val builder = Jackson2ObjectMapperBuilder()
                .indentOutput(true)
                .dateFormat(SimpleDateFormat("yyyy-MM-dd"))
                .modulesToInstall(ParameterNamesModule())
        converters.add(MappingJackson2HttpMessageConverter(builder.build()))
        converters.add(MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()))

In the previous example Jackson2ObjectMapperBuilder is used to create a common configuration for MappingJackson2HttpMessageConverter and MappingJackson2XmlHttpMessageConverter with indentation enabled, date format configured, and module registration jackson-module-parameter-nameswhich adds support for accessing parameter names (a feature added in Java 8 ).

This build tool configures the default Jackson properties as follows:

It also automatically registers the following known modules if found in the classpath:

Enabling indentation with Jackson XML support requires a dependency woodstox-core-asl in addition to jackson- dataformat-xml.

There are other interesting Jackson modules:

The following example shows how to get the same configuration in XML:


<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="objectMapper"/>
        </bean>
        <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
            <property name="objectMapper" ref="xmlMapper"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
      p:indentOutput="true"
      p:simpleDateFormat="yyyy-MM-dd"
      p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>

Controller View

This is shorthand for defining a ParameterizableViewController that, when called, immediately jumps to the view. You can use it in static cases where there is no Java controller logic that needs to be executed before the view generates a response.

The following Java configuration example makes a request to / in view called home:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("home");
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addViewControllers(registry: ViewControllerRegistry) {
        registry.addViewController("/").setViewName("home")
    }
}

The following example produces the same thing as the previous one, but using XML, by using the element <mvc:view-controller>:

<mvc:view-controller path="/" view-name="home"/>

If a method with the @RequestMapping annotation is mapped to a URL for any HTTP method, then the view controller cannot be used to process the same URL. This is because a URL match to an annotated controller is considered a strong enough indication of endpoint ownership that a 405 (METHOD_NOT_ALLOWED), 415 (UNSUPPORTED_MEDIA_TYPE), or similar response may be sent to the client to aid in debugging. For this reason, it is recommended to avoid splitting URL processing into an annotated controller and a view controller.

View Resolvers

The MVC configuration makes it easy to register view resolvers.

In the following example Java configuration configures content negotiation view resolution using JSP and Jackson as default View for rendering in JSON format:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.jsp();
    }
}        
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.enableContentNegotiation(MappingJackson2JsonView())
        registry.jsp()
    }
}        

The following example shows how to get the same configuration in XML:


<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
        </mvc:default-views>
    </mvc:content-negotiation>
    <mvc:jsp/>
</mvc:view-resolvers>

Note, however, that FreeMarker, Tiles, Groovy Markup and script templates also require presentation technology configuration.

The MVC namespace provides special elements. The following example works with FreeMarker:


<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
        </mvc:default-views>
    </mvc:content-negotiation>
    <mvc:freemarker cache="false"/>
</mvc:view-resolvers>
<mvc:freemarker-configurer>
    <mvc:template-loader-path location="/freemarker"/>
</mvc:freemarker-configurer>

In the Java configuration, you can add the corresponding Configurer bean, as shown in the following example :

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.freeMarker().cache(false);
    }
    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("/freemarker");
        return configurer;
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.enableContentNegotiation(MappingJackson2JsonView())
        registry.freeMarker().cache(false)
    }
    @Bean
    fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
        setTemplateLoaderPath("/freemarker")
    }
}

Static Resources

This option provides a convenient way to handle static resources from a list of locations based on Resource.

In the following example, if the request begins with /resources, the relative path is used to find and process static resources relative to /public in the web application root or in the classpath at /static. Resources are provided with a one-year expiration date to ensure maximum use of the browser's cache and a reduction in HTTP requests made by the browser. Last-Modified information is derived from Resource#lastModified to provide support for conditional HTTP requests with "Last-Modified" headers.

The following listing shows how to do this using the Java configuration:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public", "classpath:/static/")
                .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public", "classpath:/static/")
                .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)))
    }
}

The following example shows how to get the same configuration in XML:


<mvc:resources mapping="/resources/**"
    location="/public, classpath:/static/"
    cache-period="31556926" />

The resource handler also supports implementation chaining ResourceResolver and ResourceTransformer that you can use to create a toolkit for working with optimized resources.

You can use VersionResourceResolver to version version resource URLs based on an MD5 hash , calculated from the content, fixed version of the application or other. ContentVersionStrategy (MD5 hash) is a smart choice - with some notable exceptions, such as JavaScript resources used with the module loader.

The following example shows how to use the VersionResourceResolver in Java configuration:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(VersionResourceResolver().addContentVersionStrategy("/**"))
    }
}

The following example shows how to get the same configuration in XML:


<mvc:resources mapping="/resources/**" location="/public/">
    <mvc:resource-chain resource-cache="true">
        <mvc:resolvers>
            <mvc:version-resolver>
                <mvc:content-version-strategy patterns="/**"/>
            </mvc:version-resolver>
        </mvc:resolvers>
    </mvc:resource-chain>
</mvc:resources>

You can then use ResourceUrlProvider to rewrite the URLs and apply the full chain of resolvers and resolvers - for example, to insert versions. The MVC configuration provides a ResourceUrlProvider bean that can be injected into other beans. You can also make rewriting transparent using ResourceUrlEncodingFilter for Thymeleaf, JSP, FreeMarker and others using URL tags that rely on HttpServletResponse#encodeURL.

Note that when using EncodedResourceResolver (for example, to process encoded resources with gzip or brotli compression methods) and VersionResourceResolver, you must register them in that order. This enables content-based versions to be reliably calculated from the raw file.

WebJars are also supported using WebJarsResourceResolver, which is automatically registered when the org.webjars:webjars-locator-core library is present in the classpath. The resolver can rewrite URLs to include the jar version, and can also match incoming URLs without versions - for example, from /jquery/jquery.min.js to /jquery/1.2 .0/jquery.min.js.

Java configuration based on ResourceHandlerRegistry provides additional capabilities for fine-grained control, such as last-change logic and optimized resource resolution.

Default Servlet

The Spring MVC framework allows you to map DispatcherServlet to / (thereby overriding the rendering of the standard container servlet), with static requests for resources being handled by the standard container servlet. It configures the DefaultServletHttpRequestHandler with URL mapping /** and the lowest priority relative to other URL mappings.

This handler forwards all requests to the servlet default. Therefore, it must remain last in the order of all other HandlerMappings for the URL. This occurs when <mvc:annotation-driven> is used. Also, if you create your own HandlerMapping instance, be sure to set its order property to a value less than the DefaultServletHttpRequestHandler, which is Integer.MAX_VALUE.

The following example shows how to enable this feature using the default settings:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureDefaultServletHandling(configurer: DefaultServletHandlerConfigurer) {
        configurer.enable()
    }
}

The following example shows how to get the same configuration in XML:

<mvc:default-servlet-handler/> 

The caveat to overriding the / servlet mapping is that the RequestDispatcher for the default servlet must be found by name , and not along the way. DefaultServletHttpRequestHandler attempts to automatically determine the default servlet for a container at startup time, using a list of known names for most major servlet containers (including Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic, and WebSphere). If the default servlet has been custom configured with a different name, or if you are using a different servlet container where the default servlet name is unknown, then you must explicitly specify the default servlet name, as shown in the following example:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable("myCustomDefaultServlet");
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureDefaultServletHandling(configurer: DefaultServletHandlerConfigurer) {
        configurer.enable("myCustomDefaultServlet")
    }
}

The following example shows how to get the same configuration in XML:

<mvc:default-servlet-handler default-servlet- name="myCustomDefaultServlet"/>

Path Mapping

You can configure settings related to path mapping and URL handling . For more information about individual options, see the javadoc at PathMatchConfigurer.

The following example shows how to configure path matching in a Java configuration:

Java

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
            .setPatternParser(new PathPatternParser())
            .addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
    }
    private PathPatternParser patternParser() {
        // ...
    }
}
Kotlin

@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configurePathMatch(configurer: PathMatchConfigurer) {
        configurer
            .setPatternParser(patternParser)
            .addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
    }
    fun patternParser(): PathPatternParser {
        //...
    }
}

The following example shows how to get the same configuration in XML:


<mvc:annotation-driven>
    <mvc:path-matching
            trailing-slash="false"
            path-helper="pathHelper"
            path-matcher="pathMatcher"/>
</mvc:annotation-driven>
<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>

Advanced Java configuration

@EnableWebMvc imports DelegatingWebMvcConfiguration, which:

  • Pass the default Spring configuration for Spring MVC applications

  • Discovers and delegates WebMvcConfigurer implementations to configure this configuration.

In advanced mode, you can remove the @EnableWebMvc annotation and do the extension directly from DelegatingWebMvcConfiguration instead of implementing WebMvcConfigurer, as shown in the following example:

Java

@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
    // ...
}
Kotlin

@Configuration
class WebConfig : DelegatingWebMvcConfiguration() {
    // ...
}

You can save existing methods in WebConfig, but it is now also possible to override bean declarations from the base class, and it is still possible to have any number of other WebMvcConfigurer implementations in the classpath.

Extended XML Configuration

Space MVC names do not provide an extended mode. If you need to set a bean property that cannot be changed in any other way, you can use the BeanPostProcessor lifecycle interceptor in the ApplicationContext for Spring, as shown in the following example :

Java

@Component
public class MyPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
        // ...
    }
}
Kotlin

@Component
class MyPostProcessor : BeanPostProcessor {
    override fun postProcessBeforeInitialization(bean: Any, name: String): Any {
        // ...
    }
}