springboot原理

从启动类开始:

@EnableAsync
@EnableCaching
@EnableFeignClients
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

通过 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 {}

@SpringBootConfiguration实际上是一个@configuration。他本身也就是IOC容器的配置类。
@ComponentScan注解完成的是自动扫描的功能,相当于Spring XML配置文件中的:context:component-scan,可以使用encludeFilters,includeFilters等属性指定或排除要扫描的包,以及扫描的条件。最终将这些bean定义加载到容器中。
@EnableAutoConfiguration是让Spring Boot的配置能够如此简化的关键性注解,Spring-Boot 根据应用所声明的jar包依赖来对Spring框架进行自动配置。比如根据spring-boot-starter-web ,来判断你的项目是否需要添加了webmvc和tomcat,就会自动的帮你配置web项目中所需要的默认配置。

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

AutoConfigurationImportSelector这个类是一个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对象

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.isCustomEnvironment = false;
        this.lazyInitialization = false;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
  

    private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
        ClassLoader classLoader = this.getClassLoader();
        Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
        List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
        AnnotationAwareOrderComparator.sort(instances);
        return instances;
    }

    private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {
        List<T> instances = new ArrayList(names.size());
        Iterator var7 = names.iterator();

        while(var7.hasNext()) {
            String name = (String)var7.next();

            try {
                Class<?> instanceClass = ClassUtils.forName(name, classLoader);
                Assert.isAssignable(type, instanceClass);
                Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
                T instance = BeanUtils.instantiateClass(constructor, args);
                instances.add(instance);
            } catch (Throwable var12) {
                throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);
            }
        }

        return instances;
    }

从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer和ApplicationListener,然后保存起来,以便后边调用,最后找到main方法的主配置类。
加载 ApplicationContextInitializer 是在 SpringFactoriesLoader.loadFactoryNames 方法里面进行的。这个方法会尝试从类路径的 META-INF/spring.factories 读取相应配置文件,然后进行遍历,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer 的 value。

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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值