2024年10月springboot各个层的作用(Spring Boot 业务逻辑层)
⑴springboot各个层的作用(SpringBoot业务逻辑层
⑵SpringBoot业务逻辑层
⑶关于业务逻辑层(Service层
⑷业务逻辑层是被Controller直接调用的层(Controller不允许直接调用持久层,通常,在业务逻辑层中编写的代码是为了保证数据的完整性和安全性,使得数据是随着我们设定的规则而产生或发生变化。
⑸通常,在业务逻辑层的代码会由接口和实现类组件,其中,接口被视为是必须的
⑹关于抛出的异常,通常是自定义的异常,并且,自定义异常通常是`RuntimeException`的子类,主要原因:
⑺所以,在实际编写业务逻辑层之前,应该先规划异常,例如先创建`ServiceException`类:
⑻接下来,再创建具体的对应某种“失败”的异常,例如,在添加管理员时,可能因为“用户名已经存在”而失败,则创建对应的`UsernameDuplicateException`异常:
⑼另外,当插入数据时,如果返回的受影响行数不是时,必然是某种错误,则创建对应的插入数据异常:
⑽关于抽象方法的参数,应该设计为客户端提交的数据类型或对应的封装类型,不可以是数据表对应的实体类型!如果使用封装的类型,这种类型在类名上应该添加某种后缀,例如`DTO`或其它后缀,例如:
⑾并在以上`service`包下创建`impl`子包,再创建`AdminServiceImpl`类:
⑿以上代码未实现对密码的加密处理!关于密码加密,相关的代码应该定义在别的某个类中,不应该直接将加密过程编写在以上代码中,因为加密的代码需要在多处应用(添加用户、用户登录、修改密码等,并且,从分工的角度上来看,也不应该是业务逻辑层的任务!所以,在`.celinf.boot.demo.util`(包不存在,则创建下创建`PasswordEncoder`类,用于处理密码加密:
⒀完成后,需要在`AdminServiceImpl`中自动装配以上`PasswordEncoder`,并在需要加密时调用`PasswordEncoder`对象的`encode()`方法。
⒁SpringMVC是用于处理控制器层开发的,在使用SpringBoot时,在`pom.xml`中添加`spring-boot-starter-web`即可整合SpringMVC框架及相关的常用依赖项(包含`jackson-databind`,可以将已存在的`spring-boot-starter`直接改为`spring-boot-starter-web`,因为在`spring-boot-starter-web`中已经包含了`spring-boot-starter`。
⒂先在项目的根包下创建`controller`子包,并在此子包下创建`AdminController`,此类应该添加`RestController`和`RequestMapping(value=“/admins“,produces=“application/json;charset=utf-“)`注解,例如:
⒃由于已经决定了服务器端响应时,将响应JSON格式的字符串,为保证能够响应JSON格式的结果,处理请求的方法返回值应该是自定义的数据类型,则从此前学习的`spring-mvc`项目中找到`JsonResult`类及相关类型,复制到当前项目中来。
⒄完成后,运行启动类,即可启动整个项目,在`spring-boot-starter-web`中,包含了Tomcat的依赖项,在启动时,会自动将当前项目打包并部署到此Tomcat上,所以,执行启动类时,会执行此Tomcat,同时,因为是内置的Tomcat,只为当前项目服务,所以,在将项目部署到Tomcat时,默认已经将ContextPath(例如spring_mvc_war_exploded配置为空字符串,所以,在启动项目后,访问的URL中并没有此前遇到的ContextPath值。
⒅当项目启动成功后,即可在浏览器的地址栏中输入网址进行测试访问!
⒆【注意】:如果是未添加的管理员账号,可以成功执行结束,如果管理员账号已经存在,由于尚未处理异常,会提示错误。
⒇然后,在`.celinf.boot.demo.controller`下创建`handler.GlobalExceptionHandler`类,用于统一处理异常,例如:
⒈完成后,重新启动项目,当添加管理员时的用户名没有被占用时,将正常添加,当用户名已经被占用时,会根据处理异常的结果进行响应!
⒉由于在统一处理异常的机制下,同一种异常,无论是在哪种业务中出现,处理异常时的描述信息都是完全相同的,也无法精准的表达错误信息,这是不合适的!另外,基于面向对象的“分工”思想,关于错误信息(异常对应的描述信息,应该是由Service来描述,即“谁抛出谁描述”,因为抛出异常的代码片段是最了解、最明确出现异常的原因的!
⒊为了更好的描述异常的原因,应该在自定义的`ServiceException`和其子孙类异常中添加基于父类的全部构造方法(个,然后,在`AdminServiceImpl`中,当抛出异常时,可以在异常的构造方法中添加`String`类型的参数,对异常发生的原因进行描述,例如:
⒋最后,在处理异常时,可以调用异常对象的`getMessage()`方法获取抛出时封装的描述信息,例如:
⒌完成后,再次重启项目,当用户名已经存在时,可以显示在Service中描述的错误信息!
⒍可以看到,无论是成功还是失败,响应的JSON中都包含了不必要的数据(为`null`的数据,这些数据属性是没有必要响应到客户端的,如果需要去除这些不必要的值,可以在对应的属性上使用注解进行配置,例如:
⒎此注解还可以添加在类上,则作用于当前类中所有的属性,例如:
⒏即使添加在类上,也只对当前类的个属性有效,后续,当响应某些数据时,`data`属性可能是用户、商品、订单等类型,这些类型的数据中为`null`的部分依然会被响应到客户端去,所以,还需要对这些类型也添加相同的注解配置!
⒐以上做法相对比较繁琐,可以在`application.properties`/`application.yml`中添加全局配置,则作用于当前项目中所有响应时涉及的类,例如在`properties`中配置为:
⒑注意:当你需要在`yml`中添加以上配置时,前缀属性名可能已经存在,则不允许出现重复的前缀属性名的:
⒒最后,以上配置只是“默认”配置,如果在某些类型中还有不同的配置需求,仍可以在类或属性上通过`JsonInclude`进行配置。
⒓在使用前后端分离的开发模式下,前端项目和后端项目可能是个完全不同的项目,并且,各自己独立开发,独立部署,在这种做法中,如果前端直接向后端发送异步请求,默认情况下,在前端会出现类似以下错误:
⒔以上错误信息的关键字是`CORS`,通常称之为“跨域问题”。
⒕在基于SpringMVC框架的项目中,当需要解决跨域问题时,需要一个SpringMVC的配置类(实现了`WebMvonfigurer`接口的类,并重写其中的方法,以允许指定条件的跨域访问,例如:
⒖关于客户端提交请求参数的格式
⒗通常,客户端向服务器端发送请求时,请求参数可以有种形式,第种是直接通过`&`拼接各参数与值,例如:
⒘具体使用哪种做法,取决于服务器端的设计:
⒙-如果服务器端处理请求的方法中,在参数前添加了`RequestBody`,则允许使用以上第种做法(JSON数据提交请求参数,不允许使用以上第种做法(使用`&`拼接
⒚-如果没有使用`RequestBody`,则只能使用以上第种做法
⒛SpringBoot项目结构及功能
在IntelliJ使用SpringInitializer快速创建项目
这是pom文件中父项目,再进一步查看其spring-boot-starter-parent
发现真正管理SpringBoot应用里面的所有依赖版本的地方在这spring-boot-dependenciesSpringBoot的版本仲裁中心;以后我们导入依赖默认是不需要写版本;(没有在dependencies里面管理的依赖自然需要声明版本号再往下看:
这是springboot的web场景启动器,只要引入了它,就能帮我们导入了web模块正常运行所依赖的组件;
SpringBootApplication:SpringBoot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
SpringBootConfiguration:SpringBoot的配置类:标注在某个类上,表示这是一个SpringBoot的配置类;Configuration:配置类上来标注这个注解;配置类-----配置文件;配置类也是容器中的一个组件;ponent
EnableAutoConfiguration:开启自动配置功能;以前我们需要配置的东西,SpringBoot帮我们自动配置;EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;
在src下创建一个controller包,新建一个HelloController类,之后运行springboot,便可以通过localhost://hello来访问hello页面。
SpringBoot使用一个全局的配置文件,配置文件名是固定的;?application.properties?application.yml配置文件的作用:修改SpringBoot自动配置的默认值;SpringBoot在底层都给我们自动配置好;
springboot启动会扫描以下位置的application.properties或者application.yml文件作为Springboot的默认配置文件–file:优先级由高到底,高优先级的配置会覆盖低优先级的配置;SpringBoot会从这四个位置全部加载主配置文件;互补配置;
application.yml
Value获取值和ConfigurationProperties获取值比较配置文件yml还是properties他们都能获取到值;如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用Value;如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用ConfigurationProperties;==我们还可以通过spring.config.location来改变默认的配置文件位置==项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;java-jarspring-boot--config--..-SNAPSHOT.jar--spring.config.location=G:/application.properties
SpringBoot运行原理
SpringBoot是一个基于Spring开发,集成了大量第三方库配置的javaweb开发框架pom.xml父依赖其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件。以后我们导入依赖默认是不需要写版本的。启动器spring-boot-starterspringboot-boot-starter-xxx:spring-boot的场景启动器spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件。springBoot将所有的功能场景都抽取出来,做成一个个的starter(启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会被引进来,我们要用什么功能就导入什么样的场景启动器即可。SpringBootApplication作用:标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot运行这个类的main方法来启动SpringBoot应用。进入这个注解,里面包含了很多其他注解ponentScan作用:自动扫描并加载符合条件的组件或者bean,将这个bean定义加载到IOC容器中。SpringBootConfiguration作用:SpringBoot的配置类,标注在某个类上,表示这是一个SpringBoot的配置类。进入SpringBootConfiguration注解查看,这里的Configuration说明这是一个配置类,配置类对应Spring的xml配置文件。继续查看SpringBootConfiguration包含的其他注解EnableAutoConfiguration:开启自动配置功能进入EnableAutoConfiguration注解查看AutoConfigurationPackage自动配置包import:Spring底层注解import,给容器中导入一个组件Import({AutoConfigurationImportSelector.class}给容器导入组件AutoConfigurationImportSelector:自动配置导入选择器。那么它导入哪些组件的选择器呢这个类中有这样一个方法:getCandidateConfiguration,而在这个方法中有调用了SpringFactoriesLoader类的静态方法loadFactoryNames()方法进入loadSpringFactories方法根据全局搜索Spring.factories,打开后是自动配置的文件。随便打开一个其中的自动配置类看,它们都是javaConfig配置类,都注入了一些Bean所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件,并将其中对应的.springframework.boot.autoconfigure包下的配置项通过反射实例化为对应标注了Configuration的javaConfig形式的IOC容器配置类,然后将这些都汇总成为一个实例并加载到IOC容器中。结论:.SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值.将这些值作为自动配置类导入容器,自动配置类就生效,帮我们进行自动配置工作。.整个JEE的整体解决方案和自动配置都在springboot-autoConfigure的jar包中。.它会给容器中导入非常多的自动配置类(xxxAutoConfiguration,就是给容器中导入这个场景需要的所有组件,并配置好这些组件。.有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。SpringApplication这个类主要做了以下四件事.推断应用的类型是普通的项目还是web项目.查找并加载所有可用初始化器,设置到initializers属性中.找出所有的应用程序监听器,设置到listeners属性中.推断并设置main方法的定义类,找到运行的主类
Spring、SpringMVC、SpringBoot怎么使用,有什么区别啊
Spring、SpringMVC、SpringBoot都是框架~以下都是个人理解的语言说的。
先说SpringMVC,SpringMVC作用于控制层。代替了以往的struts.用起来更简单。
起到访问和跳转的作用。
Spring作用于service层(当有事务的时候,作用于dao层(当需要提供数据源等等操作的时候。
SpringBoot是一种快速启动框架,当你问这个问题是时候,我想你应该学了spring吧
那么spring的配置文件你应该了解吧。web.xml也需要配置吧。如果涉及到mybatis,
mybatis也要配置吧。而SpringBoot通常和maven一起使用,达到不需要配置spring的applicationCoxt.xml和web.xml,快速启动项目。springboot是现在的主流了。
具体如何实现我给你提供个网址自己学习去
网页链接?需要注册,完全免费
springboot的目录结构作用
Controller层像是一个服务员,他把客人(前端点的菜(数据、请求的类型等进行汇总什么口味、咸淡、量的多少,交给厨师长(Service层,厨师长则告诉沾板厨师(Dao、汤料房(Dao、配菜厨师(Dao等(统称Dao层我需要什么样的半成品,副厨们(Dao层就负责完成厨师长(Service交代的任务。不知道这个比喻是否合适。根据网络资源整理:
springbootvue后端有几层
有层。控制层_》调用业务层方法来控制业务逻辑,controller层的功能为请求和响应控制,controller层负责前后端交互,接受前端请求,调用service层,接收service层返回的数据,最后返回具体的页面和数据到客户端。
springboot分层后启动
springboot分层后启动?springboot分层这是一个分为两部分的系列,其中我将展示如何使用SpringBoot创建分层体系结构。什么是分层体系结构:简而言之,当我们构建企业应用程序时,我们维护不同的层以封装特定于层的逻辑,这样就不会溢出到另一层。当我们考虑企业应用程序时,我们可以想象该体系结构的三个重要层。.用户界面:与最终用户进行交互,向他们显示数据,接受用户输入,接受他们的命令等。.业务层:基于用户命令和从用户那里捕获的数据(AKA表单,它会做出特定于域的决策,例如如何处理数据,查找哪个表,如何处理数据。从数据库中获取,因此可以在UI中显示。.持久层:此层捕获数据并对其进行持久化,同样也捕获数据状态的任何更新,删除和更改,因此您可以将这一层视为维护特定于应用程序数据的状态。无论您的应用程序处于启动还是关闭状态,它都将在提交后存储数据的状态。通过分层体系结构,我们像所有代码一样在每一层上创建逻辑封装,有关UI的信息留在UI层中,有关业务逻辑的所有代码均留在业务层中,等等。每一层都与其相邻的层通信,但是从不与不相邻的另一层通信。因此,如果您的应用程序具有三层UI,即Business,DAO,UI与Business进行通信,Business与UI进行通信以及DAO和DAO与Business进行通信。通过这种方式,我们可以减少耦合,使层可重复使用,并欢迎体系结构的未来变化。每个层都有自己的模式,以适应将来的更改并使该层可重用。我们都知道Spring为每一层提供了不同的组件,例如,对于UI,您可以使用Thymleaf或Spring模板或任何其他UI框架(如JSF;对于Business层,可以使用Controller和service;还可以在其中注入Struts等不同的框架它。对于持久层,您可以使用Spring数据JPA,Hibernate,JDBC模板。但是问题是您需要在pom.xml中添加所有插件/Jars。在类路径中找到依赖项的正确版本。如果版本不匹配,它将无法正常工作。另外,您还需要在SpringXML文件中添加许多Spring特定的批注或XML条目,以在分层体系结构中使用那些组件/插件,这是一种繁琐的方法。另外,您需要打包它们并将它们部署在应用程序服务器中,因此需要许多手动干预。Spring解决了这个问题,并提出了一个称为SpringBoot的解决方案。“Spring-boot按照约定优于配置进行工作”-这意味着您不必考虑配置条目,只需要注意业务逻辑,就可以在类路径中提到要使用的组件而无需考虑使用任何组件。聪明,它会理解您想要使用它并为您配置一个完全正常工作的组件。假设您要在项目中使用JPA。如果您导入SpringbootstarterJPA模块,它将了解您要使用它,并会即时为您创建Spring模板的存储库和实用程序CRUD方法。如果没有Spring-boot,则需要配置JPA模板,从模板启动会话工厂,获取会话等,而这在这里不是必需的,SpringBoot如此强大,可以为您做到这一点,当然,如果您想要自己控制配置,您可以覆盖它们并使用自己的配置。
springboot原理
前端常使用模板引擎,主要有FreeMarker和Thymeleaf,它们都是用Java语言编写的,渲染模板并输出相应文本,使得界面的设计与应用的逻辑分离,同时前端开发还会使用到Bootstrap、AngularJS、JQuery等;
在浏览器的数据传输格式上采用Json,非xml,同时提供RESTfulAPI;SpringMVC框架用于数据到达服务器后处理请求;到数据访问层主要有Hibernate、MyBatis、JPA等持久层框架;数据库常用MySQL;开发工具推荐IntelliJIDEA。
SpringBoot所具备的特征有:
可以创建独立的Spring应用程序,并且基于其Maven或Gradle插件,可以创建可执行的JARs和WARs;
内嵌Tomcat或Jetty等Servlet容器;
提供自动配置的“starter”项目对象模型(POMS以简化Maven配置;
尽可能自动配置Spring容器;
提供准备好的特性,如指标、健康检查和外部化配置;
绝对没有代码生成,不需要XML配置。
Spring的初衷:
JAVAEE开发应该更加简单。
使用接口而不是使用类,是更好的编程习惯。Spring将使用接口的复杂度几乎降低到了零。
为JavaBean提供了一个更好的应用配置框架。
更多地强调面向对象的设计,而不是现行的技术如JAVAEE。
尽量减少不必要的异常捕捉。
使应用程序更加容易测试。
参考资料来源:百度百科-spring框架
参考资料来源:百度百科-SpringBoot
聊聊SpringBoot面试相关问题
SpringBoot是Spring开源组织下的子项目,是Spring组件一站式解决方案,主要是简化了使用Spring的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。SpringBoot主要有如下优点:启动类上面的注解是SpringBootApplication,它也是SpringBoot的核心注解,主要组合包含了以下个注解:SpringBootConfiguration:组合了Configuration注解,实现配置文件的功能。EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能:SpringBootApplication(exclude={DataSourceAutoConfiguration.class})。ponentScan:Spring组件扫描。SpringJavaConfig是Spring社区的产品,它提供了配置SpringIoC容器的纯Java方法。因此它有助于避免使用XML配置。使用JavaConfig的优点在于:(面向对象的配置。由于配置被定义为JavaConfig中的类,因此用户可以充分利用Java中的面向对象的功能。一个配置类可以继承另一个,重写它的Bean方法等。(减少或消除XML配置。基于依赖注入原则的外化配置的好处已被证明。但是,许多开发人员不希望在XML和Java之间来回切换。JavaConfig为开发人员提供了一种纯粹Java方法来配置与XML配置概念相似的Spring容器。从技术角度来讲,只是使用JavaConfig配置类来配置容器是可行的,但实际上很多人认为将JavaConfig与XML混合匹配是理想的。(类型安全和重构友好。JavaConfig提供了一种类型安全的方法来配置Spring容器。由于Java.对泛型的支持,现在可以按类型而不是按名称检索bean,不需要任何强制转换或基于字符串的查找。BFPP:BeanFactoryPostProcessorBPP:BeanPostProcessorBDRPP:BeanDefinitionRegistryPostProcessor表达的总体思路是:总-分-总、springboot自动装配是什么,解决了什么问题、自动装配实现的原理:、当启动springboot应用程序的时候,会先创建SpringApplication的对象,在对象的构造方法中会进行某些参数的初始化工作,最主要的是判断当前应用程序的类型以及初始化器和监听器,在这个过程中会加载整个应用程序中的spring.factories文件,将文件的内容放到缓存对象中,方便后续获取。、SpringApplication对象创建完成之后,开始执行run方法,来完成整个启动,启动过程中最主要的有两个方法,第一个叫做prepareContext,第二个叫做refreshContext,在这两个关键步骤中完整了自动装配的核心功能,前面的处理逻辑包含了上下文对象的创建,banner的打印,异常报告期的准备等各个准备工作,方便后续来进行调用。、在prepareContext方法中主要完成的是对上下文对象的初始化操作,包括了属性值的设置,比如环境对象,在整个过程中有一个非常重要的方法,叫做load,load主要完成一件事,将当前启动类做为一个beanDefinition注册到registry中,方便后续在进行BeanFactoryPostProcessor调用执行的时候,找到对应的主类,来完成SpringBootApplicaiton,EnableAutoConfiguration等注解的解析工作、在refreshContext方法中会进行整个容器刷新过程,会调用中spring中的refresh方法,refresh中有个非常关键的方法,来完成整个spring应用程序的启动,在自动装配过程中,会调用invokeBeanFactoryPostProcessor方法,在此方法中主要是对ConfigurationClassPostProcessor类的处理,这次是BFPP的子类也是BDRPP的子类,在调用的时候会先调用BDRPP中的postProcessBeanDefinitionRegistry方法,然后调用postProcessBeanFactory方法,在执行postProcessBeanDefinitionRegistry的时候回解析处理各种注解,包含PropertySource,ponentScan,ponentScans,Bean,Import等注解,最主要的是Import注解的解析。、在解析Import注解的时候,会有一个getImports的方法,从主类开始递归解析注解,把所有包含Import的注解都解析到,然后在processImport方法中对Import的类进行分类,此处主要识别的时候AutoConfigurationImportSelect归属于ImportSelect的子类,在后续过程中会调用deferredImportSelectorHandler中的process方法,来完整EnableAutoConfiguration的加载。、上面是我对springboot自动装配的简单理解,面试官您看一下,我回答有没有问题,帮我指点一下!在SpringBoot里面,可以使用以下几种方式来加载配置。properties文件;YAML文件;系统环境变量;等等……YAML是一种人类可读的数据序列化语言。它通常用于配置文件。与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML文件就更加结构化,而且更少混淆。可以看出YAML具有分层配置数据。YAML现在可以算是非常流行的一种配置文件格式了,无论是前端还是后端,都可以见到YAML配置。那么YAML配置和传统的properties配置相比到底有哪些优势呢?相比properties配置文件,YAML还有一个缺点,就是不支持PropertySource注解导入自定义的YAML配置。SpringBoot推荐使用Java配置而非XML配置,但是SpringBoot中也可以使用XML配置,通过ImportResource注解可以引入一个XML配置。springboot核心配置文件是什么?bootstrap.properties和application.properties有何区别?单纯做SpringBoot开发,可能不太容易遇到bootstrap.properties配置文件,但是在结合SpringCloud时,这个配置就会经常遇到了,特别是在需要加载一些远程配置文件的时侯。springboot核心的两个配置文件:bootstrap(.yml或者.properties):boostrap由父ApplicationContext加载的,比applicaton优先加载,配置在应用程序上下文的引导阶段生效。一般来说我们在SpringCloudConfig或者Nacos中会用到它。且boostrap里面的属性不能被覆盖;application(.yml或者.properties):由ApplicatonContext加载,用于springboot项目的自动化配置。SpringProfiles允许用户根据配置文件(dev,test,prod等来注册bean。因此,当应用程序在开发中运行时,只有某些bean可以加载,而在PRODUCTION中,某些其他bean可以加载。假设我们的要求是Swagger文档仅适用于QA环境,并且禁用所有其他文档。这可以使用配置文件来完成。SpringBoot使得使用配置文件非常简单。为了在自定义端口上运行SpringBoot应用程序,您可以在application.properties中指定端口。server.port=为了实现SpringBoot的安全性,我们使用spring-boot-starter-security依赖项,并且必须添加安全配置。它只需要很少的代码。配置类将必须扩展WebSecurityConfigurerAdapter并覆盖其方法。跨域可以在前端通过JSONP来解决,但是JSONP只可以发送GET请求,无法发送其他类型的请求,在RESTful风格的应用中,就显得非常鸡肋,因此我们推荐在后端通过(CORS,Cross-originresourcesharing来解决跨域问题。这种解决方案并非SpringBoot特有的,在传统的SSM框架中,就可以通过CORS来解决跨域问题,只不过之前我们是在XML文件中配置CORS,现在可以通过实现WebMvonfigurer接口然后重写addCorsMa
SpringBoot核心原理:自动配置、事件驱动、Condition
SpringBoot是Spring的包装,通过自动配置使得SpringBoot可以做到开箱即用,上手成本非常低,但是学习其实现原理的成本大大增加,需要先了解熟悉Spring原理。如果还不清楚Spring原理的,可以先查看博主之前的文章,本篇主要分析SpringBoot的启动、自动配置、Condition、事件驱动原理。SpringBoot启动非常简单,因其内置了Tomcat,所以只需要通过下面几种方式启动即可:可以看到第一种是最简单的,也是最常用的方式,需要注意类上面需要标注SpringBootApplication注解,这是自动配置的核心实现,稍后分析,先来看看SpringBoot启动做了些什么?在往下之前,不妨先猜测一下,run方法中需要做什么?对比Spring源码,我们知道,Spring的启动都会创建一个ApplicationContext的应用上下文对象,并调用其refresh方法启动容器,SpringBoot只是Spring的一层壳,肯定也避免不了这样的操作。另一方面,以前通过Spring搭建的项目,都需要打成War包发布到Tomcat才行,而现在SpringBoot已经内置了Tomcat,只需要打成Jar包启动即可,所以在run方法中肯定也会创建对应的Tomcat对象并启动。以上只是我们的猜想,下面就来验证,进入run方法:SpringBoot的启动流程就是这个方法,先看getRunListeners方法,这个方法就是去拿到所有的SpringApplicationRunListener实现类,这些类是用于SpringBoot事件发布的,关于事件驱动稍后分析,这里主要看这个方法的实现原理:一步步追踪下去可以看到最终就是通过SPI机制根据接口类型从META-INF/spring.factories文件中加载对应的实现类并实例化,SpringBoot的自动配置也是这样实现的。为什么要这样做呢?通过注解扫描不可以么?当然不行,这些类都在第三方jar包中,注解扫描实现是很麻烦的,当然你也可以通过Import注解导入,但是这种方式不适合扩展类特别多的情况,所以这里采用SPI的优点就显而易见了。回到run方法中,可以看到调用了createApplicationContext方法,见名知意,这个就是去创建应用上下文对象:注意这里通过反射实例化了一个新的没见过的上下文对象AnnotationConfigServletWebServerApplicationContext,这个是SpringBoot扩展的,看看其构造方法:如果你有看过Spring注解驱动的实现原理,这两个对象肯定不会陌生,一个实支持注解解析的,另外一个是扫描包用的。上下文创建好了,下一步自然就是调用refresh方法启动容器:这里首先会调用到其父类中ServletWebServerApplicationContext:可以看到是直接委托给了父类:这个方法不会陌生吧,之前已经分析过了,这里不再赘述,至此SpringBoot的容器就启动了,但是Tomcat启动是在哪里呢?run方法中也没有看到。实际上Tomcat的启动也是在refresh流程中,这个方法其中一步是调用了onRefresh方法,在Spring中这是一个没有实现的模板方法,而SpringBoot就通过这个方法完成了Tomcat的启动:这里首先拿到TomcatServletWebServerFactory对象,通过该对象再去创建和启动Tomcat:上面的每一步都可以对比Tomca