Springboot原理详细介绍

一、为什么要使用Springboot?🌼

    我们使用ssm开发项目的时候,需要编写大量的XML文件,繁琐的配置,这样会导致开发效率低下和部署效率等等问题。那怎么解决呢?使用我们的Springboot!!!

二、Springboot概述 🌷

Spring Boot官网

       Spring Boot是一种基于Spring框架的快速开发应用程序的工具。我们从Springboot官网来介绍

特征(优点):

●   创建独立的Spring应用程序

●   直接嵌入Tomcat、Jetty或Under拖车(不需要部署WAR文件)

●   提供固执己见的“初学者”依赖关系,以简化构建配置

●   尽可能自动配置Spring和第三方库

●   提供生产准备功能,如度量、健康检查和外部化配置。

●   绝对不需要生成代码,也不需要xml配置。

1、Springboot原理  💖

Springboot的核心注解

   SpringBoot的 核心注解是 @SpringBootApplication ,@SpringBootApplication 是一个组合注解。

 

 

@Target({ElementType.TYPE})

    @Target 注解通常与 Element 类一起使用。Element 是一个枚举类,定义了可以被注释应用的不同目标元素类型。 @Target({ElementType.TYPE}) 是Java中的元注解,用于指定被注解的注解可以应用的目标元素类型。

  @Retention(RetentionPolicy.RUNTIME)

       @@Retention 注解通常与 RetentionPolicy 枚举一起使用,用于指定注解的保留策略。

在使用 @Retention 注解时,需要传入一个 RetentionPolicy 值,指定注解的保留策略。

@SpringBootConfiguration

    @SpringBootConfiguration 是 Spring Boot 框架的注解之一,用于表示一个类为Spring Boot 的配置类。具体来说,@SpringBootConfiguration 注解是 @Configuration 注解的派生注解。它用于告诉Spring Boot 框架,被标记的类是一个配置类,其中可以包含一些配置信息、Bean的定义或其他配置相关的操作。

@EnableAutoConfiguration

        用于自动配置应用程序所需的各种配置和依赖项。

具体来说,@EnableAutoConfiguration 注解告诉 Spring Boot 框架启用自动配置机制,它会根据 classpath 下的依赖和配置,尝试推断和自动配置应用程序所需的 Bean。

@ComponentScan

        用于配置组件扫描的注解 @ComponentScan,它用于告诉 Spring 框架在指定的包中扫描并注册组件(例如,被 @Component@Service@Repository @Controller 注解标记的类)。

        其中,excludeFilters 属性用于指定排除某些组件的过滤器。在这个例子中,定义了两个过滤器:

  1. 第一个过滤器:

    • type = FilterType.CUSTOM 表示使用自定义的过滤器类型。
    • classes = {TypeExcludeFilter.class} 指定了要使用的过滤器类,即 TypeExcludeFilter 类。 这个过滤器用于排除特定类型的组件。
  2. 第二个过滤器:

    • type = FilterType.CUSTOM 表示使用自定义的过滤器类型。
    • classes = {AutoConfigurationExcludeFilter.class} 指定了要使用的过滤器类,即 AutoConfigurationExcludeFilter 类。 这个过滤器用于排除自动配置的组件。

2、SpringBoot启动流程 💖

     从我们的主启动类入手,即是标注着@SpringBootApplication注解并且有着 main() 方法的类,如下一段代码:

Run() 方法

首先执行的是我们的 run 方法:

        它里面做了两件事情 ,分别是创建 SpringApplication执行 run() 方法。

如何创建SpringApplication?

①  设置应用类型

     这个过程非常重要,直接决定了项目的类型,应用类型分为三种,都在WebApplicationType这个枚举类中,如下:

1、NONE :顾名思义,什么都没有,正常流程走,不额外的启动web容器,比如Tomcat。 没有:顾名思义,什么都没有,正常流程走,不额外的启动容器,比如Tomcat。

2、SERVLET:基纡servlet 的web程序,需要启动内嵌的servlet web容器,比如Tomcat 。 Servlet:基纡Servlet的Web程序,需要启动内嵌的Servlet Web容器,比如Tomcat。

3、REACTIVE :基于reactive的web程序,需要启动内嵌reactive web容器。

       判断的依据很简单,就是加载对应的类,比如加载了 DispatchServlet 等则会判断是 Servlet 的web程序。源码如下:

    static WebApplicationType deduceFromClasspath() {
        if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
            return REACTIVE;
        } else {
            String[] var0 = SERVLET_INDICATOR_CLASSES;
            int var1 = var0.length;

            for(int var2 = 0; var2 < var1; ++var2) {
                String className = var0[var2];
                if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
                    return NONE;
                }
            }

            return SERVLET;
        }
    }

这里我引入了是 spring-boot-starter-web ,肯定是 Servlet 的web程序。

② 设置初始化器(Initializer)

初始化器 ApplicationContextInitializer 是个好东西,用于 IOC 容器刷新之前初始化一些组件,比如 ServletContextApplicationContextInitializer

那么如何获取初始化器呢?

相对重要的就是第一步获取初始化器的名称了,这个肯定是 全类名 了,详细源码肯定在 loadFactoryNames() 方法中了,跟着源码进入,最终调用的是 #SpringFactoriesLoader.loadSpringFactories() 方法。

        loadSpringFactories () 方法就不再详细解释了,其实就是从类路径 META-INF/spring.factories 中加载 ApplicationContextInitializer 的值。

注:上图中的只是一部分初始化器,因为 spring.factories 文件不止一个。

③  设置监听器(Listener)

   监听器 (ApplicationListener) 这个概念在 Spring 中就已经存在,主要用于监听特定的事件( ApplicationEvent ),比如IOC容器刷新、容器关闭等。

  SpringApplication 的构建都是为了 run() 方法启动做铺垫,构造方法中总共就有几行代码,最重要的部分就是设置应用类型、设置初始化器、设置监听器。

 注意

        初始化器和这里的监听器都要放置在 spring.factories 文件中才能在这一步骤加载,否则不会生效,因此此时IOC容器还未创建,即使将其注入到IOC容器中也是不会生效的。

执行run()方法

①、获取、启动运行过程监听器

   SpringApplicationRunListener这个监听器和ApplicationListener不同,它是用来监听应用程序启动过程的,接口的各个方法含义如下:

public interface SpringApplicationRunListener {

    // 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作
    void starting();
    // 当environment构建完成,ApplicationContext创建之前,该方法被调用
    void environmentPrepared(ConfigurableEnvironment environment);
    // 当ApplicationContext构建完成时,该方法被调用
    void contextPrepared(ConfigurableApplicationContext context);
    // 在ApplicationContext完成加载,但没有被刷新前,该方法被调用
    void contextLoaded(ConfigurableApplicationContext context);
    // 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
    void started(ConfigurableApplicationContext context);
    // 在run()方法执行完成前该方法被调用
    void running(ConfigurableApplicationContext context);
    // 当应用运行出错时该方法被调用
    void failed(ConfigurableApplicationContext context, Throwable exception);
}

②、环境构建

        这一步主要用于加载系统配置以及用户的自定义配置(application.properties),源码如下,在run()方法中:

ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

③、创建IOC容器

context = createApplicationContext();

      根据webApplicationType决定创建的类型,很显然,我这里的是servlet,因此创建的是AnnotationConfigServletWebServerApplicationContext

④、IOC容器的前置处理

         这一步真是精华了,在刷新容器之前做准备,其中有一个非常关键的操作:将启动类注入容器,为后续的自动化配置奠定基础。源码如下:

prepareContext(context, environment, listeners, applicationArguments,printedBanner);

⑤、刷新容器

protected void refresh(ApplicationContext applicationContext) {
    Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    //调用创建的容器applicationContext中的refresh()方法
    ((AbstractApplicationContext)applicationContext).refresh();
}
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        /**
         * 刷新上下文环境
         */
        prepareRefresh();

/**
         * 初始化BeanFactory,解析XML,相当于之前的XmlBeanFactory的操作,
         */
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        /**
         * 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
         * 添加ApplicationContextAwareProcessor处理器
         * 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
         * 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
         */
        prepareBeanFactory(beanFactory);

        try {
/**
             * 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
             */
            postProcessBeanFactory(beanFactory);

            /**
             * 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
             * 执行对应的postProcessBeanDefinitionRegistry方法 和  postProcessBeanFactory方法
             */
            invokeBeanFactoryPostProcessors(beanFactory);

            /**
             * 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
             * 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
             */
            registerBeanPostProcessors(beanFactory);

            /**
             * 初始化上下文中的资源文件,如国际化文件的处理等
             */
            initMessageSource();

            /**
             * 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
             */
            initApplicationEventMulticaster();

            /**
             * 给子类扩展初始化其他Bean
             */
            onRefresh();

            /**
             * 在所有bean中查找listener bean,然后注册到广播器中
             */
            registerListeners();

            /**
             * 设置转换器
             * 注册一个默认的属性值解析器
             * 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
             * 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
             */
            finishBeanFactoryInitialization(beanFactory);

            /**
             * 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理
             * 即对那种在spring启动后需要处理的一些类,这些类实现了ApplicationListener<ContextRefreshedEvent>,
             * 这里就是要触发这些类的执行(执行onApplicationEvent方法)
             * 另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
             * 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
             */
            finishRefresh();
        }

        finally {

            resetCommonCaches();
        }
    }
}

⑥、IOC容器的后置处理

默认为空,如果有自定义需求可以重写,比如打印一些启动结束日志等。

afterRefresh(context, applicationArguments);

⑦、发出结束执行的事件

同样是EventPublishingRunListener这个监听器,广播ApplicationStartedEvent事件。

public void started(ConfigurableApplicationContext context) {
    context . publishEvent(new ApplicationS tartedEvent(this .application, this .args, context));
    AvailabilityChangeEvent . publish (context, Livenessstate . CORRECT) ;
}

⑧、执行Runners

   Spring Boot 提供了两种Runner让我们定制一些额外的操作,分别是CommandLineRunnerApplicationRunner

callRunners(context, applicationArguments);
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值