美文网首页Java
spring@ServletComponentScan如何生效

spring@ServletComponentScan如何生效

作者: guessguess | 来源:发表于2020-06-29 16:39 被阅读0次

先准备环境
pom文件

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gee</groupId>
    <artifactId>sb-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 开启热部署 -->
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- 监控 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- json -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
        </dependency>

        <!-- 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- 指定maven编译的jdk的版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!-- 打包成springboot专用的jar包,指定入口信息等等 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

整个项目结构如下


image.png

上配置类

@SpringBootApplication
@EnableAspectJAutoProxy
@ServletComponentScan
public class Config {
    public static void main(String args[]) {
        SpringApplication.run(Config.class, args);
    }
}

准备一个controller

@RestController
@RequestMapping("/test")
public class TestController {
    
    @GetMapping(value = "/hello")
    public String test() {
        return "hello world";
    }
}

添加一个过滤器

@WebFilter(urlPatterns = "/*")
public class UrlFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init filter=" +         this.getClass().getName());
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String token = request.getParameter("token");
        if(StringUtils.isEmpty(token)) {
            return;
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        System.out.println("destroy filter=" +      this.getClass().getName());     
    }

}

启动配置类,进行测试。
http://localhost:8080/test/hello?token=123](http://localhost:8080/test/hello?token=123
代码刚刚好我们定义的webFilter

image.png
直接放行,最后返回hello world说明测试是成功的.环境已经准备好了。

那么下面先抛出几个问题。
@ServletComponentScan注解是如何生效的。
@WebFilter又是如何被注入到容器呢。

先来观察一下ServletComponentScan注解本身。从代码中可以看到有一个Import标签,@Import(ServletComponentScanRegistrar.class),这里的意思是将这个类导入spring容器,归spring管理。在容器刷新,后置处理器执行的时候,ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法会扫描用户自己交给spring管理的类,在这个过程中,所有用户自己定义的bean最后都会扫描有没有被@Import修饰,若有则会将@Import标签中的类注册到容器。这里就不讲的太细致了。关键点就在于这个交给spring管理的类ServletComponentScanRegistrar。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ServletComponentScanRegistrar.class)
public @interface ServletComponentScan {

    /**
     * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
     * declarations e.g.: {@code @ServletComponentScan("org.my.pkg")} instead of
     * {@code @ServletComponentScan(basePackages="org.my.pkg")}.
     * @return the base packages to scan
     */
    @AliasFor("basePackages")
    String[] value() default {};

    /**
     * Base packages to scan for annotated servlet components. {@link #value()} is an
     * alias for (and mutually exclusive with) this attribute.
     * <p>
     * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
     * package names.
     * @return the base packages to scan
     */
    @AliasFor("value")
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages()} for specifying the packages to
     * scan for annotated servlet components. The package of each class specified will be
     * scanned.
     * @return classes from the base packages to scan
     */
    Class<?>[] basePackageClasses() default {};

}

那么下面来看看ServletComponentScanRegistrar这个类。看到一个很关键的地方,这个类实现了ImportBeanDefinitionRegistrar这个接口是专门用来注册导入的类的,核心方法便是registerBeanDefinitions。而这个方法最重要的步骤就是注册了ServletComponentRegisteringPostProcessor,看名字就是Servlet组件的后置处理器。那我们直接看看这个类的代码。

class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    private static final String BEAN_NAME = "servletComponentRegisteringPostProcessor";

    //注册导入类
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
            BeanDefinitionRegistry registry) {
        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
        //如果容器已经注册过这个bean了,那么更新,否则直接注册
        if (registry.containsBeanDefinition(BEAN_NAME)) {
            updatePostProcessor(registry, packagesToScan);
        }
        else {
            //直接进行注册,注册后置处理器ServletComponentRegisteringPostProcessor
            addPostProcessor(registry, packagesToScan);
        }
    }

    private void updatePostProcessor(BeanDefinitionRegistry registry,
            Set<String> packagesToScan) {
        BeanDefinition definition = registry.getBeanDefinition(BEAN_NAME);
        ValueHolder constructorArguments = definition.getConstructorArgumentValues()
                .getGenericArgumentValue(Set.class);
        @SuppressWarnings("unchecked")
        Set<String> mergedPackages = (Set<String>) constructorArguments.getValue();
        mergedPackages.addAll(packagesToScan);
        constructorArguments.setValue(mergedPackages);
    }
    //注册ServletComponentRegisteringPostProcessor后置处理器。那么这个后置处理器调用的时机在哪里?
    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);
    }

    private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                metadata.getAnnotationAttributes(ServletComponentScan.class.getName()));
        String[] basePackages = attributes.getStringArray("basePackages");
        Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
        Set<String> packagesToScan = new LinkedHashSet<>();
        packagesToScan.addAll(Arrays.asList(basePackages));
        for (Class<?> basePackageClass : basePackageClasses) {
            packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
        }
        if (packagesToScan.isEmpty()) {
            return Collections
                    .singleton(ClassUtils.getPackageName(metadata.getClassName()));
        }
        return packagesToScan;
    }

}

接下来我们来看看究竟这个后置处理器是如何执行的直接debug一下便是。


image.png

从上图看,最终还是到了容器到refresh方法,然后去执行后置处理器,所以我们下面一步一步来,将流程捋清楚便是。
1.从入口开始

@SpringBootApplication
@EnableAspectJAutoProxy
@ServletComponentScan
public class Config {
    public static void main(String args[]) {
        SpringApplication.run(Config.class, args);
    }
}

2.创建上下文,随后进行刷新

public class SpringApplication {
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            //创建容器,随后进行刷新
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            //刷新容器,直接往里面走
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, listeners, exceptionReporters, ex);
            throw new IllegalStateException(ex);
        }
        listeners.running(context);
        return context;
    }
}

3.容器刷新

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext {
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            //刷新的前置准备,修改上下文的状态
            prepareRefresh();

            // 获取bean工厂
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // 提供给子类去处理beanFac的接口
                postProcessBeanFactory(beanFactory);

                // 执行beanFactory的后置处理器同时实例化,这里是重点,直接往里面走
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册bean的后置处理器,同时实例化
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context subclasses.
                onRefresh();

                // 注册监听器
                registerListeners();

                // 将剩余没有实例化的bean进行实例
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

}

4.执行beanFac的后置处理器,这里面逻辑很复杂,但是,也是比较清晰的,看注解就好。

class PostProcessorRegistrationDelegate {
    public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

        // 已经执行过的后置处理器
        Set<String> processedBeans = new HashSet<>();
        //r容器本身就是BeanDefinitionRegistry的子类,所以会往里面走
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
            //beanFactoryPostProcessors其实是缓存,但是一开始是没缓存的,所以不会执行
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                }
                else {
                    regularPostProcessors.add(postProcessor);
                }
            }

            //局部变了,用于记录需要被执行的后置处理器
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

            // 首先从注册表中找出所有BeanDefinitionRegistryPostProcessor的实现类名字
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            //进行遍历
            for (String ppName : postProcessorNames) {
                //找出已经实现优先级接口的BeanDefinitionRegistryPostProcessor
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    //实例化,同时加入局部变量,表示待会会被执行
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    //这些bean待会会被执行,所以先加入已经被执行的列表
                    processedBeans.add(ppName);
                }
            }
            //排序
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            //执行后置处理器
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();

            // 这里也是类似的,只不过这个时候是执行实现Ordered的BeanDefinitionRegistryPostProcessor
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();

            //因为前面俩个执行的都是内部的BeanDefinitionRegistryPostProcessor,在执行的过程中,说不定会有新的用户自定义的BeanDefinitionRegistryPostProcessor注册,于是乎需要再将所有的BeanDefinitionRegistryPostProcessor找出来,执行一遍
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    //已经执行过则不会再进行执行
                    if (!processedBeans.contains(ppName)) {
                        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                        processedBeans.add(ppName);
                        reiterate = true;
                    }
                }
                sortPostProcessors(currentRegistryProcessors, beanFactory);
                registryProcessors.addAll(currentRegistryProcessors);
                invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
                currentRegistryProcessors.clear();
            }

            // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
            invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        }

        else {
            // Invoke factory processors registered with the context instance.
            invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
        }

        // 随后执行beanFactory的后置处理器,大致原理也是类似的,优先执行排序过的,最后执行没排序的。同时进行实例化
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

        // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        List<String> orderedPostProcessorNames = new ArrayList<>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // skip - already processed in first phase above
            }
            else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

        // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
        List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : orderedPostProcessorNames) {
            orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

        // Finally, invoke all other BeanFactoryPostProcessors.
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        //ServletComponentRegisteringPostProcessor是没有实现优先级排序的,所以会在此处执行,直接进入该方法。
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

        // Clear cached merged bean definitions since the post-processors might have
        // modified the original metadata, e.g. replacing placeholders in values...
        beanFactory.clearMetadataCache();
    }

    /**
     * Invoke the given BeanFactoryPostProcessor beans.
     */
    private static void invokeBeanFactoryPostProcessors(
            Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
        //责任链模式,到ServletComponentRegisteringPostProcessor查看该方法
        for (BeanFactoryPostProcessor postProcessor : postProcessors) {
            postProcessor.postProcessBeanFactory(beanFactory);
        }
    }
}

5.ServletComponentRegisteringPostProcessor的postProcessBeanFactory方法

class ServletComponentRegisteringPostProcessor
        implements BeanFactoryPostProcessor, ApplicationContextAware {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
            throws BeansException {
        if (isRunningInEmbeddedWebServer()) {
            ClassPathScanningCandidateComponentProvider componentProvider = createComponentProvider();
            //这个package就是标签所在的包,可以指定也可以不指定,随后去扫描包。找到包下对应的所有的filter,listener, servlet,直接往里面走
            for (String packageToScan : this.packagesToScan) {
                scanPackage(componentProvider, packageToScan);
            }
        }
    }

    //找出包下面的所有被@webFIlter,@webListener,@webServlet的class,然后通过ServletComponentHandler进行注册,下面我们看看是如何获取这些bean的,关键在于findCandidateComponents这个方法。
    private void scanPackage(
            ClassPathScanningCandidateComponentProvider componentProvider,
            String packageToScan) {
        for (BeanDefinition candidate : componentProvider
                .findCandidateComponents(packageToScan)) {
            if (candidate instanceof ScannedGenericBeanDefinition) {
                for (ServletComponentHandler handler : HANDLERS) {
                    handler.handle(((ScannedGenericBeanDefinition) candidate),
                            (BeanDefinitionRegistry) this.applicationContext);
                }
            }
        }
    }
}

6.如何找到被@webFIlter,@webListener,@webServlet的class,findCandidateComponents方法

public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
    private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
        Set<BeanDefinition> candidates = new LinkedHashSet<>();
        try {
            String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    resolveBasePackage(basePackage) + '/' + this.resourcePattern;
            //这里便是获取路径下的所有资源,也就是class集合。        
            Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
            boolean traceEnabled = logger.isTraceEnabled();
            boolean debugEnabled = logger.isDebugEnabled();
            for (Resource resource : resources) {
                if (traceEnabled) {
                    logger.trace("Scanning " + resource);
                }
                if (resource.isReadable()) {
                    try {
                        MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
                        //这里便是核心,存在着3个过滤器AnnotationTypeFilter,会去判断是否含有@webFIlter,@webListener,@webServlet的注释,若存在则加入到candidates中
                        if (isCandidateComponent(metadataReader)) {
                            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                            sbd.setResource(resource);
                            sbd.setSource(resource);
                            if (isCandidateComponent(sbd)) {
                                if (debugEnabled) {
                                    logger.debug("Identified candidate component class: " + resource);
                                }
                                candidates.add(sbd);
                            }
                            else {
                                if (debugEnabled) {
                                    logger.debug("Ignored because not a concrete top-level class: " + resource);
                                }
                            }
                        }
                        else {
                            if (traceEnabled) {
                                logger.trace("Ignored because not matching any filter: " + resource);
                            }
                        }
                    }
                    catch (Throwable ex) {
                        throw new BeanDefinitionStoreException(
                                "Failed to read candidate component class: " + resource, ex);
                    }
                }
                else {
                    if (traceEnabled) {
                        logger.trace("Ignored because not readable: " + resource);
                    }
                }
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
        }
        return candidates;
    }
}

7.找到这些被@webFIlter,@webListener,@webServlet标记的class之后呢,如何注入容器。回到ServletComponentRegisteringPostProcessor,看看这个方法,里面有一个HANDLERS,其实这是ServletComponentRegisteringPostProcessor初始化的时候加入进去的,先看看这些HANDLERS是什么。看到这里一目了然了。就是先找出对应的类,然后处理器去处理就是。这里我们只看看webFilterHandler的。


image.png
    private void scanPackage(
            ClassPathScanningCandidateComponentProvider componentProvider,
            String packageToScan) {
        for (BeanDefinition candidate : componentProvider
                .findCandidateComponents(packageToScan)) {
            if (candidate instanceof ScannedGenericBeanDefinition) {
                for (ServletComponentHandler handler : HANDLERS) {
                    //handler轮流去处理所有那些被@webFIlter,@webListener,@webServlet标记的class
                    handler.handle(((ScannedGenericBeanDefinition) candidate),
                            (BeanDefinitionRegistry) this.applicationContext);
                }
            }
        }
    }

8.webFilterHandler如何工作,webFilterHandler是ServletComponentHandler的子类

abstract class ServletComponentHandler {
    void handle(ScannedGenericBeanDefinition beanDefinition,
            BeanDefinitionRegistry registry) {
      //这里是一个通用方法,目的是找出是否被对应的注解所标记,webFilterHandler里面this.annotationType就是@WebFilter,
        Map<String, Object> attributes = beanDefinition.getMetadata()
                .getAnnotationAttributes(this.annotationType.getName());
        if (attributes != null) {
             //若是被@WebFilter修饰,则注册,后面会在容器初始化的时候被实例化。
            doHandle(attributes, beanDefinition, registry);
        }
    }
}

class WebFilterHandler extends ServletComponentHandler {

    WebFilterHandler() {
        super(WebFilter.class);
    }
    //将bean注册到注册表中,就是DefaultListableBeanFactory中beanDefinitionMap中,到这里,整个流程就跑通了,至于tomcat如何跟spring对接,这里就后面再看了。起码到这一步,webFilter如何被spring管理,整个流程已经梳理清楚了。
    @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));
        registry.registerBeanDefinition(name, builder.getBeanDefinition());
    }
}

相关文章

网友评论

    本文标题:spring@ServletComponentScan如何生效

    本文链接:https://www.haomeiwen.com/subject/dyrofktx.html