转载

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 (不常用)

原文  https://segmentfault.com/a/1190000023205328
正文到此结束
Loading...