SpringBoot源码解读与原理分析(入门)

2022-09-07 09:28:16

SpringBoot源码解读与原理分析(入门)

简介:

  • 由Pivotal团队提供的全新框架
  • 其设计目的是用来简化新Spring应用的初始搭建以及开发过程
  • 使用了特定的方式来进行配置
  • 快速应用开发领域

运行原理以及特点

特点:

  • 可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
  • 内嵌Tomcat或Jetty等Servlet容器;
  • 提供自动配置的“starter”项目对象模型(POMS)以简化Maven配置;
  • 尽可能自动配置Spring容器;
  • 提供准备好的特性,如指标、健康检查和外部化配置;
  • 绝对没有代码生成,不需要XML配置。

运行原理:在这里插入图片描述

重点:

(一)约定优于配置
90%以上的项目呢,配置都差不多,所以呢spring团队,就搞出了一个通用的配置,以后我们程序猿就不需要再去配置这些繁杂的配置了. 如果用的ssm,所有的maven依赖,版本,都需要我们程序猿去控制,去找依赖,并且互相配合依赖.依赖没有配合好,jar冲突,,出了问题就需要程序猿去解决,一般非常耗时的.
补充:约定优于配置也被称为习惯优于配置、约定大于配置
提示:全局配置名称,默认 application
配置文件优先级:有config>无configh properties > yml > yaml

(二)开箱即用

  • 内嵌Tomcat或Jetty等Servlet容器;
  • 用来简化新Spring应用的初始搭建以及开发过程
  • 每一个stater都是一个场景功能
<!--引入web starter启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

(三)程序入口

/*
springboot启动类,服务类
@SpringBootApplication是一个复合注解(包括@ComponentScan,和@SpringBootConfiguration,@EnableAutoConfiguration)
 */
@SpringBootApplicationpublicclassDemo0817Application{publicstaticvoidmain(String[] args){
        SpringApplication.run(Demo0817Application.class, args);}//main 程序的入口}

(四)常用注解

字段说明
@ComponentScan自动扫描组件,可自发配置一些Bean
@Configuration等同于 spring 的 XML 配置文件
@EnableAutoConfiguration根据jar依赖自动配置Spring应用
@SpringBootApplication给springBoot自动进行必要的配置(@Configuration ,@EnableAutoConfiguration 和 @ComponentScan)
@ResponseBody异步获取数据
@Controller定义控制类
@RequestMapping负责URL到Controller中的具体参数的映射
@Import导入其他配置类
@ImportResourc加载xml配置文件
@Autowired自动导入依赖的Bean
@Service修饰Server层
@Repository可以确保 DAO 或者 repositories 提供异常转译,这个注解修饰的 DAO 或者 repositories 类会被 ComponetScan 发现并配置,同时也不需要为它们提供 XML 配置项
@Bean等同于xml中配置的Bean
@Value注入值给配置类
@Inject等同于@Autowired(无required 属性)
@Component泛指组件
@Qualifier当有多个同一类型的 Bean 时,可以用 @Qualifier(“name”) 来指定。与 @Autowired 配合使用。@Qualifier 只描述符除了能根据名字进行注入,还能更详细的控制如何选择候选者
@Resource@Resource(name=”name”,type=”type”) 默认 byName 与@Autowired类似

还有JPA和springMVC以及全局异常处理可通过超连接访问

实例化SpringApplication

SpringApplication初始化时主要做三件事情:

  • 根据classpath下是否存在(ConfigurableWebApplicationContext)判断是否要启动一个web applicationContext
  • SpringFactoriesInstances加载classpath下所有可用的ApplicationContextInitializer
  • SpringFactoriesInstances加载classpath下所有可用的ApplicationListener
publicSpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources){this.resourceLoader= resourceLoader;
   Assert.notNull(primarySources,"PrimarySources must not be null");this.primarySources=newLinkedHashSet<>(Arrays.asList(primarySources));//1.根据classpath下是否存在(ConfigurableWebApplicationContext)判断是否要启动一个web applicationContextthis.webApplicationType= WebApplicationType.deduceFromClasspath();//2.SpringFactoriesInstances加载classpath下所有可用的ApplicationContextInitializersetInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));//3.SpringFactoriesInstances加载classpath下所有可用的ApplicationListenersetListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass=deduceMainApplicationClass();}

执行run方法

代码如下:

public ConfigurableApplicationContextrun(String... args){
    StopWatch stopWatch=newStopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context=null;
    Collection<SpringBootExceptionReporter> exceptionReporters=newArrayList<>();configureHeadlessProperty();//1.遍历SpringApplication初始化过程中加载的SpringApplicationRunListeners
    SpringApplicationRunListeners listeners=getRunListeners(args);//2.调用starting()监听SpringApplication的启动
    listeners.starting();try{
        ApplicationArguments applicationArguments=newDefaultApplicationArguments(args);//3.加载SpringBoot配置环境
        ConfigurableEnvironment environment=prepareEnvironment(listeners, applicationArguments);configureIgnoreBeanInfo(environment);//4.设置banner属性
        Banner printedBanner=printBanner(environment);//5.创建ConfigurableApplicationContext(应用配置上下文)
        context=createApplicationContext();
        exceptionReporters=getSpringFactoriesInstances(SpringBootExceptionReporter.class,newClass[]{ ConfigurableApplicationContext.class}, context);//6.将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联prepareContext(context, environment, listeners, applicationArguments, printedBanner);//7.实例化beanrefreshContext(context);afterRefresh(context, applicationArguments);
        stopWatch.stop();if(this.logStartupInfo){newStartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}
        listeners.started(context);callRunners(context, applicationArguments);}catch(Throwable ex){handleRunFailure(context, ex, exceptionReporters, listeners);thrownewIllegalStateException(ex);}try{
        listeners.running(context);}catch(Throwable ex){handleRunFailure(context, ex, exceptionReporters,null);thrownewIllegalStateException(ex);}return context;}

遍历SpringApplication初始化过程中加载的SpringApplicationRunListeners:

private SpringApplicationRunListenersgetRunListeners(String[] args){
    Class<?>[] types=newClass<?>[]{ SpringApplication.class, String[].class};returnnewSpringApplicationRunListeners(logger,getSpringFactoriesInstances(SpringApplicationRunListener.class, types,this, args));}

调用Starting()监听SpringApplication的启动:

publicvoidstarting(){//遍历所有的SpringApplicationRunListener,调用starting()方法监听SpringApplication的启动for(SpringApplicationRunListener listener:this.listeners){
        listener.starting();}}

加载SpringBoot配置环境

 加载SpringBoot配置环境,如果是通过web容器发布,会加载StandardEnvironment。将配置文件(Environment)加入到监听器对象中(SpringApplicationRunListeners)private ConfigurableEnvironmentprepareEnvironment(SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments){// Create and configure the environment//如果environment不为空直接返回 || 如果是web环境则直接实例化StandardServletEnvironment类 || 如果不是web环境则直接实例化StandardEnvironment类
    ConfigurableEnvironment environment=getOrCreateEnvironment();//配置环境信息configureEnvironment(environment, applicationArguments.getSourceArgs());//通知所有的监听者,环境已经准备好了
    listeners.environmentPrepared(environment);bindToSpringApplication(environment);if(!this.isCustomEnvironment){
        environment=newEnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,deduceEnvironmentClass());}
    ConfigurationPropertySources.attach(environment);return environment;}

初始化ConfigurableApplicationContext

publicenum WebApplicationType{/**
     * The application should not run as a web application and should not start an
     * embedded web server.
     */// 应用程序不是web应用,也不应该用web服务器去启动NONE,/**
     * The application should run as a servlet-based web application and should start an
     * embedded servlet web server.
     *///应用程序应作为基于servlet的web应用程序运行,并应启动嵌入式servlet web(tomcat)服务器SERVLET,/**
     * The application should run as a reactive web application and should start an
     * embedded reactive web server.
     *///应用程序应作为 reactive web应用程序运行,并应启动嵌入式 reactive web服务器。REACTIVE;}

根据webEnvironment是否是web环境创建默认的contextClass,

AnnotationConfigEnbeddedWebApplicationContext(通过扫描所有注解类来加载bean)和ConfigurableWebApplicationContext),最后通过BeanUtils实例化上下文对象,并返回。protected ConfigurableApplicationContextcreateApplicationContext(){//根据webEnvironment是否是web环境创建默认的contextClass
    Class<?> contextClass=this.applicationContextClass;if(contextClass==null){try{switch(this.webApplicationType){caseSERVLET://AnnotationConfigServletWebServerApplicationContext
                contextClass= Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);break;caseREACTIVE://AnnotationConfigReactiveWebServerApplicationContext
                contextClass= Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default://AnnotationConfigApplicationContext
                contextClass= Class.forName(DEFAULT_CONTEXT_CLASS);}}catch(ClassNotFoundException ex){thrownewIllegalStateException("Unable create a default ApplicationContext, "+"please specify an ApplicationContextClass",
                    ex);}}//BeanUtils实例化上下文对象return(ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);}

将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联

privatevoidprepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
        SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner){//设置上下文的environment
    context.setEnvironment(environment);//应用上下文后处理postProcessApplicationContext(context);//在context refresh之前,对其应用ApplicationContextInitializerapplyInitializers(context);//上下文准备
    listeners.contextPrepared(context);//打印启动日志和启动应用的profileif(this.logStartupInfo){logStartupInfo(context.getParent()==null);logStartupProfileInfo(context);}// Add boot specific singleton beans
    ConfigurableListableBeanFactory beanFactory= context.getBeanFactory();//向beanFactory注册单例bean:命令行参数bean
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if(printedBanner!=null){//向beanFactory注册单例bean:banner bean
        beanFactory.registerSingleton("springBootBanner", printedBanner);}if(beanFactoryinstanceofDefaultListableBeanFactory){((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// Load the sources//获取SpringApplication的primarySources属性
    Set<Object> sources=getAllSources();
    Assert.notEmpty(sources,"Sources must not be empty");//将bean加载到应用上下文load(context, sources.toArray(newObject[0]));//向上下文添加ApplicationListener,并广播ApplicationPreparedEvent事件
    listeners.contextLoaded(context);}

~bean的实例化完成

  • 作者:果办办
  • 原文链接:https://blog.csdn.net/qq_41338528/article/details/108260668
    更新时间:2022-09-07 09:28:16