1、@SpringBootApplication
写在应用主启动类上
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
点进去这个注解可以看到这个注解上面有以下主要注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
1.1、@EnableAutoConfiguration
启用 SpringBoot 的自动配置机制,在springboot中有很多Enable开头的就是启用某个功能。在@EnableAutoConfiguration注解类的上面又有以下注解
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
1.1.1、@AutoConfigurationPackage
这个注解的作用就是将 添加该注解的类所在的package 作为 自动配置package进行管理。我们知道组合注解就相当于各个单注解都添加到一个作用目标的作用(有关注解可以看这个:Java注解:元注解、普通注解、组合注解_jcpp9527的博客-优快云博客)因为相当于SpringbootApplication这个注解间接组合了AutoConfigurationPackage那么搭配这个注解的作用也就是说当SpringBoot应用启动时默认会将启动类所在的package作为自动配置的package。可以使用下面的方式检测当前的自动配置的包。
@Autowired
public BeanFactory beanFactory;
List<String> packages = AutoConfigurationPackages.get(beanFactory);
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
这个注解又包含这些注解,也就说AutoConfigurationPackage这个注解主要是通过@Import导入了一个类,这个@Import注解大家应该都熟悉,(它是spring底层注解,作用就是将注解内参数表明的类加入IOC容器。不要以为像@Controller、@Service、@Component这些就很好的可以解决,其实对于一些jar包中没有使用@Component注解的类,我们总不能打开jar包给人家加上吧,这时候这个@Import就起到作用了),回到源码中,导入的这个类Register.class也就是AutoConfigurationPackages.Registrar.class,这个类中会完成我们上面所说的AutoConfigurationPackage注解的功能,将主配置类所在的包下面所有的组件都扫描到Spring容器中。
1.1.2、@Import({AutoConfigurationImportSelector.class})
添加AutoConfigurationImportSelector.class到IOC容器,有关这个类请看后面。
1.2、@SpringBootConfiguration
这个注解里面就是一个@Configuration,也就是说它的功能和@Configuration是一样的也就是标注这个注解的类就是一个配置类,只不过这个派生注解给人见名知意的感觉,被标注者它就是Springboot的配置类。
1.3、@ComponentScan
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.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 {};
}
}
下面给出解释:
basePackages与value: 用于指定包的路径,进行扫描
basePackageClasses: 用于指定某个类的包的路径进行扫描
nameGenerator: bean的名称的生成器
useDefaultFilters: 是否开启对@Component,@Repository,@Service,@Controller的类进行检测
includeFilters: 包含的过滤条件
excludeFilters: 排除的过滤条件
有关过滤(@Filter注解),它又是本注解的内部注解,它有四个字段
FilterType type() default FilterType.ANNOTATION; //指定过滤类型,后边会说这个过滤类型有啥
@AliasFor("classes")
Class<?>[] value() default {}; //如果过滤类型为自定义时,给出的过滤器类,给定类型时、以及注解类型时用来设置需要过滤的类以及根据什么样的注解过滤
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {}; //AspectJ类型时过滤表达式,正则表达式规则时的正则表达式式
FilterType是个枚举主要有以下过滤类型
public enum FilterType {
ANNOTATION, //根据注解,即标注指定注解的通过过滤
ASSIGNABLE_TYPE, //根据自定过滤哪些类
ASPECTJ, //根据ASPECTJ表达式过滤
REGEX, //正则表达式过滤
CUSTOM //自定义过滤
}
更过有关自定义过滤规则请看 https://blog.youkuaiyun.com/nrsc272420199/article/details/88385574
@Component默认情况下,任何参数都不设置的情况下,此时,会将@ComponentScan修饰的类所在的包作为扫描包。
另外在springboot的启动类上,也就是被@SpringbootApplication所标注的类上,如果你再只加入一个@ComponentScan(什么参数都不加的情况),是会报冗余错误的,因为@SpringbootApplication已经包含@ComponentScan,只有参数与默认的也就是主启动类所在不一样的包下才可以。但是这样就会覆盖@SpringbootApplication组合的@ComponentScan,所以你需要再将@SpringbootApplication的里面的@ComponentScan所扫描包再使用@ComponentScan重新写一次(惊讶的发现此时搭配另外的@ComponentScan就不会再出错了)
更多请看Spring Boot踩坑记录(@SpringBootApplication与@ComponentScan存在冲突) - 司徒无涯的个人空间 - OSCHINA - 中文开源技术交流社区
那么让我们最后回到SpringbootApplication中的@Component,可以看出,其指定了两条过滤规则,并指定了过滤规则类。
2、@EnableAutoConfiguration-@Import({AutoConfigurationImportSelector.class})
这个本应该在在1.1.2中讲,但是单独拿开,足以说明其很重要。
也就是说在@EnableAutoConfiguration里面组合了一个@Import({AutoConfigurationImportSelector.class}),作用显而易见,将AutoConfigurationImportSelector.class这个类加入到springIOC容器,那么这个类是什么作用呢?接着看,在SpringBoot中存在大量的XXXAutoConfiguration,这些AutoConfiguration类就是帮我们进行自动配置的,他们会将指定场景使用到的所有组件都注册到容器中并且配置好。,这些类的全类名可以在
也就是在类路径下META-INF/spring.factories文件中,在这个文件有一部分
这个键对应的值,也就是等号后边的东西,会在AutoConfigurationImportSelector这个类的getCandidateConfigurations这个方法中,具体的会调用到SpringFactoriesLoader这个类的loadSpringFactories里面将字符串读入,分割等一系列操作,最后返回一个List集合,springboot会将集合中的全类名都加载到IOC容器中。
但是呢请注意,META-INF/spring.factories可不止一个,在其他的包下也可以可以有
这里面标线的方法和操作,就是将所有的spring.factories文件读入,并将其中的key和value封装成LinkedMultiValueMap,这个结构的一个key可以对应多个value,可以认为是这样的结构:Map<String, List<String>>,方法返回后会在getOrDefault(factoryTypeName, Collections.emptyList());中返回key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的list集合,这个集合中就是哪些自动配置的全限定类名。这其实是加载bean的一种方式,和import一样的理解就行。