springboot 注解 @ComponentScan

作用

@ComponentScan用于批量注册bean,这个注解会让spring去扫描某些包及其子包中所有的类,然后将满足一定条件的类作为bean 注册到spring容器中。主要使用于多模块的项目中,在总入口中引入其入模块的Bean注入。
使用范围:可以使用于任意类型,一般作用在配置类上。

定义

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    //与basePackages属性互为别名,作用一样
    @AliasFor("basePackages")
    String[] value() default {};

    // 扫描的基础包,与value只能二选一
    @AliasFor("value")
    String[] basePackages() default {};

    // 扫描的类,会扫描该类所在包及其子包的组件
    Class<?>[] basePackageClasses() default {};

    // bean id 生成器,定义了一套生成的bean id的规则
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

   
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    // 定义扫描的规则
    String resourcePattern() default "**/*.class";

    // 是否使用默认的过滤器,默认为true
    boolean useDefaultFilters() default true;

    // 包含过滤器,用来配置被扫描出来的那些类会被作为组件注册到容器中
    /*
    *指定某些定义Filter满足条件的组件 FilterType有5种类型如:
    *                        ANNOTATION, 注解类型 默认
                             ASSIGNABLE_TYPE,指定固定类
                             ASPECTJ, ASPECTJ类型
                             REGEX,正则表达式
                             CUSTOM,自定义类型
    */
    Filter[] includeFilters() default {};
    
    // 排除过滤器,用来对扫描的类进行排除的,被排除的类不会被注册到容器中
    Filter[] excludeFilters() default {};
    
    //是否延迟加载,默认为false,也就是默认bean是立即加载到容器中。
    boolean lazyInit() default false;

    //内部注解,是定义扫描规则的注解
    @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 {};
    }
}

参数

valuebasePackages

该属性配置的是spring要扫描的基础包,定义了之后,spring默认会扫描该包及其子包下的相应注解生成bean组件。
该属性是一个数组,也就是可以定义多个基础包。
当该属性不设置的时候,默认扫描该配置类所在的包及其子包下的组件。

package com.example.demo.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDao {
}
package com.example.demo.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@ComponentScan(value = "com.example.demo.dao")
@Configuration
public class UserConfig {
}
public class injectTest {

    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        for(String beanName: context.getBeanDefinitionNames()){
            System.out.println(String.format("Bean名称:%s,bean对象:%s", beanName, context.getBean(beanName)));
        }
    }
}

结果输出:

Bean名称:userConfig,bean对象:com.example.demo.config.UserConfig@2c35e847
Bean名称:userDao,bean对象:com.example.demo.dao.UserDao@7bd4937b

basePackageClasses

配置要扫描的类的class对象,默认会扫描该类所在的包及其子包下的组件。
修改上面的配置文件:

@ComponentScan(value = "com.example.demo.dao", useDefaultFilters = true, basePackageClasses = UserService.class)
@Configuration
public class UserConfig {
}

运行输出:

Bean名称:userConfig,bean对象:com.example.demo.config.UserConfig$$EnhancerBySpringCGLIB$$892447e9@2767e23c
Bean名称:userDao,bean对象:com.example.demo.dao.UserDao@710c2b53
Bean名称:userService,bean对象:com.example.demo.service.UserService@5386659f

这里不但扫描并注入了com.example.demo.dao包下面的userDao,同时userService这个bean也被注入到spring容器中。

nameGenerator

配置bean Id的生成规则,默认是如果组件注解@Component、@Controller、@Service、@Repository、@Named、ManagedBean注解都没有显示配置组件id时,就会把类名第一位转化为小写作为该组件的id。如果不同包中有相同名字的类,在扫描时就会报错。
我们可以通过配置nameGenerator属性自定义我们的组件id生成器。

resourcePattern

该属性设置在基础包的前提下,扫描的路径**表示任意层级,所以默认是从基础包开始任意层级的class文件。
如果修改成
*/*.class 就不会扫描子包,只会扫描当前包的class文件。
**/Serivce.class 只会扫描当前包下的Serivce.class结尾的文件。

lazyInit

设置是否把扫描到的组件延迟实例化,默认为false,表示立即实例化。如果设置为true,容器会在第一次getBean时实例化该组件。

useDefaultFilters

useDefaultFilters属性表示是否启用默认的过滤器,默认过滤器是指被@Component注解 标注的注解,比如ControllerServiceRepositoryComponent。也有其他的@Named等。默认是true,开启。也就是我们可以自定义组件注解,只要用@Component注解在自定义注解上面,spring默认会扫描到。

includeFilters

该属性配置扫描包含过滤器,只包含、不排除,也就是说,例如useDefaultFilters默认为true,默认会对@Compoent等注解进行扫描。然后使用includeFilters属性对自定义@MyComponent注解进行包含,那么,spring仍然会对@Compoent等注解进行扫描,对@MyComponent注解的包含不会导致原有的注解的排除。
includeFilters只包含新的扫描规则,不会排除已有的扫描规则
新建一个UserService2的类,该类不标注任何注解

public class UserService2 {
}
package com.example.demo.config;
@ComponentScan(value = "com.example.demo", useDefaultFilters = true,includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {UserService2.class})
})
@Configuration
public class UserConfig {
}
public class injectTest {

    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        for(String beanName: context.getBeanDefinitionNames()){
            System.out.println(String.format("Bean名称:%s,bean对象:%s", beanName, context.getBean(beanName)));
        }
    }
}

运行输出:

Bean名称:userController,bean对象:com.example.demo.controller.UserController@615f972
Bean名称:userDao,bean对象:com.example.demo.dao.UserDao@285f09de
Bean名称:userService,bean对象:com.example.demo.service.UserService@73393584
Bean名称:userService2,bean对象:com.example.demo.service.UserService2@31500940

从结果可以看出,没有添加任何注解的UserService2也被注入到了Spring容器中。

excludeFilters

此注解要配置不扫描的规则,比如排除了@Component注解后,用该注解的类不会被spring实例化为组件。
注意excludeFilters的优先级比includeFilters高,例如,两个属性分别配置了同样的规则,excludeFilters属性的配置会生效,spring会对该规则进行排除。

总结

1、自定扫描路径下边带有@Controller@Service@Repository@Component注解的类加入到Spring容器中。
2、通过includeFilters加入扫描路径下没有以上注解的类加入Spring容器。
3、通过excludeFilters过滤出不用加入Spring容器的类。
4、自定义增加了@Component注解的注解方式。

原创文章,作者:jiafegn,如若转载,请注明出处:https://www.techlearn.cn/archives/274

Previous 2022年9月26日
Next 2023年3月26日

相关推荐

  • SpringBoot 缓存

    简介 缓存主要是为了提高数据的读取速度。 因为服务器和应用客户端之间存在着流量的瓶颈,所以读取大容量数据时,使用缓存来直接为客户端服务,可以减少客户端与服务器端的数据交互,从而大大…

    springboot 2023年4月23日
    133
  • SpringBoot 整合Memcached

    简介 Memcached 是一个高性能的分布式内存对象的key-value缓存系统,用于动态Web应用以减轻数据库负载,现在也有很多人将它作为内存式数据库在使用,memcached…

    springboot 2023年4月24日
    242
  • SpringBoot 分布式定时任务-Quartz

    简介 Quartz是完全由Java开发的一个开源的作业调度框架。在业务系统中,主要用于做分布式定时任务。Spring本身提供的@Schedule只能实现一些相对简单的单机定时任务,…

    springboot 2023年12月17日
    371
  • Springboot 注解 @Configuration

    作用 @Configuration用于定义配置类,标注在类上,配置spring容器(应用上下文)。相当于把该类作为spring的xml配置文件中的beans。@Configurat…

    springboot 2022年9月2日
    224
  • SpringBoot CRUD基础开发 入门

    需求简介 环境准备 1、新建项目 新建一个crud的项目,如下: 2、新建数据库脚本 新建curd数据库 初始化数据库 引入依赖 1、引入web依赖 2、引入Lombok依赖 3、…

    2023年3月26日
    178
  • SpringBoot 整合 Lombok

    简介 Lombok其实和Spring Boot关系不太大,只是这个工具太好用了,这里也整理记录一下。 Lombok是一个Java库可以与Java IDE(ItelliJ IDEA、…

    2024年8月28日
    261
  • SpringBoot 全局异常统一处理

    前言 在实际的项目开发过程中,会有大量的异常发生,而我们并不能将异常信息反馈到用户,所以在返回结果的时候需要对异常进行处理,可是如果在每个Controller返回结果都需要进行异常…

    springboot 2023年4月29日
    125
  • SpringBoot自定义注解与使用

    简介 注解是一种能添加到Java代码中的元数据,方法,类,参数与包都可以使用注解进行修饰,可以将注解看为一种特殊的标记,在Java编译或运行过程中将有这种特殊标记的部分进行特殊处理…

    springboot 2024年1月25日
    254
  • SpringBoot 过滤器

    简介 SpringBoot过滤器在web开发中可以过滤指定的URL,比如拦截掉不需要的接口请求,同时也可以对request和response的内容进行修改。 使用场景 Spring…

    springboot 2023年4月30日
    241
  • SpringBoot 分布式Session

    简介 现在随着分布式,微服务架构的日益成熟,越来越多的企业将传统的单体服务改造为微服务或是分布式架构,在分布式中就遇到session管理的问题,微服务架构中一个服务为了实现高可用至…

    springboot 2023年4月30日
    176