美文网首页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