我们可以通过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注解,主要包含@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中查看到项目模块的装配情况 注意: 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() 和 basePackages 属性 互为别名,用于指定@ComponentScan注解扫描的包路径,若不设置则默认从@ComponentScan注释的类开始向下扫描。boolean useDefaultFilters() default true; 属性 标记是否启用默认过滤规则,该规则用于扫描@Component,@Repository,@Service,@Controller 注解注释的类。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 自定义规则加载Bean2、自定义策略使用案例 以上面示例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