Spring Boot 自动扫描组件
使用@ComponentScan自动扫描组件
案例准备
1.创建一个配置类,在配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的配置类,相当于之前的 <context:component-scan>。
package io.mieux.config;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
public class BeanConfig {
}
2.使用 ApplicationContext 的 getBeanDefinitionNames() 方法获取已经注册到容器中的 bean 的名称。
import io.mieux.config.BeanConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App02 {
public static void main(String[] args) {
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(BeanConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
System.out.println("beanName: " + beanName);
}
}
}
运行效果:
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: beanConfig
除了 spring 本身注册的一些 bean 之外,可以看到最后一行,已经将BeanConfig这个类注册进容器中了。
使用@ComponentScan 的 valule属性配置
3.指定要扫描的包(使用@ComponentScan 的 valule 属性来配置)
创建一个controller 包,并在该包下新建一个 AppController 类。
package io.mieux.controller;
import org.springframework.stereotype.Controller;
@Controller
public class AppController {
}
在类上加了@Controller注解,说明该类是一个 Component。在 BeanConfig 类中修改:
package io.mieux.config;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(value = "io.mieux.controller")
public class BeanConfig {
}
在 @ComponentScan 注解中指定了要扫描的包。
运行效果:
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: beanConfig
beanName: appController
AppController 已经被注册进容器了。
excludeFilters 和 includeFilters 的使用
使用 excludeFilters 来按照规则排除某些包的扫描。
package io.mieux.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@ComponentScan(value = "io.mieux",
excludeFilters = {@Filter(type = FilterType.ANNOTATION,
value = {Controller.class})})
public class BeanConfig {
}
excludeFilters 的参数是一个 Filter[] 数组,然后指定 FilterType 的类型为 ANNOTATION,也就是通过注解来过滤,最后的 value 则是Controller 注解类。配置之后,在 spring 扫描的时候,就会跳过 io.mieux 包下,所有被 @Controller 注解标注的类。
使用 includeFilters 来按照规则只包含某些包的扫描。
在创建一个 service 的包,并创建一个 AppService 类,再加上一个 @Service 注解。
package io.mieux.service;
import org.springframework.stereotype.Service;
@Service
public class AppService {
}
修改 BeanCofig 类:
package io.mieux.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@ComponentScan(value = "io.mieux", includeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})})
public class BeanConfig {
}
运行效果:
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: beanConfig
beanName: appController
beanName: appService
配置里面,应该是只包含 @Controller 注解的类才会被注册到容器中,为什么 @Service 注解的类也被注册了呢?
这里涉及到 @ComponentScan 的一个useDefaultFilters 属性的用法,该属性默认值为 true,也就是说 spring 默认会自动发现被 @Component、@Repository、@Service 和 @Controller 标注的类,并注册进容器中。要达到只包含某些包的扫描效果,就必须将这个默认行为给禁用掉(在 @ComponentScan 中将 useDefaultFilters 设为 false 即可)。
package io.mieux.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@ComponentScan(value = "io.mieux",
includeFilters = {@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})},
useDefaultFilters = false)
public class BeanConfig {
}
运行效果:
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: beanConfig
beanName: appController
添加多种扫描规则
1、如果使用的 jdk8,则可以直接添加多个 @ComponentScan 来添加多个扫描规则,但是在配置类中要加上 @Configuration 注解,否则无效。
package io.mieux.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan(value = "io.mieux.controller")
@ComponentScan(value = "io.mieux.service")
@Configuration
public class BeanConfig {
}
2、也可以使用 @ComponentScans 来添加多个 @ComponentScan,从而实现添加多个扫描规则。同样,也需要加上 @Configuration 注解,否则无效。
package io.mieux.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
@ComponentScans(value =
{@ComponentScan(value = "io.mieux.controller"),
@ComponentScan(value = "io.mieux.service")})
@Configuration
public class BeanConfig {
}
添加自定义过滤规则
在前面使用过 @Filter 注解,里面的 type 属性是一个 FilterType 的枚举类型:
public enum FilterType {
ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM
}
使用 CUSTOM 类型,就可以实现自定义过滤规则。
1、 首先创建一个实现 TypeFilter 接口的 CustomTypeFilter 类,并实现其 match 方法。
package io.mieux.config;
import org.springframework.core.io.Resource;
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;
public class CustomTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader,
MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前扫描到的类的注解元数据
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前扫描到的类的元数据
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前扫描到的类的资源信息
Resource resource = metadataReader.getResource();
if (classMetadata.getClassName().contains("Co")) {
return true;
}
return false;
}
}
这里简单对扫描到的类名进行判断,如果类名包含”Co“的就符合条件,也就会注入到容器中。
2、对 BeanConfig 进行修改,指定过滤类型为 Custom 类型,并指定 value 为 CustomTypeFilter.class。
package io.mieux.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
@ComponentScan(value = "io.mieux",
includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, value = {CustomTypeFilter.class})},
useDefaultFilters = false)
public class BeanConfig {
}
运行效果:
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalRequiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: beanConfig
beanName: appController
Springboot配置扫描其它模块路径的方法
@SpringBootApplication=@Configuration+@EnableAutoConfiguration+@ComponentScan,其中扫描包的范围为启动类所在包和子包,不包括第三方的jar包。如果我们需要扫描通过maven依赖添加的jar,我们就要单独使用@ComponentScan注解扫描第三方包。
但是,如果@SpringBootApplication和@ComponentScan注解共存,那么@SpringBootApplication注解的扫描的作用将会失效,也就是说不能够扫描启动类所在包以及子包了。因此,我们必须在@ComponentScan注解配置本工程需要扫描的包范围。
@SpringBootApplication 启动时会默认扫描主类当前包及子包,如果需要扫描主类当前包以外的其他包,可用如下注解配置实现:
@SpringBootApplication
@ComponentScan(basePackages = {"com.oxing.mall","com.oxing.blog"})
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
注意这里basePackages必须包含所有的扫描路径,此时@SpringBootApplication中的@ComponentScan已经失效
使用spring.factories加载第三方的Bean
在java spring cloud项目中,我们常常会在子模块中创建公共类库,作为驱动包。如果在另外一个子模块中,需要加载配置文件的时候,往往Spring Boot 自动扫描包的时候,只会扫描自己模块下的类。
抛出一个问题
首先抛出一个问题:
如果想要被Spring容器管理的Bean的路径不在Spring Boot 的包扫描路径下,怎么办呢?也就是如何去加载第三方的Bean 呢?
有两种方式可以解决。这里我们使用Swagger的配置来做实验。
- 首先一个Swagger的配置类:SwaggerConfig
SwaggerConfig 代码:
@Configuration
@EnableSwagger2
public class SwaggerConfig implements EnvironmentAware {
private static final Logger log = LoggerFactory.getLogger(SwaggerConfig.class);
@Autowired
private Environment env;
@Value("${swagger.scan.package}")
private String swaggerScanPackage;
public SwaggerConfig() {
}
@Bean
public Docket createRestApi() {
Predicate<String> path = PathSelectors.any();
if (Arrays.asList(this.env.getActiveProfiles()).contains("prod")) {
path = PathSelectors.none();
}
log.info("####初始化createRestApi####swaggerScanPackage:" + this.swaggerScanPackage);
log.info(path.toString());
return (new Docket(DocumentationType.SWAGGER_2)).apiInfo(this.apiInfo()).select().apis(RequestHandlerSelectors.basePackage(this.swaggerScanPackage)).paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo() {
log.info("##################################初始化API信息################################################");
return (new ApiInfoBuilder()).title("APIs").description("…………").termsOfServiceUrl("https://js.dazhi.loan.com").version("1.0").build();
}
@Override
public void setEnvironment(Environment environment) {
}
}
- 再看工程结构:

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

所以这时候我如果想要把SwaggerConfig 加载到Spring容器中的话 要怎么办呢?下面介绍两种方式
方法一、在Spring Boot Application 主类上 使用@Import 注解

方法二、创建spring.factories文件
现在我们将其改造一下,采用spring.factories 的方式去加载SwaggerConfig类,在resources目录下新建一个META-INF 的目录,然后再新建一个spring.factories 的文件,里面的内容为:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sg.config.SwaggerConfig
然后在把Spring Boot 启动类上的@Import注释掉,启动发现也可以把SwaggerConfig加载到Spring 容器中

到这就完成了加载一个Spring 不能扫描到的一个类,他可以是第三方的,也可以是自己写的,只要是Spring Boot 默认扫描路径不能够扫描到,都可以使用这种方式去加载!!!
Spring Boot 自动扫描组件的更多相关文章
- Spring Boot相关组件的添加
在勾选相关组件后, pom.xml文件上发生了根本的变化 1.这是最简单的项目的pom文件 <?xml version="1.0" encoding="UTF-8& ...
- 集成 Spring Boot 常用组件的后台快速开发框架 spring-boot-plus 国
spring-boot-plus是一套集成spring boot常用开发组件的后台快速开发框架 Purpose 每个人都可以独立.快速.高效地开发项目! Everyone can develop pr ...
- spring boot 四大组件之Auto Configuration
SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @Confi ...
- Spring Boot自动扫描
进行Spring Boot和Mybatis进行整合的时候,Spring Boot注解扫描的时候无法扫描到Application类的以外的包下面的注解,如下图: App就是Application类,下图 ...
- spring boot 四大组件之Actuator
执行器(Actuator)的定义 执行器是一个制造业术语,指的是用于移动或控制东西的一个机械装置,一个很小的改变就能让执行器产生大量的运动.An actuator is a manufacturing ...
- spring boot 四大组件之Starter
1.概述 依赖管理是任何复杂项目的关键方面.手动完成这些操作并不理想; 你花在它上面的时间越多,你在项目的其他重要方面所花费的时间就越少. 构建Spring Boot启动器是为了解决这个问题.Star ...
- Spring boot 开发组件
一.Jboot 描述:Jboot是一个基于jfinal 和 undertow开发的微服务框架.提供了AOP.RPC.分布式缓存.限流.降级.熔断.统一配置中心.swagger api自动生成.Open ...
- 禁用 Spring Boot 中引入安全组件 spring-boot-starter-security 的方法
1.当我们通过 maven 或 gradle 引入了 Spring boot 的安全组件 spring-boot-starter-security,Spring boot 默认开启安全组件,这样我们就 ...
- Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件
本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...
随机推荐
- ABP开发框架中分页查询排序的实现处理
在ABP开发框架中应用服务层ApplicationService类中,都会提供常见的一些如GetAll.Get.Create.Update.Delete等的标准处理接口,而由于在Application ...
- Spring 之 BeanFactory 源码 - 接口分析
一.BeanFactory的基本类体系结构(接口为主):
- C# for Beginner Part 21 to 30
Part 21 Inheritance in c# Why Inheritance Pillars(支架) of Object Oriented Programming 1,Inheritance(继 ...
- Veeam Backup & Replication 10.0.0.4461安装部署(包含补丁)
Veeam Backup & Replication 是一款数据保护软件,为VMware 和Hyper-V 虚拟机.物理与云环境提供了备份.复制与恢复选项.如有需要请去官方购买正版授权:htt ...
- pyhon-高并发测试
使用gevent.对注册.接口进行200的并发量进行测试. #!/usr/bin/env python # -*- coding:utf-8 -*- #设置路径:Defualt Settings--- ...
- Jetpack架构组件学习(2)——ViewModel和Livedata使用
要看本系列其他文章,可访问此链接Jetpack架构学习 | Stars-One的杂货小窝 原文地址:Jetpack架构组件学习(2)--ViewModel和Livedata使用 | Stars-One ...
- 【CSS】水平居中和垂直居中
水平居中和垂直居中 2019-11-12 15:35:37 by冲冲 1.水平居中 (1)父级元素是行内元素,子级元素是行内元素,子级元素水平居中 ① 设置父级元素为块级元素 display:bl ...
- page_fault_in_nonpaged_area异常解决方案(已解决)
电脑在运行虚拟机的时候异常重启,多次打开结果一样,问了客服告诉我导致蓝屏的原因很多,可能是驱动不兼容,系统,或其他.{没点有用的} 百度到这个方案: 打开->此电脑->右键属性->高 ...
- mybatis判断集合长度
使用mybatis框架在写sql的时候碰到一个异常: 1064 - You have an error in your SQL syntax; check the manual that corres ...
- Codeforces 718E - Matvey's Birthday(思维题)
Codeforces 题面传送门 & 洛谷题面传送门 首先注意到这个图的特殊性:我们对于所有 \(s_i=s_j\) 的 \((i,j)\) 之间都连了条边,而字符集大小顶多只有 \(8\ ...