转载

springboot系列文章之SpringBootApplication注解

Springboot的启动类可以是非常简单,其中最关键的两部分是Annotation定义( @SpringBootApplication )和类定义(SpringApplication.run),这篇文章主要分析其 @SpringBootApplication 注解,后续文章再接着分析其类定义。

@SpringBootApplication
public class Application {


    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
复制代码

其中参考了《SpringBoot揭秘》里面的分析,也是学习总结了。

@SpringBootApplication注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    .....
}
复制代码

看似有这么多注解,实际上 @SpringBootApplication 是一个"三体"结构,重要的只有三个Annotation:

@Configuration
@EnableAutoConfiguration
@ComponentScan

为什么 @SpringBootApplication注解 里没有包含 @Configuration ,实际上是在 @SpringBootConfiguration 里面

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
复制代码

@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类, 并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名。

实际上如果我们使用如下的Springboot启动类,整个SpringBoot应用依然可以与之前的启动类功能对等。

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application {


    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
复制代码

下面分别说说这三个关键注解

@Configuration

这里的 @Configuration 就是以JavaConfig形式的Spring IoC容器的配置类使用的那个 @Configuration ,所以这里的启动类标注了 @Configuration 之后,本身其实也是一个IoC容器的配置类。

以前的XML配置是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
       default-lazy-init="true">
    <!--bean定义-->
</beans>
复制代码

现在的JavaConfig配置是这样的,效果等同,标注了该注解说明就是一个配置类

@Configuration
public class Application{
    //bean定义
}
复制代码

更多关于 @Configuration@Bean 的讲解,参考文章: 使用 Java 配置进行 Spring bean 管理

@ComponentScan

@ComponentScan的功能其实就是自动扫描并加载符合条件的组件或bean定义,最终将这些bean定义加载到容器中。 我们可以通过basePackages等属性指定@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现从声明@ComponentScan所在类的package进行扫描,默认情况下是不指定的,所以SpringBoot的启动类最好放在root package下。

@EnableAutoConfiguration

各位是否还记得Spring框架提供的各种名字为@Enable开头的Annotation定义?比如 @EnableScheduling , @EnableCaching , @EnableMBeanExport 等, @EnableAutoConfiguration 的理念和"做事方式"其实一脉相承, 借助 @Import 的支持,收集和注册特定场景相关的bean定义:

@EnableScheduling
@EnableMBeanExport

而@EnableAutoConfiguration也是借助@Import的帮助, 将所有符合自动配置条件的bean定义加载到Ioc容器,仅此而已

@EnableAutoConfiguration也是一个复合Annotation,其定义如下:

@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 {};
}
复制代码

其中,最关键的要属 @Import(AutoConfigurationImportSelector.class) ,借助 AutoConfigurationImportSelector 这个类, @EnableAutoConfiguration 可以帮助Springboot应用将所有符合条件的@configuration都加载到当前的SpringBoot创建并使用的Ioc容器

springboot系列文章之SpringBootApplication注解

AutoConfigurationImportSelector

在SpringBoot1.5以前,使用的是 EnableAutoConfigurationImportSelector ,它继承自 AutoConfigurationImportSelector ,1.5以后, EnableAutoConfigurationImportSelector 已经不再被建议使用,而是推荐使用 AutoConfigurationImportSelector

何时被执行

现在我们已经知道了在@EnableAutoConfiguration中引入了AutoConfigurationImportSelector类,那么它是如何被执行的呢?

Springboot启动时会使用ConfigurationClassParser来解析被@Configuration修饰的配置类,然后再处理这个类内部被其他注解修饰的情况,比如@Import注解,@ComponentScan注解,@Bean注解等。

如果发现注解中存在@Import(ImportSelector)的情况下,就会创建一个相应的importSelector对象,并调用其selectImports方法,而AutoConfigurationImportSelector就是一个ImportSelector的实现类。更多关于ConfigurationClassParser的分析,参阅文章:Spring类注册笔记

springboot系列文章之SpringBootApplication注解

所以ConfigurationClassParser会实例化一个AutoConfigurationImportSelector 并调用它的 selectImports() 方法

springboot系列文章之SpringBootApplication注解

在selectImports方法中有使用getCandidateConfigurations()这个方法,这个方法走进去,就可以看到自动配置的幕后英雄:SpringFactoriesLoader

springboot系列文章之SpringBootApplication注解

自动配置的幕后英雄:SpringFactoriesLoader

SpringFactoriesLoader的主要功能就是从指定的配置文件 META/spring.factories 加载配置,spring.factories是一个典型的java properties文件,配置格式为Key-Value形式,只不过Key和Value都是Java类型的完整类名。

进入loadFactoryNames()方法,就发现loadFactoryNames()读取了ClassPath下面的 META-INF/spring.factories 文件。

springboot系列文章之SpringBootApplication注解

在@EnableAutoConfiguration的场景中,它更多是提供一种配置查找的功能支持,即根据@EnableAutoConfiguration的完整类名org.springframework.boot.autoconfigure.EnableAutoConfiguration作为查找的key,获取对应的一组@Configuration类

springboot系列文章之SpringBootApplication注解

SpringBootApplication注解中4个方法

@SpringBootApplication不仅包括上面的三个重要注解,还包含有4个方法:

springboot系列文章之SpringBootApplication注解
Class<?>[] exclude() default {};
String[] excludeName() default {};
String[] scanBasePackages() default {};
Class<?>[] scanBasePackageClasses() default {};

小结

这里总结下@SpringBootApplication中的三个重要注解的特征:

  • @Configuration

定义Spring Ioc容器的配置类

  • @EnableAutoConfiguration :

从classpath中搜寻所有META/spring.factories配置文件,并将其中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项,也就是一个自动配置类列表加载到Ioc容器中。 而对于所有标注@Configuration的配置类,统一使用 ConfigurationClassParser 解析的。

  • @ComponentScan

自动扫描并加载符合条件的组件或者bean定义

原文  https://juejin.im/post/5b778945f265da436b524043
正文到此结束
Loading...