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 Boot 最核心的 25 个注解,都是干货!
Spring Boot 最核心的 25 个注解
1、@SpringBootApplication
这是 Spring Boot 最最最核心的注解,用在 Spring Boot 主类上,标识这是一个 Spring Boot 应用,用来开启 Spring Boot 的各项能力。
其实这个注解就是 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan 这三个注解的组合,也可以用这三个注解来代替 @SpringBootApplication 注解。
2、@EnableAutoConfiguration
允许 Spring Boot 自动配置注解,开启这个注解之后,Spring Boot 就能根据当前类路径下的包或者类来配置 Spring Bean。
如:当前类路径下有 Mybatis 这个 JAR 包,MybatisAutoConfiguration 注解就能根据相关参数来配置 Mybatis 的各个 Spring Bean。
3、@Configuration
这是 Spring 3.0 添加的一个注解,用来代替 applicationContext.xml 配置文件,所有这个配置文件里面能做到的事情都可以通过这个注解所在类来进行注册。
4、@SpringBootConfiguration
这个注解就是 @Configuration 注解的变体,只是用来修饰是 Spring Boot 配置而已,或者可利于 Spring Boot 后续的扩展。
5、@ComponentScan
这是 Spring 3.1 添加的一个注解,用来代替配置文件中的 component-scan 配置,开启组件扫描,即自动扫描包路径下的 @Component 注解进行注册 bean 实例到 context 中。
前面 5 个注解可以在这篇文章《Spring Boot 最核心的 3 个注解详解》中了解更多细节的。
6、@Conditional
这是 Spring 4.0 添加的新注解,用来标识一个 Spring Bean 或者 Configuration 配置文件,当满足指定的条件才开启配置。
7、@ConditionalOnBean
组合 @Conditional 注解,当容器中有指定的 Bean 才开启配置。
8、@ConditionalOnMissingBean
组合 @Conditional 注解,和 @ConditionalOnBean 注解相反,当容器中没有指定的 Bean 才开启配置。
9、@ConditionalOnClass
组合 @Conditional 注解,当容器中有指定的 Class 才开启配置。
10、@ConditionalOnMissingClass
组合 @Conditional 注解,和 @ConditionalOnMissingClass 注解相反,当容器中没有指定的 Class 才开启配置。
11、@ConditionalOnWebApplication
组合 @Conditional 注解,当前项目类型是 WEB 项目才开启配置。
当前项目有以下 3 种类型。
enum Type {
}
12、@ConditionalOnNotWebApplication
组合 @Conditional 注解,和 @ConditionalOnWebApplication 注解相反,当前项目类型不是 WEB 项目才开启配置。
13、@ConditionalOnProperty
组合 @Conditional 注解,当指定的属性有指定的值时才开启配置。
14、@ConditionalOnExpression
组合 @Conditional 注解,当 SpEL 表达式为 true 时才开启配置。
15、@ConditionalOnJava
组合 @Conditional 注解,当运行的 Java JVM 在指定的版本范围时才开启配置。
16、@ConditionalOnResource
组合 @Conditional 注解,当类路径下有指定的资源才开启配置。
17、@ConditionalOnJndi
组合 @Conditional 注解,当指定的 JNDI 存在时才开启配置。
18、@ConditionalOnCloudPlatform
组合 @Conditional 注解,当指定的云平台激活时才开启配置。
19、@ConditionalOnSingleCandidate
组合 @Conditional 注解,当指定的 class 在容器中只有一个 Bean,或者同时有多个但为首选时才开启配置。
20、@ConfigurationProperties
用来加载额外的配置(如 .properties 文件),可用在 @Configuration 注解类,或者 @Bean 注解方法上面。
21、@EnableConfigurationProperties
一般要配合 @ConfigurationProperties 注解使用,用来开启对 @ConfigurationProperties 注解配置 Bean 的支持。
22、@AutoConfigureAfter
用在自动配置类上面,表示该自动配置类需要在另外指定的自动配置类配置完之后。
如 Mybatis 的自动配置类,需要在数据源自动配置类之后。
23、@AutoConfigureBefore
这个和 @AutoConfigureAfter 注解使用相反,表示该自动配置类需要在另外指定的自动配置类配置之前。
24、@Import
这是 Spring 3.0 添加的新注解,用来导入一个或者多个 @Configuration 注解修饰的类,这在 Spring Boot 里面应用很多。
25、@ImportResource
这是 Spring 3.0 添加的新注解,用来导入一个或者多个 Spring 配置文件,这对 Spring Boot 兼容老项目非常有用,因为有些配置无法通过 Java Config 的形式来配置就只能用这个注解来导入。
欢迎Java工程师朋友们加入Java高并发: 957734884 ,群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!
spring boot增加@ComponentScan后就扫描不到其他包了
参考如下:
扫描多个包
@ComponentScan("com.a,com.b")
public class APP {
public static void main(String[] args) {
SpringApplication.run(APP.class, args);
}
}
springboot项目scanBasePackages和exclude 迁移到配置文件
在实际开发中想把@SpringBootApplication 扫描包 scanBasePackages 和 排除功能exclude 放到配置文件 @Configuration中,方便打jar包(不要@SpringBootApplication)……搜索查询了很久,没有找到方法 手动捂脸…… 最后……如下
@SpringBootApplication(scanBasePackages = { "com.demo.workflow", "com.demo.xiaoxiao.swagger"}, ,exclude = {SecurityAutoConfiguration.class}) 迁移到config配置文件
注意 如下方式迁移是无效的
@ComponentScan(basePackages = {"com.demo.workflow", "com.demo.skull","org.flowable.ui.modeler", "org.flowable.ui.common"}
, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityAutoConfiguration.class)
)
为什么这么迁移? 其实 很简单,我们看下注解源码就知道了,截取一部分
scanBasePackages 对应的刚好是 @ComponentScan
exclude 对应的刚好是 @EnableAutoConfiguration(exclude
所以将启动类的配置更改到配置中心如上
SpringBoot启动分析
SpringApplication.run方法中,实例化一个SpringApplication对象,并调用该对象的run方法。
在SpringApplication构造函数中,主要完成了这样两件事:
在run()中主要完成如下几项工作:
在refreshContext方法中实现Ioc容器的初始化和Ioc的依赖注入。其中,在invokeBeanFactoryPostProcessors()方法中完成了IoC容器初始化过程的三个步骤。
第一步:Resource定位
在SpringBoot中,我们都知道他的包扫描是从主类所在的包开始扫描的,prepareContext()方法中,会先将主类解析成BeanDefinition,然后在refresh()方法的invokeBeanFactoryPostProcessors()方法中解析主类的BeanDefinition获取basePackage的路径。这样就完成了定位的过程。其次SpringBoot的各种starter是通过SPI扩展机制实现的自动装配,SpringBoot的自动装配同样也是在invokeBeanFactoryPostProcessors()方法中实现的。还有一种情况,在SpringBoot中有很多的@EnableXXX注解,细心点进去看的应该就知道其底层是@Import注解,在invokeBeanFactoryPostProcessors()方法中也实现了对该注解指定的配置类的定位加载。
常规的在SpringBoot中有三种实现定位,第一个是主类所在包的,第二个是SPI扩展机制实现的自动装配(比如各种starter),第三种就是@Import注解指定的类。
第二步:BeanDefinition的载入
在第一步中说了三种Resource的定位情况,定位后紧接着就是BeanDefinition的分别载入。所谓的载入就是通过上面的定位得到的basePackage,SpringBoot会将该路径拼接成:classpath :org/springframework/boot/demo/ / .class这样的形式,然后一个叫做PathMatchingResourcePatternResolver的类会将该路径下所有的.class文件都加载进来,然后遍历判断是不是有@Component注解,如果有的话,就是我们要装载的BeanDefinition。大致过程就是这样的了。
TIPS:@Configuration,@Controller,@Service等注解底层都是@Component注解,只不过包装了一层罢了。
第三步:注册BeanDefinition
这个过程通过调用上文提到的BeanDefinitionRegister接口的实现来完成。这个注册过程把载入过程中解析得到的BeanDefinition向IoC容器进行注册。通过上文的分析,我们可以看到,在IoC容器中将BeanDefinition注入到一个ConcurrentHashMap中,IoC容器就是通过这个HashMap来持有这些BeanDefinition数据的。比如DefaultListableBeanFactory 中的beanDefinitionMap属性。
invokeBeanFactoryPostProcessors方法中主要通过ConfigurationClassPostProcessor完成IoC容器初始化的过程。
registerBeanPostProcessors方法中注册了AutowiredAnnotationBeanPostProcessor,registerBeanPostProcessors方法中对bean进行初始化时会调用AutowiredAnnotationBeanPostProcessor的接口实现@Autowired,完成Ioc的注入。
参考:
springboot配置文件注解
springboot使用一个全局配置文件,配置文件的名字是固定的:
application.properties或application.yml
@ConfigurationProperties: 将 全局配置文件 的属性值,映射到SpringBoot 组件 上
@Value: 从 全局配置文件 中读取属性,映射到组件上
@PropertySource: 加载指定的配置文件。可以配合 @Value 和 @ConfigurationProperties 使用。默认只能加载XML文件,若需要加载yml文件需要实现 DefaultPropertySourceFactory 的 createPropertySource() 方法,并在注解中声明。spring boot 中 yml 、yaml 对应的加载类为 YamlPropertySourceLoader .
@ImportResource: 加载自定义的Spring XML 配置文件
SpringBoot不推荐使用这种方式,推荐使用全注解(JavaConfig)的方式。
SpringBoot会扫描当前包和所有子包的注解配置到容器中。