java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > @ComponentScan注解

Spring中的@ComponentScan注解详解

作者:nsnsttn

这篇文章主要介绍了Spring中的@ComponentScan注解详解,ComponentScan做的事情就是告诉Spring从哪里找到bean,由你来定义哪些包需要被扫描,一旦你指定了,Spring将会在被指定的包及其下级包中寻找bean,需要的朋友可以参考下

Spring注解 @ComponentScan

1.添加 @ComponentScan 注解

创建一个配置类,在配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的

 <context:component-scan>

2.获取已经注册到容器中的 bean 的名称以及数量

使用 ApplicationContext 的 getBeanDefinitionNames() 方法和getBeanDefinitionCount()获取已经注册到容器中的 bean 的名称以及数量

@SpringBootApplication
public class ZzyNotesApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(ZzyNotesApplication.class, args);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames) {
            System.out.println("beanName: " + beanName);
        }
        System.out.println("bean总数:"+context.getBeanDefinitionCount());
    }
}

3.@ComponentScan

@SpringBootApplication注解中已经存在,也可以根据需要自定义		
@SpringBootApplication(scanBasePackages = "")

常用参数:

1.value || basePackages = "包路径,默认当前类所在包"

2.excludeFilters 使用 excludeFilters 来按照规则排除某些包的扫描。

3.includeFilters 用includeFilters配置 扫描的类 

优先级由上之下,比如自定义的MyTypeFilter如果已经Bean已经在ioc容器中,或者上面的excludeFilters已经过滤掉这个Bean,则不扫描这个类

4.useDefaultFilters

默认为true ,会优先执行默认的过滤器 对 @Component、@ManagedBean、@Named注解的Bean进行扫描 所以要改为false

配置类代码如下

@Configuration
@ComponentScans(
        {
        @ComponentScan(value = "com.zzy.zzyNotes" ,useDefaultFilters = false),
        @ComponentScan(value = "com.zzy.zzyNotes.spring.createBean",
                excludeFilters = {
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Service.class}),//排除包含注解Service的类(不生效,原因未知)
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = {ExcludeMyAnnotation.class})//排除包含注解MyAnnotation2的类
                },
                includeFilters = {
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {IncludeMyAnnotation.class}),//指定扫描包换注解MyAnnotation的类
                        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),//指定注解扫描包换注解Controller的类
                        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE , classes = {Person2.class}),//指定类型Person2的类
                        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})//自定义过滤规则
                }
                , useDefaultFilters = false//这个没有效果,必须在启动类上的@ComponentScan( useDefaultFilters = false)中配置 false
        )
        }
)
public class BeanConfig {
}
/**
 * @author zzy
 * @createDate: 2021-12-30 16:26:50
 * @description: 自定义注解 指定某个类被扫描
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IncludeMyAnnotation {
}

/**
 * @author zzy
 * @createDate: 2021-12-30 16:26:50
 * @description: 自定义注解 排除某个类被扫描
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcludeMyAnnotation {
}

/**
 * 扫描包自定义规则
 * metadataReader:读取到当前正在扫描类的信息
 * metadataReaderFactory:可以获取到其他任何类的信息
 *	注意:只有不满足其它的规则,才会被自定义过滤规则判断
 * @author zzy
 */
public class MyTypeFilter implements TypeFilter {

    /**
    * @description:  扫描规则
    * @params:
    * @return: 返回true 加入IOC容器 false ,排除
    */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
        throws IOException {
        //获取当前类注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描类的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源信息 (比如类存在哪个盘,类的路径  )
        Resource resource = metadataReader.getResource();
        String name = classMetadata.getClassName();
        System.out.println("Filter扫描的类名:" + name);
        if(name.contains("Person3")){
            return true;
        }
        return false;
    }
}
/**
 * @author zzy
 * @createDate: 2021-12-30 10:08:35
 * @description: 创建Bean Person1 加IncludeMyAnnotation
 */
@IncludeMyAnnotation
public class Person1 {
}

/**
 * @author zzy
 * @createDate: 2021-12-30 10:10:37
 * @description: 创建Bean Person1 加@ExcludeMyAnnotation 被排除
 * 正常有@Component就会被扫描,加了@ExcludeMyAnnotation就会被排除
 */
@ExcludeMyAnnotation
@Component
public class Person2 {
}
/**
 * @author zzy
 * @createDate: 2021-12-30 17:03:44
 * @description: 创建Bean Person3  符合MyTypeFilter过滤规则
 */
public class Person3 {
}

其他问题

优先级

注意

1.自定义@ComponentScan时注意控制的路径范围

2.有重名的Bean会注册失败

问题

spring 有默认的规律规则 会对 @Component、@ManagedBean、@Named注解的Bean进行扫描,如果设置了 

excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Service.class})

但是加了@service的类依然被注册到ioc

所以要设置 useDefaultFilters = false 

到此这篇关于Spring中的@ComponentScan注解详解的文章就介绍到这了,更多相关@ComponentScan注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文