写点什么

阿里面试官:就说最后一遍,有关 Spring 这 13 点我们必问!

  • 2021 年 11 月 12 日
  • 本文字数:9464 字

    阅读完需:约 31 分钟

2.2 Context

IOC?容器只是提供一个管理对象的空间而已,如何向容器中放入我们需要容器代为管理的对象呢?这就涉及到 Spring 的应用上下文 Context


应用上下文 Context?:


基于 Core 和 Beans,提供了大量的扩展,包括国际化操作(基于 JDK )、资源加载(基于 JDK properties)、数据校验(Spring 自己封装的数据校验机制)、数据绑定(Spring 特有,HTTP 请求中的参数直接映射<typo id="typo-2467" data-origin="称" ignoretag="true">称</typo> POJO)、类型转换,ApplicationContext 接口是 Context 的核心,可以理解为 Bean 的上下文或背景信息。


可以简单的理解 应用上下文 是 Spring 容器的一种抽象化表述,而我们常见的?ApplicationContext?本质上就是一个维护 Bean 定义以及对象之间协作关系的高级接口。Spring 框架本身就提供了很多个容器的实现,大概分为两种类型:


  1. 一种是不常用的 BeanFactory,这是最简单的容器,只能提供基本的 DI 功能。

  2. 另外一种就是继承了 BeanFactory 后派生而来的应用上下文,其抽象接口也就是我们上面提到的的 ApplicationContext,它能提供更多企业级的服务,例如解析配置文本信息等等,这也是应用上下文实例对象最常见的应用场景。有了上下文对象,我们就能向容器注册需要 Spring 管理的对象了。对于上下文抽象接口,Spring 也为我们提供了多种类型的容器实现,供我们在不同的应用场景选择。


AnnotationConfigApplicationContext:从一个或多个基于 java 的配置类中加载上下文定义,适用于 java 注解的方式。

ClassPathXmlApplicationContext:从类路径下的一个或多个 xml 配置文件中加载上下文定义,适用于 xml 配置的方式。

FileSystemXmlApplicationContext:从文件系统下的一个或多个 xml 配置文件中加载上下文定义,也就是说系统盘符中加载 xml 配置文件。

AnnotationConfigWebApplicationContext:专门为 web 应用准备的,适用于注解方式。

XmlWebApplicationContext:从 web 应用下的一个或多个 xml 配置文件加载上下文定义,适用于 xml 配置方式。


工作中通过 XML 配置或注解?将需要管理的 Bean 跟 Bean 之间的协作关系配置好,然后利用应用上下文对象 Context 加载进 Spring 容器,容器就能为你的程序提供你想要的对象管理服务了。比如追踪下?ClassPathXmlApplicationContext?的底层源码:


可以看到一个 XML 文件的解析就可以上延 8 层,可见 Spring 容器为了实现 IOC 进行了全面性的考虑。

2.3 AOP

如果想编码实现计算器功能,我们的目标是实现加减乘除的运算,可是如何在每种运算前后进行打印日志跟数字合规的校验呢。


把日志记录和数据校验可重用的功能模块分离出来,然后在程序的执行的合适的地方动态地植入这些代码并执行。这样就简化了代码的书写。

业务逻辑代码中没有参和通用逻辑的代码,业务模块更简洁,只包含核心业务代码。实现了业务逻辑和通用逻辑的代码分离,便于维护和升级,降低了业务逻辑和通用逻辑的耦合性。



思路:代码最终是要加载到内存中实现 new 出对象,那么如果我们把可重用的功能提取出来,然后将这些通用功能在内存中通过入的方式实现构造出一个新的目标对象不就 OK 了么!


Spring AOP(Aspect Oriented?Programming) 恰恰提供从另一个角度来考虑程序结构以完善面向对象编程,如果说依赖注入的目的是让相互协作的组件保持一种较为松散的耦合状态的话,AOP 则是将遍布应用各处的功能分离出来形成可重用的组件。在编译期间、装载期间或运行期间实现在不修改源代码的情况下给程序动态添加功能的一种技术。从而实现对业务逻辑的隔离,提高代码的模块化能力。


AOP 的核心其实就是动态代理,如果是实现了接口的话就会使用 JDK 动态代理,否则使用 CGLIB 代理,主要应用于处理一些具有横切性质的系统级服务,如日志收集、事务管理、安全检查、缓存、对象池管理等。


Spring 主要提供了 Aspect 切面、JoinPoint 连接点、PointCut 切入点、Advice 增强等实现方式,AOP 一般有 5 种环绕方式:


前置通知 (@Before)

返回通知 (@AfterReturning)

异常通知 (@AfterThrowing)

后置通知 (@After)

环绕通知 (@Around) :(优先级最高)



PS?:多个切面的情况下,可以通过 @Order 指定先后顺序,数字越小,优先级越高。

3 ?JDK 动态代理和 CGLIB 代理区别

**JDK?**动态代理 与?CGLib 动态代理均是实现 Spring AOP 的基础,它们的实现方式有所不同。

3.1 JDK 动态代理

特点


Interface:对于 JDK 动态代理,业务类需要一个 Interface。

Proxy:Proxy 类是动态产生的,这个类在调用 Proxy.newProxyInstance() 方法之后,产生一个 Proxy 类的实例。实际上,这个 Proxy 类也是存在的,不仅仅是类的实例,这个 Proxy 类可以保存在硬盘上。

Method:对于业务委托类的每个方法,现在 Proxy 类里面都不用静态显示出来。

InvocationHandler:这个类在业务委托类执行时,会先调用 invoke 方法。invoke 方法在执行想要的代理操作,可以实现对业务方法的再包装。


总结:


JDK 动态代理类实现了 InvocationHandler 接口,重写的 invoke 方法。

JDK 动态代理的基础是反射机制(method.invoke(对象,参数))Proxy.newProxyInstance()

3.2 CGLib 动态代理

特点


使用字节码处理框架 ASM,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

CGLib 创建的动态代理对象性能比 JDK 创建的动态代理对象的性能高不少,但是 CGLib 在创建代理对象时所花费的时间却比 JDK 多得多,所以对于单例的对象,因为无需频繁创建对象,用 CGLib 合适,反之,使用 JDK 方式要更为合适一些。同时,由于 CGLib 由于是采用动态创建子类的方法,对于 final 方法,无法进行代理。


注意


JDK 的动态代理只可以为接口去完成操作,而 CGlib 它既可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理。

3.3 代码实现部分

公共代码?:


//接口类 public?interface?FoodService?{public?void?makeNoodle();public?void?makeChicken();}


//实现接口 public?class?FoodServiceImpl?implements?FoodService?{@Overridepublic?void?makeNoodle()?{System.out.println("make?noodle");}


@Overridepublic?void?makeChicken()?{System.out.println("make?Chicken");}}


jdk 动态代理代码


import?java.lang.reflect.InvocationHandler;import?java.lang.reflect.Method;import?java.lang.reflect.Proxy;


public?class?JDKProxyFactory?implements?InvocationHandler{private?Object?target;


public?JDKProxyFactory(Object?target){super();this.target?=?target;}


//?创建代理对象 public?Object?createProxy(){//?1.得到目标对象的类加载器 ClassLoader?classLoader?=?target.getClass().getClassLoader();//?2.得到目标对象的实现接口 Class<?>[]?interfaces?=?target.getClass().getInterfaces();//?3.第三个参数需要一个实现 invocationHandler 接口的对象 Object?newProxyInstance?=?Proxy.newProxyInstance(classLoader,?interfaces,?this);return?newProxyInstance;}


//?第一个参数:代理对象.一般不使用;第二个参数:需要增强的方法;第三个参数:方法中的参数 @Overridepublic?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable{System.out.println("这是增强方法前......");Object?invoke?=?method.invoke(target,?args);System.out.println("这是增强方法后......");return?invoke;}


public?static?void?main(String[]?args){//?1.创建对象 FoodServiceImpl?foodService?=?new?FoodServiceImpl();//?2.创建代理对象 JDKProxyFactory?proxy?=?new?JDKProxyFactory(foodService);//?3.调用代理对象的增强方法,得到增强后的对象 FoodService?createProxy?=?(FoodService)?proxy.createProxy();createProxy.makeChicken();}}


Cglib 动态代理代码


import?net.sf.cglib.proxy.Enhancer;import?net.sf.cglib.proxy.MethodInterceptor;import?net.sf.cglib.proxy.MethodProxy;import?java.lang.reflect.Method;


public?class?CglibProxyFactory?implements?MethodInterceptor{//得到目标对象 private?Object?target;//使用构造方法传递目标对象 public?CglibProxyFactory(Object?target)?{super();this.target?=?target;}//创建代理对象 public?Object?createProxy(){//1.创建 EnhancerEnhancer?enhancer?=?new?Enhancer();//2.传递目标对象的 classenhancer.setSuperclass(target.getClass());//3.设置回调操作 enhancer.setCallback(this);return?enhancer.create();}


//参数一:代理对象;参数二:需要增强的方法;参数三:需要增强方法的参数;参数四:需要增强的方法的代理 @Overridepublic?Object?intercept(Object?proxy,?Method?method,?Object[]?args,?MethodProxy?methodProxy)?throws?Throwable?{System.out.println("这是增强方法前......");Object?invoke?=?methodProxy.invoke(target,?args);System.out.println("这是增强方法后......");return?invoke;}


public?static?void?main(String[]?args)?{//?1.创建对象 FoodServiceImpl?foodService?=?new?FoodServiceImpl();//?2.创建代理对象 CglibProxyFactory?proxy?=?new?CglibProxyFactory(foodService);//?3.调用代理对象的增强方法,得到增强后的对象 FoodService?createProxy?=?(FoodService)?proxy.createProxy();createProxy.makeChicken();}}

4. Spring AOP 和 AspectJ AOP 区别

4.1 Spring AOP

Spring AOP 属于运行时增强,主要具有如下特点:


  1. 基于动态代理来实现,默认如果使用接口的,用 JDK 提供的动态代理实现,如果是方法则使用 CGLIB 实现

  2. Spring AOP 需要依赖 IOC 容器来管理,并且只能作用于 Spring 容器,使用纯 Java 代码实现

  3. 在性能上,由于 Spring AOP 是基于动态代理来实现的,在容器启动时需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 的那么好。

  4. Spring AOP 致力于解决企业级开发中最普遍的 AOP(方法织入)。

4.2 AspectJ

AspectJ 是一个易用的功能强大的 AOP 框架,属于编译时增强, ?可以单独使用,也可以整合到其它框架中,是 AOP 编程的完全解决方案。AspectJ 需要用到单独的编译器 ajc。


AspectJ 属于静态织入,通过修改代码来实现,在实际运行之前就完成了织入,所以说它生成的类是没有额外运行时开销的,一般有如下几个织入的时机:


  1. 编译期织入(Compile-time weaving):如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。

  2. 编译后织入(Post-compile weaving):也就是已经生成了 .class 文件,或已经<typo id="typo-8742" data-origin="打成" ignoretag="true">打成</typo> jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。

  3. 类加载后织入(Load-time weaving):指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法

4.3 对比

5. ?BeanFactory 和 FactoryBean

5.1 BeanFactory

  1. BeanFactory?以 Factory 结尾,表示它是一个工厂类(接口),BeanFacotry 是 Spring 中比较原始的 Factory。

  2. BeanFactory?无法支持 Spring 的许多插件,如 AOP 功能、Web 应用等。ApplicationContext?接口由 BeanFactory 接口派生而来,提供了国际化访问、事件传播等多个功能。

  3. BeanFactory?是 IOC 容器的核心,负责生产和管理 Bean 对象。

5.2 FactoryBean

  1. FactoryBean?以 Bean 结尾,表示它是一个 Bean。

  2. **FactoryBe


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


an**?是工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。FactoryBean 接口对于 Spring 框架来说占用重要的地位,Spring 自身就提供了 70 多个 FactoryBean 的实现。3. 当在 IOC 容器中的 Bean 实现了 FactoryBean 后,通过 getBean(String BeanName)获取到的 Bean 对象并不是 FactoryBean 的实现类对象,而是这个实现类中的 getObject() 方法返回的对象。要想获取 FactoryBean 的实现类,就要 getBean(String &BeanName),在 BeanName 之前加上?&

6. Spring 生命周期

Spring IOC 初始化跟销毁 Bean 的过程大致分为 Bean 定义、Bean 初始化、Bean 的生存期 跟 Bean 的销毁 4 个部分。



如果仅仅是实例化跟依赖注入当然简单,问题是如果我们要完成自定义的要求,Spring 提供了一系列接口跟配置来完成 Bean 的初始化过程,看下整个 IOC 容器初始化 Bean 的流程。


一般情况下我们自定义 Bean 的初始化跟销毁方法下面三种:


  1. 通过 XML 或者 @Bean 配置


通过 xml 或者 @Bean(initMethod="init", destroyMethod="destory")来实现。


  1. 使用 JSR250 规则定义的(java 规范)两个注解来实现


@PostConstruct: 在 Bean 创建完成,且属于赋值完成后进行初始化,属于 JDK 规范的注解。

@PreDestroy: 在 bean 将被移除之前进行通知,在容器销毁之前进行清理工作。

提示:JSR 是由 JDK 提供的一组规范。


  1. 通过继承实现类方法


实现 InitializingBean 接口的 afterPropertiesSet()方法,当 beanFactory 创建好对象,且把 bean 所有属性设置好之后会调这个方法,相当于初始化方法。

实现 DisposableBean 的 destory()方法,当 bean 销毁时会把单实例 bean 进行销毁

对于单实例的 bean,可以正常调用初始化和销毁方法。对于多实例的 bean,容器只负责调用时候初始化,但不会管理 bean, 容器关闭时不会调用销毁方法。


7. Spring 中的设计模式

Spring 框架中广泛使用了不同类型的设计模式,下面我们来看看到底有哪些设计模式?


  1. 工厂设计模式?: Spring 使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。

  2. 代理设计模式?: Spring AOP 功能的实现。

  3. 单例设计模式?: Spring 中的 Bean 默认都是单例的。

  4. 模板方法模式?: Spring 中 jdbcTemplate、hibernateTemplate 等以?Template?结尾的对数据库操作的类,它们就使用到了模板模式。

  5. 包装器设计模式?: 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。

  6. 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。

  7. 适配器模式?:Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配 Controller。

8. Spring 循环依赖

8.1 简说循环依赖


Spring 循环依赖:说白了就是一个或多个对象实例之间存在直接或间接的依赖关系,这种依赖关系构成了构成一个环形调用。发生循环依赖的两个前提条件是:


出现循环依赖的 Bean 必须要是单例(singleton),如果依赖 prototype 则完全不会有此需求。

依赖注入的方式不能全是构造器注入的方式,只能解决 setter 方法的循环依赖,这是错误的。


假设 AB 之间相互依赖,通过尝试不同的注入方式注入后可的如下结论:



PS:第四种可以而第五种不可以的原因是 Spring 在创建 Bean 时默认会根据自然排序进行创建,所以 A 会先于 B 进行创建。

8.2 循环依赖通俗说

Spring 通过三级缓存解决了循环依赖。


  1. 一级缓存 : Map<String,Object>?singletonObjects,单例池,用于保存实例化、注入、初始化完成的 bean 实例

  2. 二级缓存 : Map<String,Object>?earlySingletonObjects,早期曝光对象,用于保存实例化完成的 bean 实例

  3. 三级缓存 : Map<String,ObjectFactory<?>>?singletonFactories,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。


当 A、B 两个类发生循环引用时,在 A 完成实例化后,就使用实例化后的对象去创建一个对象工厂,并添加到三级缓存中,如果 A 被 AOP 代理,那么通过这个工厂获取到的就是 A 代理后的对象,如果 A 没有被 AOP 代理,那么这个工厂获取到的就是 A 实例化的对象。当 A 进行属性注入时,会去创建 B,同时 B 又依赖了 A,所以创建 B 的同时又会去调用 getBean(a)来获取需要的依赖,此时的 getBean(a)会从缓存中获取:


第一步,先获取到三级缓存中的工厂。

第二步,调用对象工工厂的 getObject 方法来获取到对应的对象,得到这个对象后将其注入到 B 中。紧接着 B 会走完它的生命周期流程,包括初始化、后置处理器等。


当 B 创建完后,会将 B 再注入到 A 中,此时 A 再完成它的整个生命周期。至此循环依赖结束!

8.2 三级缓存意义何在?


先跟踪下源码(如上图),跟踪过程中注意区别下有 AOP 的依赖没有 AOP 的依赖两种情况,跟踪后你会发现三级缓存的功能是只有真正发生循环依赖的时候,才去提前生成代理对象,否则只会创建一个工厂并将其放入到三级缓存中,但是不会去通过这个工厂去真正创建对象。至于提速这一说法,还是拉闸吧。



如上图所示,如果使用二级缓存解决循环依赖,意味着所有 Bean 在实例化后就要完成 AOP 代理,这样违背了 Spring 设计的原则,Spring 在设计之初就是通过 AnnotationAwareAspectJAutoProxyCreator 这个后置处理器来在 Bean 生命周期的最后一步来完成 AOP 代理,而不是在实例化后就立马进行 AOP 代理。

9. Spring 事务

Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring 是无法提供事务功能的。Spring 只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过 binlog 或者 undolog 实现的,具体流程在 MySQL 中讲过了。Spring 会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别,由此保持一致。

9.1 ?Spring 事务的种类

Spring 支持编程式事务管理和声明式事务管理两种方式:


  1. 编程式事务


编程式事务管理使用 TransactionTemplate。


  1. 声明式事务


声明式事务管理建立在 AOP 之上的。其本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前启动一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

优点是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过 @Transactional 注解的方式,便可以将事务规则应用到业务逻辑中,减少业务代码的污染。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

9.2 Spring 的事务传播机制

spring 事务的传播机制说的是,当多个事务同时存在的时候,spring 如何处理这些事务的行为。事务传播机制实际上是使用简单的 ThreadLocal 实现的,所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的。


  1. propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择,也是默认模式,它适合于绝大多数情况。

  2. propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。

  3. propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。

  4. propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。

  5. propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

  6. propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。

  7. propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 propagation_required 类似的操作

9.2 Spring 的事务隔离级别

TransactionDefinition 接口中定义了五个表示隔离级别的常量,这里其实关键还是要看 MySQL 的隔离级别:


  1. ISOLATION_DEFAULT:使用后端数据库默认的隔离界别,MySQL 默认可重复读,Oracle 默认读已提交。

  2. ISOLATION_READ_UNCOMMITTED:读未提交。

  3. ISOLATION_READ_COMMITTED:读已提交。

  4. ISOLATION_REPEATABLE_READ:可重复读。

  5. ISOLATION_SERIALIZABLE:串行化。

10. Spring MVC

10.1 什么是 MVC ?


MVC 模式中 M 是指业务模型,V 是指用户界面,C 则是控制器,使用 MVC 的目的是将 M 和 V 的实现代码分离,开发中一般将应用程序分为 Controller、Model、View 三层,Controller 接收客户端请求,调用 Model 生成业务数据,传递给 View,View 最终展示前端结果。


Spring MVC 就是对上述这套流程的封装,屏蔽了很多底层代码,开放出接口,让开发者可以更加轻松、便捷地完成基于 MVC 模式的 Web 开发。

10.2 Spring 跟 Spring MVC 关系

最开始只有 Spring,只提供 IOC 跟 AOP 核心功能,后来出了乱七八糟的比如 MVC、Security、Boot 等。原来的 Spring 就变成了现在的 Spring Core,MVC 指的是 Web 的 MVC 框架。


Spring MVC?就是一个 MVC 框架,其实大范围上来说属于 Spring,Spring MVC 是一个类似于 Struts 的 MVC 模式的 WEB 开发框架,Spring MVC 是基于 Spring 功能之上添加的 Web 框架,Spring 跟 SpringMVC 可以理解为父子容器的关系,想用 Spring MVC 必须先依赖 Spring。

Spring MVC?是控制层,用来接收前台传值,调用 service 层和持久层,返回数据再通过 Spring MVC 把数据返回前台

10.3 Spring MVC 的核心组件

DispatcherServlet:前置控制器,是整个流程控制的核心,控制其他组件的执行,进行统一调度,降低组件之间的耦合性,相当于总指挥。

Handler:处理器,完成具体的业务逻辑,相当于 Servlet 或 Action。

HandlerMapping:DispatcherServlet 接收到请求之后,通过 HandlerMapping 将不同的请求映射到不同的 Handler。

HandlerInterceptor:处理器拦截器,是一个接口,如果需要完成一些拦截处理,可以实现该接口。

HandlerExecutionChain:处理器执行链,包括两部分内容:Handler 和 HandlerInterceptor(系统会有一个默认的 HandlerInterceptor,如果需要额外设置拦截,可以添加拦截器)。

HandlerAdapter:处理器适配器,Handler 执行业务方法之前,需要进行一系列的操作,包括表单数据的验证、数据类型的转换、将表单数据封装到 JavaBean 等,这些操作都是由 HandlerApater 来完成,开发者只需将注意力集中业务逻辑的处理上,DispatcherServlet 通过 HandlerAdapter 执行不同的 Handler。

ModelAndView:装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。

ViewResolver:视图解析器,DispatcheServlet 通过它将逻辑视图解析为物理视图,最终将渲染结果响应给客户端。

10.4 Spring MVC 的工作流程


DispatcherServlet 表示前置控制器,是整个 SpringMVC 的控制中心。用户发出请求,接收请求并拦截请求。

HandlerMapping 为处理器映射。DispatcherServlet 调用 HandlerMapping,HandlerMapping 根据请求 url 查找 Handler。

HandlerExecution 表示具体的 Handler,其主要作用是根据 url 查找控制器,如上 url 被查找控制器为:hello。

HandlerExecution 将解析后的信息传递给 DispatcherServlet,如解析控制器映射等。

HandlerAdapter 表示处理器适配器,其按照特定的规则去执行 Handler。

Handler 让具体的 Controller 执行。

Controller 将具体的执行信息返回给 HandlerAdapter,如 ModelAndView。

HandlerAdapte r 将视图逻辑名或模型传递给 DispatcherServlet。

DispatcherServlet 调用视图解析器(ViewResolver)来解析 HandlerAdapter 传递的逻辑视图名。

视图解析器将解析的逻辑视图名传给 DispatcherServlet。

DispatcherServlet 根据视图解析器解析的视图结果,调用具体的视图。

最终视图呈现给用户。


Spring MVC?虽然整体流程复杂,但是实际开发中很简单,大部分的组件不需要开发者创建跟管理,只需要通过配置文件的方式完成配置即可,真正需要开发者进行处理的只有?Handler?、View?、Modle


但是随着前后端分离跟微服务的发展,一包走天下的开发模式其实用的不是很多了,大部分情况下是?SpringBoot?+?Vue

11. Spring Boot

11.1 Spring Boot 简介

Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。它并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。Spring Boot 以约定大于配置核心思想开展工作,相比 Spring 具有如下优势:

评论

发布
暂无评论
阿里面试官:就说最后一遍,有关Spring这13点我们必问!