解析源碼---結合@ServletComponentScan與@WebServlet,@WebFilter,@WebListener註冊servlet,filter,listener

概述

由於@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());
   }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章