docs/Spring全家桶/SpringBoot源码解析/SpringBootWeb应用(一):servlet组件的注册流程.md
springboot УҪע servlet servlet``filter``listenerôأspringboot ĵΪṩ 3 ַľ 3 ַԴʵ֡
XxxRegistrationBean עspringboot ṩ͵ RegistrationBean servlet עᣬֱ ServletRegistrationBean``FilterRegistrationBean``ServletListenerRegistrationBeanǼʾǵ÷
/**
* һservlet
*/
public class MyServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// һЩ
...
}
}
/**
* ע
*/
@Bean
public ServletRegistrationBean registerServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(
new MyServlet(), "/myServlet");
// һЩò
servletRegistrationBean.setXxx();
...
return servletRegistrationBean;
}
ṩ servlet ע᷽ʽҪע filter``listenerֻʹöӦ RegistrationBean ɣͲչʾˡ
Servlet 3.0servlet ṩ 3 ע servlet ע
@WebServlet: servlet ע@WebFilter: filter ע@WebListener: listener עservlet עΪ @WebServlet:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
String name() default "";
String[] value() default {};
String[] urlPatterns() default {};
int loadOnStartup() default -1;
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
Կ@WebServlet ֶ֧ãָ servlet ơӳ url ָҲṩһʾ
@WebServlet(name = "myServlet", urlPatterns = "/myServlet")
public class JavaServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// һЩ
...
}
}
ҪһҪIJǾʹ @ServletComponentScan ɨ蹦ܣ
// ʹ @ServletComponentScan servlet ɨ蹦
@ServletComponentScan
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
...
}
}
ServletContextInitializer עʹַʽעᣬҪʵ ServletContextInitializer ӿڣ
/**
* һservlet
*/
public class MyServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
// һЩ
...
}
}
/**
* ʵ ServletContextInitializer
*/
@Component
public class ServletConfig implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) {
// ʹ servletContext ע
ServletRegistration initServlet = servletContext.addServlet("myServlet", MyServlet.class);
// ԽһЩ
initServlet.addMapping("/myServlet");
}
}
ʹַʽעᣬҪʵ ServletContextInitializerȻд ServletContextInitializer#onStartup ServletContextInitializer#onStartup ʹ ServletContext עᡣServletContext servlet ṩעռ࣬ʹ RegistrationBean עᣬʹ @ServletComponentScan ɨעᣬնͨ ServletContext עᵽ servlet С
˽ʹúǾ Դ뿴Щʵ֡
@ServletComponentScan ɨֱӽ @ServletComponentScan
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {
...
}
ע @Import ע⣬һࣺServletComponentScanRegistrarǿ྿ɶ
/**
* ʵImportBeanDefinitionRegistrar
* ע ServletComponentRegisteringPostProcessor
*/
class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
private static final String BEAN_NAME = "servletComponentRegisteringPostProcessor";
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
if (registry.containsBeanDefinition(BEAN_NAME)) {
updatePostProcessor(registry, packagesToScan);
}
else {
// ע BeanFactoryPostProcessor
addPostProcessor(registry, packagesToScan);
}
}
/**
* ע BeanFactoryPostProcessor
* ע ServletComponentRegisteringPostProcessor
*/
private void addPostProcessor(BeanDefinitionRegistry registry, Set<String> packagesToScan) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
// ServletComponentRegisteringPostProcessor: ɨ BeanFactoryPostProcessor
beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(packagesToScan);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// ServletComponentScanRegistrar Ϊע ServletComponentRegisteringPostProcessor
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
...
}
Կʵ ImportBeanDefinitionRegistrarҪ spring ע ServletComponentRegisteringPostProcessorǼȥ ServletComponentRegisteringPostProcessor
class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor,
ApplicationContextAware {
/**
* Ҫɨİ.
*/
private final Set<String> packagesToScan;
/**
* Ҫɨİɹ췽
*/
ServletComponentRegisteringPostProcessor(Set<String> packagesToScan) {
this.packagesToScan = packagesToScan;
}
/**
* дBeanFactoryPostProcessorķ
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
// жǷǶ web
if (isRunningInEmbeddedWebServer()) {
// ɨɨ
ClassPathScanningCandidateComponentProvider componentProvider
= createComponentProvider();
for (String packageToScan : this.packagesToScan) {
// аɨ
scanPackage(componentProvider, packageToScan);
}
}
}
...
}
ԿServletComponentRegisteringPostProcessor ʵ BeanFactoryPostProcessorд BeanFactoryPostProcessor#postProcessBeanFactory дɨɨǰǴɨ ClassPathScanningCandidateComponentProviderȻٽɨ衣
ɨĴ createComponentProvider()
// handler
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);
}
/**
* ɨ
*/
private ClassPathScanningCandidateComponentProvider createComponentProvider() {
//
ClassPathScanningCandidateComponentProvider componentProvider
= new ClassPathScanningCandidateComponentProvider(false);
componentProvider.setEnvironment(this.applicationContext.getEnvironment());
componentProvider.setResourceLoader(this.applicationContext);
for (ServletComponentHandler handler : HANDLERS) {
// ù˹
componentProvider.addIncludeFilter(handler.getTypeFilter());
}
return componentProvider;
}
createComponentProvider() УǴɨȻһЩԣžù˹ص¹˹ãЩ WebServletHandler/WebFilterHandler/WebListenerHandler getTypeFilter() ṩ
getTypeFilter() λһУ
abstract class ServletComponentHandler {
private final TypeFilter typeFilter;
/**
* ע⣬תΪ AnnotationTypeFilter
*/
protected ServletComponentHandler(Class<? extends Annotation> annotationType) {
this.typeFilter = new AnnotationTypeFilter(annotationType);
...
}
/**
* TypeFilter
*/
TypeFilter getTypeFilter() {
return this.typeFilter;
}
...
}
ServletComponentHandler УһԱ typeFilterڹ췽дעֵת AnnotationTypeFilterȻֵ typeFilter getTypeFilter() صľ typeFilter
˽ typeFilter Դļʵࣺ
/**
* WebFilterHandler 췽IJ WebFilter
*/
class WebFilterHandler extends ServletComponentHandler {
WebFilterHandler() {
super(WebFilter.class);
}
...
}
/**
* WebListenerHandler 췽IJ WebListener
*/
class WebListenerHandler extends ServletComponentHandler {
WebListenerHandler() {
super(WebListener.class);
}
...
}
/**
* WebServletHandler 췽IJ WebServlet
*/
class WebServletHandler extends ServletComponentHandler {
WebServletHandler() {
super(WebServlet.class);
}
...
}
ɴ˾ˣcreateComponentProvider() õ ClassPathScanningCandidateComponentProvider ֻ 3 עࣺ
@WebFilter@WebListener@WebServletǼɨ̣Ϊ ServletComponentRegisteringPostProcessor#scanPackage:
private void scanPackage(ClassPathScanningCandidateComponentProvider componentProvider,
String packageToScan) {
for (BeanDefinition candidate : componentProvider.findCandidateComponents(packageToScan)) {
if (candidate instanceof AnnotatedBeanDefinition) {
// õ BeanDefinition
for (ServletComponentHandler handler : HANDLERS) {
handler.handle(((AnnotatedBeanDefinition) candidate),
(BeanDefinitionRegistry) this.applicationContext);
}
}
}
}
ھɨ̣ClassPathScanningCandidateComponentProvider#findCandidateComponents ͬ spring İɨ̻һ£Ͳչϸˣǰص BeanDefinition ĴϣҲ ServletComponentHandler#handle
void handle(AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
// annotationType ǹ췽дע⣬@WebFilter@WebListener
Map<String, Object> attributes = beanDefinition.getMetadata()
.getAnnotationAttributes(this.annotationType.getName());
// ж϶ӦעǷڣ
if (attributes != null) {
doHandle(attributes, beanDefinition, registry);
}
}
ڴɨõ BeanDefinition ʱȱе handler(WebServletHandler/WebFilterHandler/WebListenerHandler)Ȼ ServletComponentHandler#handle д ServletComponentHandler#handle УֻǷڶӦעǷڣʹ AnnotatedBeanDefinition#getMetadata ȡӦעϢǷ doHandler()
ô doHandler() ʲôأǽ WebServletHandler#doHandle
public void doHandle(Map<String, Object> attributes, AnnotatedBeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
// ע ServletRegistrationBean Ӧ BeanDefinition
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(ServletRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("initParameters", extractInitParameters(attributes));
builder.addPropertyValue("loadOnStartup", attributes.get("loadOnStartup"));
// ȡ servlet ƣָƣʹָƣûָʹbean
String name = determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);
builder.addPropertyValue("servlet", beanDefinition);
builder.addPropertyValue("urlMappings", extractUrlPatterns(attributes));
builder.addPropertyValue("multipartConfig", determineMultipartConfig(beanDefinition));
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}
ԿҪǴ Servlet ã spring ע ServletRegistrationBean Ӧ beanDefinition
Handler doHandle() Ҳ࣬ spring ע beanDefinition ͬͲϸˡ
ܽ⼸ע spring ע beanDefinition
@WebServlet: ע ServletRegistrationBean Ӧ beanDefinition@WebFilter: ע FilterRegistrationBean Ӧ beanDefinition@WebListener: ע ServletListenerRegistrationBean Ӧ beanDefinitionʹ XxxRegistrationBean עʱֶ XxxRegistrationBeanȻͨ @Bean עעᵽ spring Уʹ @WebServlet/@WebFilter/@WebListener һȦҲǻص XxxRegistrationBean
XxxRegistrationBean עʹ XxxRegistrationBean עᣬʹ @ServletComponentScan ɨעᣬնõ XxxRegistrationBean Ӧ beanǾ̽Щ bean עᵽ servlet еġ
ӴϿServletRegistrationBean``FilterRegistrationBean ServletListenerRegistrationBean ServletContextInitializer ӿڵʵ࣬ServletRegistrationBean ļ̳нṹ£
ServletContextInitializer ֻһ onStartup(...)
@FunctionalInterface
public interface ServletContextInitializer {
/**
* servletContextǽ Servletfilterlistener ע
*/
void onStartup(ServletContext servletContext) throws ServletException;
}
ڽ servlet ע᷽ʽʱᵽͨʵ ServletContextInitializerд onStartup() ʵ servlet עᣬ XxxRegistrationBean ĵײʵҲôġ
ServletRegistrationBean onStartup(...) ɶ
ServletRegistrationBean ûд onStartup(...) ֱӼ̳ RegistrationBean:
public final void onStartup(ServletContext servletContext) throws ServletException {
// ȡϢ
String description = getDescription();
// ǷעᣬĬΪtrue
if (!isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
return;
}
// ע
register(description, servletContext);
}
ӣȻȡһϢȻжǷעᣬžǽעˡֱӲ鿴ע DynamicRegistrationBean#register:
protected final void register(String description, ServletContext servletContext) {
D registration = addRegistration(description, servletContext);
if (registration == null) {
logger.info(...);
return;
}
//
configure(registration);
}
Ҫ£ע servlet 봦ãע ServletRegistrationBean#addRegistration :
protected ServletRegistration.Dynamic addRegistration(String description,
ServletContext servletContext) {
String name = getServletName();
// ע
return servletContext.addServlet(name, this.servlet);
}
עDZȽϼģֱӵ ServletContext#addServlet С
鿴ô ServletRegistrationBean#configure
protected void configure(ServletRegistration.Dynamic registration) {
// ø
super.configure(registration);
// urlMapping
String[] urlMapping = StringUtils.toStringArray(this.urlMappings);
if (urlMapping.length == 0 && this.alwaysMapUrl) {
urlMapping = DEFAULT_MAPPINGS;
}
if (!ObjectUtils.isEmpty(urlMapping)) {
registration.addMapping(urlMapping);
}
// loadOnStartup
registration.setLoadOnStartup(this.loadOnStartup);
// һЩ
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
}
ǵ˸ķȻôˣҪǴ urlMapping loadOnStartupͲˡ
super.configure(...) ɶ DynamicRegistrationBean#configure:
/**
* ҲǴһЩ
*/
protected void configure(D registration) {
registration.setAsyncSupported(this.asyncSupported);
// óʼ
if (!this.initParameters.isEmpty()) {
registration.setInitParameters(this.initParameters);
}
}
Ҫ˳ʼá
ķServletRegistrationBean onStartup(...) Ҫ
servlet ӵservletFilterRegistrationBean ServletListenerRegistrationBean עƣͲ˵ˡ
ServletContextInitializer#onStartup ִעѾˣ ServletContextInitializer#onStartup ִеġעһ̱Ƚϸӣ漰 tomcat ̣ⲿֻעص룬һ̡
tomcat Ϊһϵеĵ٣ TomcatStarter еģ£
class TomcatStarter implements ServletContainerInitializer {
private final ServletContextInitializer[] initializers;
TomcatStarter(ServletContextInitializer[] initializers) {
this.initializers = initializers;
}
@Override
public void onStartup(Set<Class<?>> classes, ServletContext servletContext)
throws ServletException {
try {
for (ServletContextInitializer initializer : this.initializers) {
// ִ ServletContextInitializer#onStartup
initializer.onStartup(servletContext);
}
}
catch (Exception ex) {
this.startUpException = ex;
...
}
}
...
}
TomcatStarter springboot ṩ࣬ʵ ServletContainerInitializer ServletContextInitializer``ServletContainerInitializer tomcat ṩģ tomcat ʱִ ServletContainerInitializer#onStartup servlt 3.0 淶
ô TomcatStarter ӵ tomcat еأȻ servlt 3.0 淶ͨ spi ɨ赽 ServletContainerInitializer ʵ֣ԲģΪ tomcat ͨ spi ɨõ TomcatStarter ʵijԱ initializers ֵˣӵ tomcat ǰTomcatStarter Ҫʵ initializers Ҫֵ
εԣ TomcatStarter TomcatServletWebServerFactory#configureContext ӵ tomcat ģؼ:
Կinitializers 뵽 TomcatStarter Ĺ췽Уõ TomcatStarter ʵֶӵ tomcat ˡ
ô initializers ȡأʵϣǵ XxxRegistrationBean Ҫ spring УҪȡĻֻҪ beanFactory.getBeansOfType(...) ͿˣServletContextInitializerBeans#addServletContextInitializerBean(String, ServletContextInitializer, ListableBeanFactory) Ǹµģ
private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
for (Class<? extends ServletContextInitializer> initializerType : this.initializerTypes) {
// ȡ ServletContextInitializer: getOrderedBeansOfType(beanFactory, initializerType)
for (Entry<String, ? extends ServletContextInitializer> initializerBean
: getOrderedBeansOfType(beanFactory, initializerType)) {
addServletContextInitializerBean(initializerBean.getKey(),
initializerBean.getValue(), beanFactory);
}
}
}
/**
* Ӳ
*/
private void addServletContextInitializerBean(String beanName,
ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
// ServletRegistrationBean
if (initializer instanceof ServletRegistrationBean) {
Servlet source = ((ServletRegistrationBean<?>) initializer).getServlet();
addServletContextInitializerBean(Servlet.class, beanName, initializer,
beanFactory, source);
}
// FilterRegistrationBean
else if (initializer instanceof FilterRegistrationBean) {
Filter source = ((FilterRegistrationBean<?>) initializer).getFilter();
addServletContextInitializerBean(Filter.class, beanName, initializer,
beanFactory, source);
}
// DelegatingFilterProxyRegistrationBean
else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
}
// ServletListenerRegistrationBean
else if (initializer instanceof ServletListenerRegistrationBean) {
EventListener source = ((ServletListenerRegistrationBean<?>) initializer).getListener();
addServletContextInitializerBean(EventListener.class, beanName, initializer,
beanFactory, source);
}
else {
// ServletContextInitializer Bean
addServletContextInitializerBean(ServletContextInitializer.class, beanName,
initializer, beanFactory, initializer);
}
}
ķ springboot ע servlet ̣
Servlet Ϊ 3 ע᷽ʽʹ XxxRegistrationBean עᡢʹ servlet ע (@WebServlet/@WebFilter/@WebListener) עᣬԼʵ ServletContextInitializer ӿֶע@ServletComponentScan עɨServletRegistrationBean Ϊ˽ ServletRegistrationBean עᵽ servletServletContainerInitializer#onStartup ִԭӣhttps://my.oschina.net/funcy/blog/4951050 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע