SpringBoot实现原理

最普通的SpringBoot应用启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

springboot应用,只需要配置@SpringBootAplication注解,便可以自动启动,为什么呢?

我们进入这个注解可以发现@SpringBootAplication是一个组合annotation,其中最重要的annotation是@SpringBootConfiguration,@EnableAutoConfiguration和@ComponentScan。 

@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 {}

@SpringBootConfiguration本质上是一个@Configuration。启动类标注了@SpringBootConfiguration之后,本身其实也是一个IOC容器的配置类。

@ComponentScan注解完成的是自动扫描的功能,相当于Spring XML配置文件中的:<context:component-scan>,可以使用encludeFilters,includeFilters等属性指定或排除要扫描的包,以及扫描的条件。最终将这些bean定义加载到容器中。

@EnableAutoConfiguration是让Spring Boot的配置能够如此简化的关键性注解,Spring-Boot 根据应用所声明的jar包依赖来对Spring框架进行自动配置。比如根据spring-boot-starter-web ,来判断你的项目是否需要添加了webmvctomcat,就会自动的帮你配置web项目中所需要的默认配置。


@EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//导入了类EnableAutoConfigurationImportSelector
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

类EnableAutoConfigurationImportSelector是一个ImportSelector接口的实现类,而ImportSelector接口中的selectImports方法所返回的类将被Spring容器管理起来。

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
   
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            try {
                //加载META-INF/spring-autoconfigure-metadata.properties文件
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
                //获取注解的属性及其值
                AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
                //在classpath下所有的META-INF/spring.factories文件中查找org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,并将其封装到一个List中返回
                List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
                //对上一步返回的List中的元素去重、排序
                configurations = this.removeDuplicates(configurations);
                configurations = this.sort(configurations, autoConfigurationMetadata);
                //依据第2步中获取的属性值排除一些特定的类
                Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
                this.checkExcludedClasses(configurations, exclusions);
                configurations.removeAll(exclusions);
                //对上一步中所得到的List进行过滤,过滤的依据是条件匹配。这里用到的过滤器是org.springframework.boot.autoconfigure.condition.OnClassCondition最终返回的是一个ConditionOutcome[]数组。
                configurations = this.filter(configurations, autoConfigurationMetadata);
                this.fireAutoConfigurationImportEvents(configurations, exclusions);
                return (String[])configurations.toArray(new String[configurations.size()]);
            } catch (IOException var6) {
                throw new IllegalStateException(var6);
            }
        }
    }
}

那么这个注解@EnableAutoConfiguration式怎么生效的呢?

在主启动类的main函数中,会调用SpringApplication.run(DemoApplication.class,args),然后会分两步执行,第一步先创建SpringApplication对象,第二步运行run方法。

第一步、创建SpringApplication对象

这一步的主要功能初始化SpringApplication对象,从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer和ApplicationListener,然后保存起来,以便后边调用,最后找到main方法的主配置类。

private void initialize(Object[] sources) {
    //保存主配置类
    if (sources != null && sources.length > 0) {
        this.sources.addAll(Arrays.asList(sources));
    } 
    //判断当前是否一个web应用
    this.webEnvironment = deduceWebEnvironment();
    //从类路径下找到META‐INF/spring.factories配置的所有ApplicationContextInitializer;然后保存        起
来
    setInitializers((Collection) getSpringFactoriesInstances(
    ApplicationContextInitializer.class));
    //从类路径下找到ETA‐INF/spring.factories配置的所有ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //从多个配置类中找到有main方法的主配置类
    this.mainApplicationClass = deduceMainApplicationClass();
}

第二步、运行run方法

run方法中的重要点就是创建IOc容器context = createApplicationContext();,最后返回启动的IOC容器。中间会调用refreshContent(),最后调用到spring容器的refresh时,invokeBeanFactoryPostProcessors(beanFactory)方法中调用到ConfigurationClassPostProcessor。ConfigurationClassPostProcessor会解析到我们的主类,把@Import中的类拿出来,调用它的selectImports()方法。然后spring容器会对selectInports方法返回的配置类进行处理。

public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    FailureAnalyzers analyzers = null;
    configureHeadlessProperty();
    //获取SpringApplicationRunListeners;从类路径下META‐INF/spring.factories
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //回调所有的获取SpringApplicationRunListener.starting()方法
    listeners.starting();
    try {
        //封装命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
    args);
        //准备环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
    applicationArguments);
        //创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准
    备完成
        Banner printedBanner = printBanner(environment);
        //创建ApplicationContext;决定创建web的ioc还是普通的ioc
        context = createApplicationContext();
        analyzers = new FailureAnalyzers(context);
        //准备上下文环境;将environment保存到ioc中;而且applyInitializers();
        //applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
        //回调所有的SpringApplicationRunListener的contextPrepared();
        //
        prepareContext(context, environment, listeners, applicationArguments,
    printedBanner);
        //prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();
        //s刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat);Spring注解版
        //扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
        refreshContext(context);
        //从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
        //ApplicationRunner先回调,CommandLineRunner再回调
        afterRefresh(context, applicationArguments);
        //所有的SpringApplicationRunListener回调finished方法
        listeners.finished(context, null);
        stopWatch.stop();
        if (this.logStartupInfo) {
        new StartupInfoLogger(this.mainApplicationClass)
        .logStarted(getApplicationLog(), stopWatch);
        }
        //整个SpringBoot应用启动完成以后返回启动的ioc容器;
        return context;
    } catch (Throwable ex) {
        handleRunFailure(context, listeners, analyzers, ex);
        throw new IllegalStateException(ex);
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子松的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值