乐趣区

Spring注解驱动开发笔记ComponentScan

ComponentScan 注解
  1. @ComponentScan 用法 1:
package com.niewj.config;

import com.niewj.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan("com.niewj")
public class MainConfig {

    @Bean
    public Person person() {return new Person("張三", 22);
    }
}

(0). 惯例: @ComponentScan(value="com.niewj")

(1). FilterType.ANNOTATION 只排除注解 value + excludeFilters

@ComponentScan( // 只排除:
        value = "com.niewj",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)}
)

(2).FilterType.ANNOTATION 只过滤注解: 须要加上 value + useDefaultFilters=false + includeFilters

@ComponentScan( // 只蕴含: 必须要写 useDefaultFilters 否则不失效
        value = "com.niewj",
        useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)}
)

(3). FilterType.ASSIGNABLE_TYPE : 制订具体的类型, includeFilters 和 excludeFilters 自身就是个数组!

@ComponentScan( // 只蕴含: 必须要写 useDefaultFilters 否则不失效
        value = "com.niewj",
        useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BookService.class)
        }
)
  1. 自定义 TypeFilter @ComponentScan 用法:
@Test
public void testTypeFilter() {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
    Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
}

输入如下:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
person

MainConfig.java:

package com.niewj.config;

import com.niewj.bean.Person;
import com.niewj.util.MyComponentScanTypeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(value = "com.niewj",
        useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyComponentScanTypeFilter.class)
        }
)
public class MainConfig {

    @Bean
    public Person person() {return new Person("張三", 22);
    }
}

次要看 MyComponentScanTypeFilter 的类申明: 它的判断逻辑是满足一下两点, 则匹配!

  1. 如果类有注解 @Controller
  2. 如果类是 BaseController 的子类
package com.niewj.util;

import com.niewj.controller.BaseController;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

/**
 * 自定义 ComponentScan 形式:
 */
public class MyComponentScanTypeFilter implements TypeFilter {
    /**
     * 此处的判断逻辑是:
     * 如果
     * 1. 类是 BaseController 的子类
     * 2. && 注解蕴含 @Controller, 则匹配!
     *
     * @param metadataReader        获取到的以后类的注解信息
     * @param metadataReaderFactory 可获取到其余类信息的工厂
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        // 1. 获取以后类的注解信息
        AnnotationMetadata annoMetadata = metadataReader.getAnnotationMetadata();
        // 2. 获取以后正在扫描的类信息:
        ClassMetadata classMetadata = metadataReader.getClassMetadata();

        if (isBaseController(classMetadata) && hasControllerAnnotation(annoMetadata)) {return true;}
        return false;
    }

    /**
     * 条件 1: 正在扫描的类 是不是 BaseController 的子类
     *
     * @param classMetadata
     * @return
     */
    private boolean isBaseController(ClassMetadata classMetadata) {
        // 3. 正在扫描的类名称
        String className = classMetadata.getClassName();

        // 4. 正在扫描的类的父类, 格局: BookController->com.niewj.controller.BaseController
        String superClassName = classMetadata.getSuperClassName();
        return superClassName.contains(BaseController.class.getSimpleName());
    }

    /**
     * 判断注解中有无 Controller "org.springframework.stereotype.Controller"
     *
     * @param annotationMetadata
     * @return
     */
    private boolean hasControllerAnnotation(AnnotationMetadata annotationMetadata) {return annotationMetadata.getAnnotationTypes().stream().anyMatch(e -> e.equals("org.springframework.stereotype.Controller"));
    }
}

小结: ComponentScan 扫描大抵罕用有这么几类:

1. 一般 @ComponentScan(value=”com.niewj”)

2. 注解过滤排除: @ComponentScan(value=”com.niewj”, excludeFilters={filter1, filter2,…})

3. 注解过滤蕴含: @ComponentScan(value=”com.niewj”, includeFilters={filter1, filter2, …})

其中的 Filter 蕴含

(1). 注解过滤匹配: type = FilterType.ANNOTATION
(2). 指定的类名比配: type=FilterType.ASSIGNABLE_TYPE
(3). 自定义类型匹配: type=FilterType.CUSTOM 如示例中的:

MyComponentScanTypeFilter implements `TypeFilter`

(4). type=FilterType.ASPECTJ (不罕用)
(5). 正则匹配 type=FilterType.REGEX (不罕用)

退出移动版