使用@ComponentScan自动扫描组件

案例准备

1.创建一个配置类,在配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 <context:component-scan>。

  1. package io.mieux.config;
  2. import org.springframework.context.annotation.ComponentScan;
  3. @ComponentScan
  4. public class BeanConfig {
  5. }

2.使用 ApplicationContext 的 getBeanDefinitionNames() 方法获取已经注册到容器中的 bean 的名称。

  1. import io.mieux.config.BeanConfig;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4. public class App02 {
  5. public static void main(String[] args) {
  6. ApplicationContext applicationContext =
  7. new AnnotationConfigApplicationContext(BeanConfig.class);
  8. String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
  9. for (String beanName : beanDefinitionNames) {
  10. System.out.println("beanName: " + beanName);
  11. }
  12. }
  13. }

运行效果:

  1. beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
  2. beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
  3. beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
  4. beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
  5. beanName: org.springframework.context.event.internalEventListenerProcessor
  6. beanName: org.springframework.context.event.internalEventListenerFactory
  7. beanName: beanConfig

除了 spring 本身注册的一些 bean 之外,可以看到最后一行,已经将BeanConfig这个类注册进容器中了。

使用@ComponentScan 的 valule属性配置

3.指定要扫描的包(使用@ComponentScan 的 valule 属性来配置)

创建一个controller 包,并在该包下新建一个 AppController 类。

  1. package io.mieux.controller;
  2. import org.springframework.stereotype.Controller;
  3. @Controller
  4. public class AppController {
  5. }

在类上加了@Controller注解,说明该类是一个 Component。在 BeanConfig 类中修改:

  1. package io.mieux.config;
  2. import org.springframework.context.annotation.ComponentScan;
  3. @ComponentScan(value = "io.mieux.controller")
  4. public class BeanConfig {
  5. }

@ComponentScan 注解中指定了要扫描的包。

运行效果:

  1. beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
  2. beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
  3. beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
  4. beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
  5. beanName: org.springframework.context.event.internalEventListenerProcessor
  6. beanName: org.springframework.context.event.internalEventListenerFactory
  7. beanName: beanConfig
  8. beanName: appController

AppController 已经被注册进容器了。

excludeFilters 和 includeFilters 的使用

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

  1. package io.mieux.config;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.ComponentScan.Filter;
  4. import org.springframework.context.annotation.FilterType;
  5. import org.springframework.stereotype.Controller;
  6. @ComponentScan(value = "io.mieux",
  7. excludeFilters = {@Filter(type = FilterType.ANNOTATION,
  8. value = {Controller.class})})
  9. public class BeanConfig {
  10. }

excludeFilters 的参数是一个 Filter[] 数组,然后指定 FilterType 的类型为 ANNOTATION,也就是通过注解来过滤,最后的 value 则是Controller 注解类。配置之后,在 spring 扫描的时候,就会跳过 io.mieux 包下,所有被 @Controller 注解标注的类。

使用 includeFilters 来按照规则只包含某些包的扫描。

在创建一个 service 的包,并创建一个 AppService 类,再加上一个 @Service 注解。

  1. package io.mieux.service;
  2. import org.springframework.stereotype.Service;
  3. @Service
  4. public class AppService {
  5. }

修改 BeanCofig 类:

  1. package io.mieux.config;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.ComponentScan.Filter;
  4. import org.springframework.context.annotation.FilterType;
  5. import org.springframework.stereotype.Controller;
  6. @ComponentScan(value = "io.mieux", includeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})
  7. public class BeanConfig {
  8. }

运行效果:

  1. beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
  2. beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
  3. beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
  4. beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
  5. beanName: org.springframework.context.event.internalEventListenerProcessor
  6. beanName: org.springframework.context.event.internalEventListenerFactory
  7. beanName: beanConfig
  8. beanName: appController
  9. beanName: appService

配置里面,应该是只包含 @Controller 注解的类才会被注册到容器中,为什么 @Service 注解的类也被注册了呢?

这里涉及到 @ComponentScan 的一个useDefaultFilters 属性的用法,该属性默认值为 true,也就是说 spring 默认会自动发现被 @Component、@Repository、@Service 和 @Controller 标注的类,并注册进容器中。要达到只包含某些包的扫描效果,就必须将这个默认行为给禁用掉(在 @ComponentScan 中将 useDefaultFilters 设为 false 即可)。

  1. package io.mieux.config;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.ComponentScan.Filter;
  4. import org.springframework.context.annotation.FilterType;
  5. import org.springframework.stereotype.Controller;
  6. @ComponentScan(value = "io.mieux",
  7. includeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})},
  8. useDefaultFilters = false)
  9. public class BeanConfig {
  10. }

运行效果:

  1. beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
  2. beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
  3. beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
  4. beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
  5. beanName: org.springframework.context.event.internalEventListenerProcessor
  6. beanName: org.springframework.context.event.internalEventListenerFactory
  7. beanName: beanConfig
  8. beanName: appController

添加多种扫描规则

1、如果使用的 jdk8,则可以直接添加多个 @ComponentScan 来添加多个扫描规则,但是在配置类中要加上 @Configuration 注解,否则无效。

  1. package io.mieux.config;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.Configuration;
  4. @ComponentScan(value = "io.mieux.controller")
  5. @ComponentScan(value = "io.mieux.service")
  6. @Configuration
  7. public class BeanConfig {
  8. }

2、也可以使用 @ComponentScans 来添加多个 @ComponentScan,从而实现添加多个扫描规则。同样,也需要加上 @Configuration 注解,否则无效。

  1. package io.mieux.config;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.ComponentScans;
  4. import org.springframework.context.annotation.Configuration;
  5. @ComponentScans(value =
  6. {@ComponentScan(value = "io.mieux.controller"),
  7. @ComponentScan(value = "io.mieux.service")})
  8. @Configuration
  9. public class BeanConfig {
  10. }

添加自定义过滤规则

在前面使用过 @Filter 注解,里面的 type 属性是一个 FilterType 的枚举类型:

  1. public enum FilterType {
  2. ANNOTATION,
  3. ASSIGNABLE_TYPE,
  4. ASPECTJ,
  5. REGEX,
  6. CUSTOM
  7. }

使用 CUSTOM 类型,就可以实现自定义过滤规则。

1、 首先创建一个实现 TypeFilter 接口的 CustomTypeFilter 类,并实现其 match 方法。

  1. package io.mieux.config;
  2. import org.springframework.core.io.Resource;
  3. import org.springframework.core.type.AnnotationMetadata;
  4. import org.springframework.core.type.ClassMetadata;
  5. import org.springframework.core.type.classreading.MetadataReader;
  6. import org.springframework.core.type.classreading.MetadataReaderFactory;
  7. import org.springframework.core.type.filter.TypeFilter;
  8. import java.io.IOException;
  9. public class CustomTypeFilter implements TypeFilter {
  10. @Override
  11. public boolean match(MetadataReader metadataReader,
  12. MetadataReaderFactory metadataReaderFactory) throws IOException {
  13. // 获取当前扫描到的类的注解元数据
  14. AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
  15. // 获取当前扫描到的类的元数据
  16. ClassMetadata classMetadata = metadataReader.getClassMetadata();
  17. // 获取当前扫描到的类的资源信息
  18. Resource resource = metadataReader.getResource();
  19. if (classMetadata.getClassName().contains("Co")) {
  20. return true;
  21. }
  22. return false;
  23. }
  24. }

这里简单对扫描到的类名进行判断,如果类名包含”Co“的就符合条件,也就会注入到容器中。

2、对 BeanConfig 进行修改,指定过滤类型为 Custom 类型,并指定 value 为 CustomTypeFilter.class。

  1. package io.mieux.config;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.FilterType;
  4. @ComponentScan(value = "io.mieux",
  5. includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, value = {CustomTypeFilter.class})},
  6. useDefaultFilters = false)
  7. public class BeanConfig {
  8. }

运行效果:

  1. beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
  2. beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
  3. beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
  4. beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
  5. beanName: org.springframework.context.event.internalEventListenerProcessor
  6. beanName: org.springframework.context.event.internalEventListenerFactory
  7. beanName: beanConfig
  8. beanName: appController

Springboot配置扫描其它模块路径的方法

@SpringBootApplication=@Configuration+@EnableAutoConfiguration+@ComponentScan,其中扫描包的范围为启动类所在包和子包,不包括第三方的jar包。如果我们需要扫描通过maven依赖添加的jar,我们就要单独使用@ComponentScan注解扫描第三方包。

但是,如果@SpringBootApplication@ComponentScan注解共存,那么@SpringBootApplication注解的扫描的作用将会失效,也就是说不能够扫描启动类所在包以及子包了。因此,我们必须在@ComponentScan注解配置本工程需要扫描的包范围。

@SpringBootApplication 启动时会默认扫描主类当前包及子包,如果需要扫描主类当前包以外的其他包,可用如下注解配置实现:

  1. @SpringBootApplication
  2. @ComponentScan(basePackages = {"com.oxing.mall","com.oxing.blog"})
  3. public class Main {
  4. public static void main(String[] args) {
  5. SpringApplication.run(Main.class, args);
  6. }
  7. }

注意这里basePackages必须包含所有的扫描路径,此时@SpringBootApplication中的@ComponentScan已经失效

使用spring.factories加载第三方的Bean

java spring cloud项目中,我们常常会在子模块中创建公共类库,作为驱动包。如果在另外一个子模块中,需要加载配置文件的时候,往往Spring Boot 自动扫描包的时候,只会扫描自己模块下的类。

抛出一个问题

首先抛出一个问题:

如果想要被Spring容器管理的Bean的路径不在Spring Boot 的包扫描路径下,怎么办呢?也就是如何去加载第三方的Bean 呢?

有两种方式可以解决。这里我们使用Swagger的配置来做实验。

 

  1. 首先一个Swagger的配置类:SwaggerConfig 

SwaggerConfig 代码:

  1. @Configuration
  2. @EnableSwagger2
  3. public class SwaggerConfig implements EnvironmentAware {
  4. private static final Logger log = LoggerFactory.getLogger(SwaggerConfig.class);
  5. @Autowired
  6. private Environment env;
  7. @Value("${swagger.scan.package}")
  8. private String swaggerScanPackage;
  9. public SwaggerConfig() {
  10. }
  11. @Bean
  12. public Docket createRestApi() {
  13. Predicate<String> path = PathSelectors.any();
  14. if (Arrays.asList(this.env.getActiveProfiles()).contains("prod")) {
  15. path = PathSelectors.none();
  16. }
  17. log.info("####初始化createRestApi####swaggerScanPackage:" + this.swaggerScanPackage);
  18. log.info(path.toString());
  19. return (new Docket(DocumentationType.SWAGGER_2)).apiInfo(this.apiInfo()).select().apis(RequestHandlerSelectors.basePackage(this.swaggerScanPackage)).paths(PathSelectors.any()).build();
  20. }
  21. private ApiInfo apiInfo() {
  22. log.info("##################################初始化API信息################################################");
  23. return (new ApiInfoBuilder()).title("APIs").description("…………").termsOfServiceUrl("https://js.dazhi.loan.com").version("1.0").build();
  24. }
  25. @Override
  26. public void setEnvironment(Environment environment) {
  27. }
  28. }
  1. 再看工程结构:

发现我的SwaggerConfig 类和 SpringBoot 的启动类ConfigApplication.java 不在同一级目录下,所以当Spring Boot 自动扫描包的时候,是扫描不到我的SwaggerConfig 的配置的,也就在控制台没有Swagger的打印的信息:

所以这时候我如果想要把SwaggerConfig 加载到Spring容器中的话 要怎么办呢?下面介绍两种方式

方法一、在Spring Boot Application 主类上 使用@Import 注解

  

方法二、创建spring.factories文件

现在我们将其改造一下,采用spring.factories 的方式去加载SwaggerConfig类,在resources目录下新建一个META-INF 的目录,然后再新建一个spring.factories 的文件,里面的内容为:

  1. org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sg.config.SwaggerConfig

然后在把Spring Boot 启动类上的@Import注释掉,启动发现也可以把SwaggerConfig加载到Spring 容器中

到这就完成了加载一个Spring 不能扫描到的一个类,他可以是第三方的,也可以是自己写的,只要是Spring Boot 默认扫描路径不能够扫描到,都可以使用这种方式去加载!!!

Spring Boot 自动扫描组件的更多相关文章

  1. Spring Boot相关组件的添加

    在勾选相关组件后, pom.xml文件上发生了根本的变化 1.这是最简单的项目的pom文件 <?xml version="1.0" encoding="UTF-8& ...

  2. 集成 Spring Boot 常用组件的后台快速开发框架 spring-boot-plus 国

    spring-boot-plus是一套集成spring boot常用开发组件的后台快速开发框架 Purpose 每个人都可以独立.快速.高效地开发项目! Everyone can develop pr ...

  3. spring boot 四大组件之Auto Configuration

    SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...

  4. Spring Boot自动扫描

    进行Spring Boot和Mybatis进行整合的时候,Spring Boot注解扫描的时候无法扫描到Application类的以外的包下面的注解,如下图: App就是Application类,下图 ...

  5. spring boot 四大组件之Actuator

    执行器(Actuator)的定义 执行器是一个制造业术语,指的是用于移动或控制东西的一个机械装置,一个很小的改变就能让执行器产生大量的运动.An actuator is a manufacturing ...

  6. spring boot 四大组件之Starter

    1.概述 依赖管理是任何复杂项目的关键方面.手动完成这些操作并不理想; 你花在它上面的时间越多,你在项目的其他重要方面所花费的时间就越少. 构建Spring Boot启动器是为了解决这个问题.Star ...

  7. Spring boot 开发组件

    一.Jboot 描述:Jboot是一个基于jfinal 和 undertow开发的微服务框架.提供了AOP.RPC.分布式缓存.限流.降级.熔断.统一配置中心.swagger api自动生成.Open ...

  8. 禁用 Spring Boot 中引入安全组件 spring-boot-starter-security 的方法

    1.当我们通过 maven 或 gradle 引入了 Spring boot 的安全组件 spring-boot-starter-security,Spring boot 默认开启安全组件,这样我们就 ...

  9. Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件

    本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...

随机推荐

  1. fabric运行记录

    创建第一个fabric网络 Generate Network Artifacts cd first-network 先关闭服务 ./byfn.sh -m down 然后创建 ./byfn.sh -m ...

  2. Salesforce Consumer Goods Cloud 浅谈篇二之门店产品促销的配置

    本篇参考:https://documentation.b2c.commercecloud.salesforce.com/DOC1/index.jsp?topic=%2Fcom.demandware.d ...

  3. Python 爬取 拉钩

    ... from urllib import request from urllib import parse from urllib.error import URLError import jso ...

  4. 微信小程序(四)开发框架

    wxss: 一套样式语言,用于描述wxml 的组件样式 基于css 的删除和修改 尺寸单位:rpx 样式导入 @import 内联样式 style 选择器 .class .intro 选择所有拥有 c ...

  5. python实现对象测量

    目录: 问题,轮廓找到了,如何去计算对象的弧长与面积(闭合),多边形拟合,几何矩的计算等 (一)对象的弧长与面积 (二)多边形拟合 (三)几何矩的计算 (四)获取图像的外接矩形boundingRect ...

  6. <C#任务导引教程>练习四

    //27,创建一个控制台应用程序,声明两个DateTime类型的变量dt,获取系统的当前日期时间,然后使用Format格式化进行规范using System;class Program{    sta ...

  7. [nowcoder5668H]Sort the Strings Revision

    考虑对于$p_{i}=0$,那么可以快速比较出$s_{0},s_{1},...,s_{i-1}$与$s_{i},s_{i+1},...,s_{n}$之间的大小关系,然后对两边分别找到最小的$p_{i} ...

  8. lambda函数实现链表的小根堆

    struct ListNode { int val; ListNode *next; ListNode() : val(0), next(nullptr) {} explicit ListNode(i ...

  9. 卸载.net 5.0后使用dotnet提示Found .NET Core SDK

    之前安装了预览版本的vs2019后试了下,然后卸载了.但发现控制台执行dotnet相关命令提示Found .NET Core SDK, but did not find dotnet.dll at [ ...

  10. 分布式多任务学习论文阅读(四):去偏lasso实现高效通信

    1.难点-如何实现高效的通信 我们考虑下列的多任务优化问题: \[ \underset{\textbf{W}}{\min} \sum_{t=1}^{T} [\frac{1}{m_t}\sum_{i=1 ...