概述
由於@ServletComponentScan所在類被加載BeanDefinition時,會加載其Registar。所以會導入ServletComponentScanRegistrar,由此向beanfactory添加了一個ServletComponentRegisteringPostProcessor。當最後調用各種nonOrderedPostProcessors時,會調用ServletComponentRegisteringPostProcessor的postProcessBeanFactory,最終掃描路徑獲取由@WebServlet,@WebFilter,@WebListener註冊的servlet,filter,listener。
前言
我們可以看見@ServletComponentScan import 了ServletComponentScanRegistrar
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {
......
}
而ServletComponentScanRegistrar向beanfactory添加了ServletComponentRegisteringPostProcessor
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);
}
......
}
入口
通過@ServletComponentScan所在組件類加載BeanDefinition時,加載ServletComponentScanRegistrar
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
......
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//加載ServletComponentScanRegistrar
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
然後調用ServletComponentScanRegistrar的registerBeanDefinitions:向BeanDefinitionRegistry添加ServletComponentRegisteringPostProcessor
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
//根據註解所在類的元信息獲取掃描包路徑,如果沒有定義註解掃描的包路徑,就以註解所在類的包路徑爲默認路徑
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
//是否已有ServletComponentRegisteringPostProcessor,無則添加,有則更新
if (registry.containsBeanDefinition(BEAN_NAME)) {
updatePostProcessor(registry, packagesToScan);
}
else {
addPostProcessor(registry, packagesToScan);
}
}
執行
AbstractApplicationContext:其中refresh方法會調用各個後處理器
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
......
// 調用各個後處理器,添加各種beandefinition
invokeBeanFactoryPostProcessors(beanFactory);
......
}
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors:
統一處理各種BeanFactoryPostProcessor,最後一種BeanFactoryPostProcessor處理就是有關ServletComponentRegisteringPostProcessor處理servlet,filter,listener
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
......
//添加各類bean
}
......
// Finally, invoke all other BeanFactoryPostProcessors.
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
//調用ServletComponentRegisteringPostProcessor處理servlet,filter,listener
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
......
}
ServletComponentRegisteringPostProcessor
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
//必須是嵌入式的tomcat並且此時ServletContext爲null
if (isRunningInEmbeddedWebServer()) {
//獲取環境和ResourceLoader,及確定需要掃描@WebServlet,@WebFilter,@WebListener
ClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider();
//packagesToScan是@ServletComponentScan的掃描路徑
for (String packageToScan : this.packagesToScan) {
scanPackage(componentProvider, packageToScan);
}
}
}
private void scanPackage(
ClassPathScanningCandidateComponentProvider componentProvider,
String packageToScan) {
//獲取包路徑下有@WebServlet,@WebFilter,@WebListener的類
for (BeanDefinition candidate : componentProvider
.findCandidateComponents(packageToScan)) {
if (candidate instanceof ScannedGenericBeanDefinition) {
for (ServletComponentHandler handler : HANDLERS) {
handler.handle(((ScannedGenericBeanDefinition) candidate),
(BeanDefinitionRegistry) this.applicationContext);
}
}
}
}
WebServletHandler.doHandle:最終添加Servlet的BeanDefinition
@Override
public void doHandle(Map<String, Object> attributes,
ScannedGenericBeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(ServletRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("initParameters", extractInitParameters(attributes));
builder.addPropertyValue("loadOnStartup", attributes.get("loadOnStartup"));
String name = determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);
builder.addPropertyValue("servlet", beanDefinition);
builder.addPropertyValue("urlMappings", extractUrlPatterns(attributes));
builder.addPropertyValue("multipartConfig",
determineMultipartConfig(beanDefinition));
//註冊BeanDefinition
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}
WebFilterHandler:最終添加合法的filter的BeanDefinition
@Override
public void doHandle(Map<String, Object> attributes,
ScannedGenericBeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(FilterRegistrationBean.class);
builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
builder.addPropertyValue("dispatcherTypes", extractDispatcherTypes(attributes));
builder.addPropertyValue("filter", beanDefinition);
builder.addPropertyValue("initParameters", extractInitParameters(attributes));
String name = determineName(attributes, beanDefinition);
builder.addPropertyValue("name", name);
builder.addPropertyValue("servletNames", attributes.get("servletNames"));
builder.addPropertyValue("urlPatterns", extractUrlPatterns(attributes));
//註冊BeanDefinition
registry.registerBeanDefinition(name, builder.getBeanDefinition());
}
對於Listener處理差不多,通過WebListenerHandler.doHandle()
@Override
protected void doHandle(Map<String, Object> attributes,
ScannedGenericBeanDefinition beanDefinition,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.rootBeanDefinition(ServletListenerRegistrationBean.class);
builder.addPropertyValue("listener", beanDefinition);
//註冊BeanDefinition
registry.registerBeanDefinition(beanDefinition.getBeanClassName(),
builder.getBeanDefinition());
}