Mastering Servlet Registration in Spring Boot 2.3.9: From Annotations to Dynamic Registration
This guide explains three ways to register Servlets in Spring Boot 2.3.9—including @ServletComponentScan with @WebServlet, ServletRegistrationBean, and dynamic registration via ServletContextInitializer—while detailing the underlying scanning mechanism, BeanFactory post‑processor workflow, and how Tomcat ultimately registers the servlet.
1. Servlet Registration
Method 1: Add
@ServletComponentScanon the configuration class and annotate the servlet class with
@WebServlet("/hello"). Corresponding annotations for filter and listener are
@WebFilterand
@WebListener.
<code>@SpringBootApplication
@ServletComponentScan
public class SpringBootComprehensiveApplication { }</code> <code>@WebServlet("/hello")
public class MyServlet extends HttpServlet { }</code>Method 2: Register a
ServletRegistrationBeanin a @Bean method, allowing injection of other beans and access to application properties.
<code>@Bean
public ServletRegistrationBean<MyServlet> servlet() {
ServletRegistrationBean<MyServlet> servlet = new ServletRegistrationBean<>(new MyServlet());
servlet.addUrlMappings("/hello");
return servlet;
}</code>Method 3: Dynamically register a servlet by implementing
ServletContextInitializer(available since Servlet 3.0).
<code>@Component
public class DynamicRegServlet implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
ServletRegistration.Dynamic initServlet = servletContext.addServlet("myServlet", MyServlet.class);
initServlet.addMapping("/hello");
}
}</code>Dynamic registration relies on the SPI mechanism and the
ServletContainerInitializerinterface.
2. Scanning Servlet Implementation Principle
In method 1, Spring scans the classpath for
@WebServlet,
@WebFilter, and
@WebListenerannotations and registers them via the bean registration process.
2.1 Import Core Classes
<code>@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan { }
</code>The
ServletComponentScanRegistrarregisters a
ServletComponentRegisteringPostProcessorbean.
<code>class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
if (registry.containsBeanDefinition(BEAN_NAME)) {
updatePostProcessor(registry, packagesToScan);
} else {
addPostProcessor(registry, packagesToScan);
}
}
}
</code>2.2 Register BeanFactory Post Processor
<code>class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
private void addPostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(packagesToScan);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
}
</code>2.3 Instantiate Scanning Components
The static block of
ServletComponentRegisteringPostProcessorcreates handlers for servlet, filter, and listener annotations.
<code>class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor, ApplicationContextAware {
private static final List<ServletComponentHandler> HANDLERS;
static {
List<ServletComponentHandler> servletComponentHandlers = new ArrayList<>();
servletComponentHandlers.add(new WebServletHandler());
servletComponentHandlers.add(new WebFilterHandler());
servletComponentHandlers.add(new WebListenerHandler());
HANDLERS = Collections.unmodifiableList(servletComponentHandlers);
}
}
</code>Each handler extracts annotation attributes and registers a corresponding
ServletRegistrationBean.
2.4 Find and Register Beans
The post‑processor scans candidate components, matches them with the handlers, and invokes
handleto create bean definitions.
<code>abstract class ServletComponentHandler {
void handle(AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
Map<String, Object> attributes = beanDefinition.getMetadata()
.getAnnotationAttributes(this.annotationType.getName());
if (attributes != null) {
doHandle(attributes, beanDefinition, registry);
}
}
}
</code>2.5 Tomcat Registers the Servlet
During Spring Boot startup,
AnnotationConfigServletWebServerApplicationContextcreates the embedded web server and invokes all
ServletContextInitializerbeans, including
ServletRegistrationBean, which registers the servlet with the servlet container.
<code>public abstract class RegistrationBean implements ServletContextInitializer, Ordered {
@Override
public final void onStartup(ServletContext servletContext) throws ServletException {
if (!isEnabled()) {
return;
}
register(description, servletContext);
}
protected abstract void register(String description, ServletContext servletContext);
}
</code>Finally,
ServletRegistrationBeanadds the servlet to the
ServletContextand configures URL mappings, load‑on‑startup, and multipart settings.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.