SpringBoot 启动注解 @SpringBootApplication 相关知识整理
一、启动类使用
我们可以通过SpringBoot官方网站 https://start.spring.io/创建一个基础的SpringBoot项目
如下示例为 tysite-spark 项目的启动类部分代码
package org.items.tysite;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication (1)
public class StartApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(StartApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}
本章节主要介绍 @SpringBootApplication 注解的都做了那些事情,前面的文章已经介绍过注解的基础知识,本文将忽略基础知识部分的讲解
二、@SpringBootApplication 详解
@SpringBootApplication注解,主要包含@SpringBootConfiguration 、@EnableAutoConfiguration 和@ComponentScan 三个注解
注解源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration (1)
@EnableAutoConfiguration (2)
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) (3)
public @interface SpringBootApplication {
……
}
(1)@SpringBootConfiguration: 该注解继承自
@Configuration
,两者功能一致,标注当前类是一个配置类。
注解源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
……
}
其下可以通过
@Bean
标注将方法返回的类对象依赖注入到
Spring容器
中。
需要注意的是,虽然
@Configuration
继承自
@Component
,但
@Configuration
采用
CGLIB
的动态代理功能,使
@Bean
注释的方法都会被动态代理,调用时通过
BeanFactory
返回相同的对象。即
@Configuration
注解是单例模式,
@Component
注解是多例模式。
(2)@EnableAutoConfiguration :spring的自动装配注解,该注解会根据项目添加的
jar包
依赖项,完成对项目依赖的自动装配。
注解源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
@EnableAutoConfiguration注解默认会扫描
spring-boot-autoconfigure:xxx.RELEASE.jar
包下
META-INF/spring.factories
文件中,所有
org.springframework.boot.autoconfigure.EnableAutoConfiguration
值中对应的
*Configuration
类,并根据类上的条件注解判定结果,将符合条件的配置类加载到spring容器中。·
代码片段如下:
……
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
……
注意:如果项目要剔除某个依赖的自动装配,可以通过本注解的
exclude
属性,设置要剔除的配置类即可。(使用上面auto Configure 中的类命名), 示例如下:
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) // -> 禁止数据源自动装配
启动spring时,若开启
DEBUG
模式,可以在启动日志的
CONDITIONS EVALUATION REPORT
中查看到项目模块的装配情况
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPRpFMsJzY1I1MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLyQTM0IzNwYTMxIjNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
注意:
1、
@EnableAutoConfiguration
通过资源导入注解(
@Import(AutoConfigurationImportSelector.class)
),将``类引入到启动类中
2、配置类加载规则,通过扫描SpringBoot自动配置包内
spring-boot-autoconfigure-*.RELEASE.jar/META-INF/spring.factories
文件中
org.springframework.boot.autoconfigure.EnableAutoConfiguration
属性所配置的所有
*AutoConfiguration
类,进行装载。在扫描到
*AutoConfiguration
类时,所有类中的
@ConditionalOn*
注解生效,判断其所需的类是否存在(或生效),以决定是否装载对应配置。
参考资料:
https://www.cnblogs.com/leihuazhe/p/7743479.html
https://blog.csdn.net/mapleleafforest/article/details/87273213
(3)@ComponentScan : 配置组件自动扫描的指令,以便提供与XML配置
<context:component-scan base-package="org.example"/>
相同的功能,继承于
@ComponentScans
注解。
注解源码如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
boolean useDefaultFilters() default true;
Filter[] includeFilters() default {};
Filter[] excludeFilters() default {};
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
从注解源码中,可以看到
@ComponentScan
注解的一些重要属性
-
和value()
属性 互为别名,用于指定@ComponentScan注解扫描的包路径,若不设置则默认从@ComponentScan注释的类开始向下扫描。basePackages
-
属性 标记是否启用默认过滤规则,该规则用于扫描@Component,@Repository,@Service,@Controller 注解注释的类。boolean useDefaultFilters() default true;
-
属性指定特定扫描规则,通常此时关闭默认扫描规则。includeFilters
-
属性用于排除特定扫描规则。excludeFilters
-
内部注解可以配合@Filter
或excludeFilters
实现 排除 或 增加 某个过滤规则includeFilters
1、
@ComponentScan
常用应用示例:
@ComponentScan(“org.items.tysite”)
扫描 [org.items.tysite] 包下的所有默认注解,如@Controller、@Service、@Component等
@ComponentScan(basePackageClasses = ThymeleofController.class, useDefaultFilters = false)
扫描 指定的 ThymeleofController 类
@ComponentScan(value = “org.items.tysite”, includeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) }, useDefaultFilters = false)
只扫描 [org.items.tysite] 包下,由 @Component注解注释的类
@ComponentScan(value = “org.items.tysite”, excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
扫描 [org.items.tysite] 包下,除@Component注解之外的所有默认规则注解
@ComponentScan(value = “org.items.tysite”, includeFilters = { @Filter(type = FilterType.CUSTOM, value = CustomTypeFilter.class) }, useDefaultFilters = false)
扫描 [org.items.tysite] 包下,基于CustomTypeFilter 自定义规则加载Bean
2、自定义策略使用案例
以上面示例5的配置作为配置样例,通过实现
TypeFilter
接口,创建自定义的策略,并通过
@Configuration
配置
@ComponentScan
@Configuration
@ComponentScan(value = "org.items.tysite", includeFilters = { @Filter(type = FilterType.CUSTOM, value = CustomTypeFilter.class) }, useDefaultFilters = false)
public class CustomComponentScanConfiguration { }
public class CustomTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
ClassMetadata classMetadata = metadataReader.getClassMetadata();
String className = classMetadata.getClassName();
if (CommonConsts.class.getName().equals(className)) {
System.out.println("成功加载类 ["+CommonConsts.class.getName()+"]");
return true;
} else {
return false;
}
}
}
注意: 项目使用
@SpringBootApplication
的注解扫描时,以上示例无法生效。因为
@SpringBootApplication
注解中排除了
FilterType.CUSTOM
自定义的扫描规则 (
详见注解源码
)。如果我们的项目中需要使某个类或注解注释不被注入时,可以通过继承
TypeExcludeFilter
类并重写
match
方法实现。
方法的
match
参数,可以获取到扫描对象 类信息、注解信息、以及资源信息,可以根据以上信息判断要注入的类
MetadataReader
//获取扫描到的类注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取扫描到的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取扫描到的类资源信息
Resource resource = metadataReader.getResource();
参考资料:
https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/core.html#beans-scanning-autodetection
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/TypeExcludeFilter.html#match-org.springframework.core.type.classreading.MetadataReader-org.springframework.core.type.classreading.MetadataReaderFactory-
https://blog.csdn.net/luojinbai/article/details/85877956