使用@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的配置来做实验。

 

  1. 首先一个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) { }
}
  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 的文件,里面的内容为:

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. LeetCode -90. 子集 II C++ (回溯法)

    class Solution { public: vector<vector<int>> subsetsWithDup(vector<int>& nums) ...

  2. 我罗斯方块第二次作业(Block类)

    负责任务 完善Block类的相关函数及变量: 对Block类的函数功能进行调试: github项目地址. 开发日记 2020.5.11 今天和朋友们讨论了如何分工的工作,我负责的部分是Block类的完 ...

  3. go微服务框架Kratos笔记(一)入门教程

    kratos简介 Kratos 一套轻量级 Go 微服务框架,包含大量微服务相关功能及工具 本文基于kratos v2.0.3,windows平台,其他系统平台均可借鉴参考 环境搭建 Golang开发 ...

  4. requests_cookie登陆古诗文网。session的使用

    通过登录失败,快速找到登录接口 获取hidden隐藏域中的id的value值 # 通过登陆 然后进入到主页面 # 通过找登陆接口我们发现 登陆的时候需要的参数很多 # _VIEWSTATE: /m1O ...

  5. R数据分析:潜类别轨迹模型LCTM的做法,实例解析

    最近看了好多潜类别轨迹latent class trajectory models的文章,发现这个方法和我之前常用的横断面数据的潜类别和潜剖面分析完全不是一个东西,做纵向轨迹的正宗流派还是这个方法,当 ...

  6. [hdu7042]二叉树

    考虑最后这棵二叉树的结构,不难发现被移动的点在原树或新树中构成的都是若干棵完整的子树 (若$x$被移动,则$x$在原树或新树的子树中所有点都会被移动) 先在原树中考虑此问题,对于每一棵由被移动的点所构 ...

  7. [hdu7013]String Mod

    枚举$a$​​​和$b$​​​​​出现的次数,问题即求$$A_{i,j}=\sum_{p=0}^{L}\sum_{q=0}^{L-p}[n\mid (p-i)][n\mid (q-j)]{L\choo ...

  8. [bzoj1927]星际竞速

    考虑没有爆发,那么相当于是带权最小不可交路径覆盖,由于只能从编号小的到编号大的,因此一定是DAG,而DAG的最小路径覆盖可以拆点并跑最大流,那么带权的只需要跑费用流即可(S向i连(1,0)的边,i'向 ...

  9. buu

    buuCTFwp(1~32) 1.签到题 题里就有flag flag{buu_ctf} 2.二维码 1.题目是一个二维码,用010发现提示四位数字,想到应该是暗藏压缩包 2.虚拟机foremost分离 ...

  10. 解决ip和域名都能够ping通但是启动nginx无法访问网页的问题

    解决思路 最近双11逛西部数码的官网看看有没有什么服务器优惠的时候,发现了可以申请一个一块钱用一整年的SSL证书,立马心动下单了,想想俺也可以用https装装X了哈哈 不过在部署完证书,并调整ngin ...