当前位置:首页 > 英文周记 > 正文内容

componentscan「ComponentScans」

更新时间:2026-07-18 00:59:25 周记网3年前 (2023-02-17)英文周记122

(新手勿进,全是代码)@ComponentScan、@ComponentScans详解

这些问题如果都ok,恭喜你,太优秀了,不知道没关系,一起来看看。

到目前为止,介绍了2种注册bean的方式:

componentscan「ComponentScans」

通常情况下,项目中大部分类都需要交给spring去管理,按照上面这2种方式,代码量还是挺大的。

为了更方便bean的注册,Spring提供了批量的方式注册bean,方便大量bean批量注册,spring中的@ComponentScan就是干这个事情的。

@ComponentScan用于批量注册bean。

这个注解会让spring去扫描某些包及其子包中所有的类,然后将满足一定条件的类作为bean注册到spring容器容器中。

具体需要扫描哪些包?以及这些包中的类满足什么条件时被注册到容器中,这些都可以通过这个注解中的参数动态配置。

先来看一下这个注解的定义:

@ComponentScan工作的过程:

1. Spring会扫描指定的包,且会递归下面子包,得到一批类的数组

2. 然后这些类会经过上面的各种过滤器,最后剩下的类会被注册到容器中

第一个:需要扫描哪些包?通过 value、backPackages、basePackageClasses 这3个参数来控制

第二:过滤器有哪些?通过 useDefaultFilters、includeFilters、excludeFilters 这3个参数来控制过滤器

这两个问题搞清楚了,就可以确定哪些类会被注册到容器中。

默认情况下,任何参数都不设置的情况下,此时,会将@ComponentScan修饰的类所在的包作为扫描包;默认情况下useDefaultFilters为true,这个为true的时候,spring容器内部会使用默认过滤器,规则是:凡是类上有 @Repository、@Service、@Controller、@Component 这几个注解中的任何一个的,那么这个类就会被作为bean注册到spring容器中,所以默认情况下,只需在类上加上这几个注解中的任何一个,这些类就会自动交给spring容器来管理了。

这几个注解都是spring提供的。

先说一下 @Component 这个注解,看一下其定义:

再来看看 @Repository 源码如下:

其他两个注解 @Service、@Controller 源码和 @Repository 源码类似。

这4个注解本质上是没有任何差别,都可以用在类上面,表示这个类被spring容器扫描的时候,可以作为一个bean组件注册到spring容器中。

spring容器中对这4个注解的解析并没有进行区分,统一采用 @Component 注解的方式进行解析,所以这几个注解之间可以相互替换。

spring提供这4个注解,是为了让系统更清晰,通常情况下,系统是分层结构的,多数系统一般分为controller层、service层、dao层。

@controller通常用来标注controller层组件,@service注解标注service层的组件,@Repository标注dao层的组件,这样可以让整个系统的结构更清晰,当看到这些注解的时候,会和清晰的知道属于哪个层,对于spring来说,将这3个注解替换成@Component注解,对系统没有任何影响,产生的效果是一样的。

下面通过案例来感受@ComponentScan各种用法。

上面几个类中,分别使用了4种注解。

部分输出如下:

指定需要扫毛哪些包,可以通过value或者basePackage来配置,二者选其一,都配置运行会报错,下面我们通过value来配置。

ComponentScanTest中新增个方法

截取了关键几行如下:

可以看出只有controller包和service包中的2个类被注册为bean了。

指定包名的方式扫描存在的一个隐患,若包被重名了,会导致扫描会失效,一般情况下面我们使用basePackageClasses的方式来指定需要扫描的包,这个参数可以指定一些类型,默认会扫描这些类所在的包及其子包中所有的类,这种方式可以有效避免这种问题。

下面来看一下basePackageClasses的方式。

我们可以在需要扫描的包中定义一个标记的接口或者类,他们的唯一的作用是作为basePackageClasses的值,其他没有任何用途。

ComponentScanTest中新增个方法

再来看一下includeFilters这个参数的定义:

是一个 Filter 类型的数组, 多个Filter之间为或者关系,即满足任意一个就可以了 ,看一下 Filter 的代码:

我们自定义一个注解,让标注有这些注解的类自动注册到容器中

下面的代码都在 com.javacode2018.lesson001.demo22.test3 包中。

ComponentScanTest中新增个测试用例

Service1上标注了 @MyBean 注解,被注册到容器了,但是 Service2 上没有标注 @MyBean 啊,怎么也被注册到容器了?

原因:Service2上标注了 @Compontent 注解,而@CompontentScan注解中的 useDefaultFilters 默认是 true ,表示也会启用默认的过滤器,而默认的过滤器会将标注有 @Component、@Repository、@Service、@Controller 这几个注解的类也注册到容器中

如果我们只想将标注有 @MyBean 注解的bean注册到容器,需要将默认过滤器关闭,即:useDefaultFilters=false,我们修改一下ScanBean3的代码如下:

再次运行 test3 输出:

上面的自定义的@MyBean注解,是无法指定bean的名称的,可以对这个注解做一下改造,加个value参数来指定bean的名称,如下:

修改一下Service1的代码:

运行test3用例输出:

此时bean名称就变成了 service1Bean 。

下面的代码都位于 com.javacode2018.lesson001.demo22.test4 包中。

让spring来进行扫描,类型满足IService的都将其注册到容器中。

ComponentScanTest中新增个测试用例

有时候我们需要用到自定义的过滤器,使用自定义过滤器的步骤:

来看一下 TypeFilter 这个接口的定义:

是一个函数式接口,包含一个match方法,方法返回boolean类型,有2个参数,都是接口类型的,下面介绍一下这2个接口。

类元数据读取器,可以读取一个类上的任意信息,如类上面的注解信息、类的磁盘路径信息、类的class对象的各种信息,spring进行了封装,提供了各种方便使用的方法。

看一下这个接口的定义:

类元数据读取器工厂,可以通过这个类获取任意一个类的MetadataReader对象。

源码:

我们来个自定义的Filter,判断被扫描的类如果是 IService 接口类型的,就让其注册到容器中。

来个自定义的TypeFilter类:

ComponentScanTest中新增个测试用例

配置排除的过滤器,满足这些过滤器的类不会被注册到容器中,用法上面和includeFilters用一样,这个我就不演示了,可以自己玩玩

从这个注解的定义上可以看出这个注解可以同时使用多个,如:

还有一种写法,使用@ComponentScans的方式:

@CompontentScan注解是被下面这个类处理的

这个类非常非常关键,主要用户bean的注册,前面我们介绍的@Configuration,@Bean注解也是被这个类处理的。

还有下面这些注解:

以上这些注解都是被ConfigurationClassPostProcessor这个类处理的,内部会递归处理这些注解,完成bean的注册。

以@CompontentScan来说一下过程,第一次扫描之后会得到一批需要注册的类,然后会对这些需要注册的类进行遍历,判断是否有上面任意一个注解,如果有,会将这个类交给ConfigurationClassPostProcessor继续处理,直到递归完成所有bean的注册。

想成为高手,这个类是必看的。

component-scan应该放在哪

component-scan应该放在哪

环境变量的配置

在(系统属性--高级--环境变量--系统变量 中)(以下目录都根据自己的电脑MinGW所在位置不同而改变)

a.在PATH的值中加入“C:\Program Files\MinGWStudio\MinGW\bin”。这是寻找gcc编译器的路径。如果PATH中还有其他内容,需要用英文状态下分号进行分割

b.新建LIBRARY_PATH变量,在其值中加入“C:\Program Files\MinGWStudio\MinGW\lib”。这是标准库存放的路径。

c.新建C_INCLUDE_PATH变量,在其值中加入“C:\Program Files\MinGWStudio\MinGW\include”。这是Include查找头文件的路径。

4.验证gcc是否正常运行

在cmd控制台窗口下面,输入gcc -v。若已经成功安装好,会显示gcc的版本信息。

ComponentScan注解的扫描范围及源码解析

一,ComponentScan注解的默认扫描范围

ComponentScan注解的默认扫描范围是启动程序XxxApplication. java所在目录及其下的所有子包。

为了方便理解,我们看一下下面这个图片。

这个项目中的启动类是:SpringbootApplication.java

该启动类所在的目录是:springboot

那么ComponentScan注解的默认扫描范围是:springboot目录及其下面的所有子包。

二,如何修改ComponentScan注解的扫描范围

ComponentScan注解即可以扫描包,也可以扫描指定的类。我们只需要指定一个包扫描的路径,就可以实现更改包扫描路径的功能了。

1,ComponentScan注解扫描包。

@ComponentScan({"com.company.user","com.company.service"})

2,ComponentScan注解扫描类。

@ComponentScan(basePackageClasses={XxxService.class})

三,ComponentScan注解

ComponentScan注解中定义了12个属性,我们下面详细来看一下。我们的讨论是基于java8的,spring-context的版本是4.3.7。

1,String[] value() default {};

指定包扫描路径,value属性的值,就是项目中的一个具体路径。value属性的类型是String数组,也就是支持一次指定多个包扫描路径。这个属性上面添加了一个注解,@AliasFor("basePackages"),这个注解的意思就是说,value这个属性等价于basePackages属性。关于basePackages属性,下面会讲到。

2,String[] basePackages() default {};

指定包扫描路径,basePackages属性的值,就是项目中的一个具体路径。basePackages属性的类型是String数组,也就是支持一次指定多个包扫描路径。basePackages属性上面添加了一个注解,@AliasFor("value"),这个注解的意思就是说,basePackages这个属性等价于value属性。

3,Class?[] basePackagesClasses() default {};

扫描具体的类。basePackagesClasses属性的类型是Class数组,也就是说支持同时指定多个扫描类。

4,Class? extends BeanNameGenerator nameGenerator() default BeanNameGenerator. class;

配置beanName生成器,默认是BeanNameGenerator。一般情况下,我们都是使用默认的beanName生成器,但是Spring实现了beanName生成器的可配置。

5,Class? extends ScopeMetaDataResolver scopeResolver() default AnnotationScopeMetaDataResolver.class;

处理检测到的bean的scope范围。什么意思呢?我们都知道spring的bean是有作用域的,默认是singleton,这个默认值就是在ScopeMetaData类中指定的:

private String scopeName = "singleton";

这个属性也是可选配置,默认的处理bean作用域的实现类是AnnotationScopeMetaDataResolver.class。源码比较简单,就是取注解上获取指定的scope的value值,如果没有配置,就是用默认的singleton。

6,ScopedProxyMode scopedProxy() default ScopedProxyMode. DEFAULT;

是否为检测到的组件生成代理。

ScopedProxyMode是一个枚举类,可选值有四个:DEFAULT,NO,INTERFACES,TARGET_CLASS。

7,String resourcePattern() default """**/*.class";

控制符合组件检测条件的类文件,默认是包扫描下的  **/*.class。

8,boolean useDefaultFilters() default true;

是否对含有以下注解的类开启检测,默认是开启的。

@Component

@Repository

@Service

@Controller

9,ComponentScan.Filter[] includeFilters() default {};

指定某些Filter扫描到的类。听起来有些费劲,说白了就是指定了类型,扫描指定的这些类型。可选类型有5种,定义在枚举类FilterType中:

第一种:ANNOTATION

第二种:ASSIGNABLE_TYPE

第三种:ASPECTJ

第四种:REGEX,正则表达式。

第五种:CUSTOM,自定义类型。

10,ComponentScan.Filter[] excludeFilters() default {};

排除过滤器扫描的的类。

11,boolean lazyInit() default false;

扫描到的类是否开启懒加载,默认不开启。

12,

@Retention(RetentionPolicy.RUNTIME);

@Target({})

public @interface Filter {

FilterType type() default FilterType. ANNOTATION;

@AliasFor("classes")

Class?[] value() default {};

@AliasFor("value")

Class?[] classes() default {};

String[] pattern() default {};

}

spring java显式配置@componentscan在哪个包下

如果是指@componentscan的源码,4+版本是在:

org.springframework.context.annotation

...

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

@Documented

public @interface ComponentScan{

    ...

}

如果是指@componentscan扫描哪些包,由basePackages和basePackageClasses来指定:

@ComponentScan(basePackageClasses = AppConfig.class)

// 或者

@ComponentScan(basePackages = "com.sleest.xx")

其中basePackageClasses 为type-safe,类型为Class?[]

basePackages 类型为String[],

源码中都能看到

component-scan包含了启用注解吗

spring

applicationcontext.xml的

标签用途比我想像的还要实用。而且後来才知道,有了

,另一个

标签根本可以移除掉,因为被包含进去了。原本我survery

spring3通常只配置成

,意即在base-package下寻找有@component和@configuration的target

class。

标签: componentscan

“componentscan「ComponentScans」” 的相关文章

componentscan「ComponentScan 无效」

componentscan「ComponentScan 无效」

(新手勿进,全是代码)@ComponentScan、@ComponentScans详解 这些问题如果都ok,恭喜你,太优秀了,不知道没关系,一起来看看。 到目前为止,介绍了2种注册bean的方...

componentscan「ComponentScanAnnotationParser」

componentscan「ComponentScanAnnotationParser」

component-scan包含了启用注解吗 springapplicationcontext.xml的标签用途比我想像的还要实用。而且後来才知道,有了,另一个标签根本可以移除掉,因为被包含进去了。原...

componentscan「componentscan排除某个类」

componentscan「componentscan排除某个类」

(新手勿进,全是代码)@ComponentScan、@ComponentScans详解 这些问题如果都ok,恭喜你,太优秀了,不知道没关系,一起来看看。 到目前为止,介绍了2种注册bean的方...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。