6. Spring框架

在这里插入图片描述

重点面试题


说一下你对Spring框架的理解?

Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。

Spring具有以下特点:

  • 轻量:Spring 是轻量的,基本的版本大约2MB。
  • 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
  • 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
  • 容器:Spring 包含并管理应用中对象的生命周期和配置。MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
  • 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
  • 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。

Spring框架都包含哪些模块?

  • spring core: 提供了框架的基本组成部分,包括控制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)功能。
  • sprng beans: 提供了BeanFactory,是工厂模式的一个经典实现,Spring将管理对象称为Bean。
  • spring context: 构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
  • spring jdbc: 提供了一个JDBC的抽象层,消除了烦琐的JDBC编码和数据库厂商特有的错误代码解析, 用于简化JDBC。
  • spring aop: 提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
  • spring Web: 提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
  • spring test: 主要为测试提供支持的,支持使用JUnit或TestNG对Spring组件进行单元测试和集成测试。

Spring框架中都用到了哪些设计模式?

  • 工厂模式: BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
  • 单例模式: Bean默认为单例模式。
  • 代理模式: Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
  • 模板方法: 用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
  • 观察者模式: 定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。
  • 适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
  • 装饰器模式: Spring 中配置 DataSource 的时候,DataSource 可能是不同的数据库和数据源,项目需要连接多个数据库,这种模式让我们可以根据客户需求切换不同的数据源。
  • 策略模式: Spring中资源访问接口Resource的设计是一种典型的策略模式。Resource接口是所有资源访问类所实现的接口,客户端程序只和 Resource 接口耦合,并不知道底层采用何种资源访问策略,这样客户端程序可以在不同的资源访问策略之间自由切换

什么是SpringIOC容器?

控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。

Spring IOC 负责创建对象,管理对象(通过依赖注–DI),装配对象,配置对象,并且管理这些对象的整个生命周期。

BeanFactory 和 ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

依赖关系
BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。

ApplicationContext 接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

  • 继承MessageSource,因此支持国际化。 统一的资源文件访问方式。 提供在监听器中注册bean的事件。 同时加载多个配置文件。 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。 加载方式
  • BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
  • ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
  • 相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

创建方式
BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

注册方式
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

什么是Spring的依赖注入?

控制反转IoC是一个很大的概念,可以用不同的方式来实现。其主要实现方式有两种:依赖注入和依赖查找

依赖注入:相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。

所谓依赖注入(Dependency Injection),即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。

依赖注入的基本原则是:应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由IoC容器负责,“查找资源”的逻辑应该从应用组件的代码中抽取出来,交给IoC容器负责。容器全权负责组件的装配,它会把符合依赖关系的对象通过属性(JavaBean中的setter)或者是构造器传递给需要的对象。

有哪些注入方式?

依赖注入分为setter方法注入(Setter Injection)和构造器注入(Constructor Injection)。

构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。

Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。

SpringBean的作用域有哪些?

在spring框架中定义bean时,可以使用scope属性设置作用域,支持以下5种作用域:
singleton: bean在每个Spring ioc 容器中只有一个实例。
prototype: 一个bean的定义可以有多个实例。
request: 每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
session: 在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
global-session: 在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

注意: 缺省的Spring bean 的作用域是Singleton。使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。

Spring框架中单例bean是线程安全的么?

不是,Spring框架中的单例bean不是线程安全的。

spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。

实际上大部分时候 spring bean 是无状态的(比如 dao 类),所以某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。

有状态就是有数据存储功能。 无状态就是不会保存数据。

在一般情况下,只有无状态的Bean才可以在多线程环境下共享,但在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

@Autowired,@Resource和@Qualifier的作用

@Autowired可用于:构造函数、成员变量、Setter方法

@Autowired和@Resource之间的区别

  • @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
  • @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。

@Qualifier,当创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,可以使用@Qualifier 注解和 @Autowired 注解指定应该装配哪个确切的 bean 来消除歧义

使用@Autowired注解自动装配的过程是怎样的?

首先需要在xml配置文件中开启注解配置

在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据; 如果查询的结果不止一个,那么@Autowired会根据名称来查找; 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

简述Spring bean的生命周期?

spring bean 容器的生命周期流程如下:

  1. Spring 容器根据配置中的 bean 定义中实例化 bean。
  2. Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
  3. 如果 bean 实现 BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用 setBeanName()。
  4. 如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
  5. 如果存在与 bean 关联的任何 BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法。
  6. 如果为 bean 指定了 init 方法( <bean> 的 init-method 属性),那么将调用它。
  7. 最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。
  8. 如果 bean 实现 DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
  9. 如果为 bean 指定了 destroy 方法( <bean> 的 destroy-method 属性),那么将调用它。

Spring如何解决循环依赖问题?

  1. 首先 A 完成初始化第一步并将自己提前曝光出来(通过 ObjectFactory 将自己提前曝光),在初始化的时候,发现自己依赖对象 B,此时就会去尝试 get(B),这个时候发现 B 还没有被创建出来;
  2. 然后 B 就走创建流程,在 B 初始化的时候,同样发现自己依赖 C,C 也没有被创建出来;
  3. 这个时候 C 又开始初始化进程,但是在初始化的过程中发现自己依赖 A,于是尝试 get(A)。这个时候由于 A 已经添加至缓存中(一般都是添加至三级缓存 singletonFactories),通过ObjectFactory 提前曝光,所以可以通过 ObjectFactory#getObject() 方法来拿到 A 对象。C 拿到 A 对象后顺利完成初始化,然后将自己添加到一级缓存中;
  4. 回到 B,B 也可以拿到 C 对象,完成初始化,A 可以顺利拿到 B 完成初始化。到这里整个链路就已经完成了初始化过程了。
    关键字:三级缓存,提前曝光。

什么是AOP?

OOP(Object-Oriented Programming)面向对象编程,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。

AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。

Spring AOP and AspectJ AOP 有什么区别?

AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

  1. AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
  2. Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

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

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。 如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。

CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

SpringAOP都有哪些类型的通知?

  • before:前置通知,在一个方法执行前被调用。
  • after: 在方法执行之后调用的通知,无论方法执行是否成功。
  • after-returning: 仅当方法成功完成后执行的通知。
  • after-throwing: 在方法抛出异常退出时执行的通知。
  • around: 在方法执行之前和之后调用的通知。

Spring支持事务类型?

Spring支持两种类型的事务管理:
编程式事务管理: 这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
声明式事务管理: 这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。

说一下Spring的事务传播行为都有哪些?

spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。

  1. PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
  2. PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
  3. PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
  4. PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
  5. PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  6. PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  7. PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。

SpringMVC常用注解有哪些?

@RequestMapping 用于映射请求路径,可以定义在类上和方法上。用于类上,则表示类中的所有方法都是以该地址作为父路径
@RequestBody 注解实现接收http请求的json数据,将Json转化为Java对象
@RequestParam 指定请求参数的名称
@PathViriable 从请求路径中获取请求参数:(/user/{id}),传递给方法的形参
@ResponseBody 将Controller内的方法的返回对象转化为Json格式传递给前端
@RequestHeader 获取指定的请求头数据
@RestController @Controller + ResponseBody

Spring MVC的主要组件?

  1. 前端控制器 DispatcherServlet(不需要程序员开发) 作用: 接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
  2. 处理器映射器HandlerMapping(不需要程序员开发)作用: 根据请求的URL来查找Handler
  3. 处理器适配器HandlerAdapter 注意: 在编写Handler的时候要按照HandlerAdapter要求的规则去编写,这样适配器HandlerAdapter才可以正确的去执行Handler。
  4. 处理器Handler(需要程序员开发)
  5. 视图解析器 ViewResolver(不需要程序员开发) 作用: 进行视图的解析,根据视图逻辑名解析成真正的视图(view)
  6. 视图View(需要程序员开发jsp)View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)

请描述Spring MVC的工作流程?

  1. 用户发送请求至前端控制器DispatcherServlet;
  2. DispatcherServlet前端控制器收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给前端控制器DispatcherServlet;
  4. DispatcherServlet 前端控制器调用 HandlerAdapter处理器适配器;
  5. HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
  6. Handler处理器执行完成返回ModelAndView;
  7. HandlerAdapter处理器适配器将Handler处理器执行结果ModelAndView返回给前端控制器DispatcherServlet;
  8. DispatcherServlet前端控制器将ModelAndView传给ViewResolver视图解析器进行解析;
  9. ViewResolver解析后返回具体View;
  10. DispatcherServlet前端控制器对View进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet前端控制器响应用户。

SpringMVC是怎么处理异常的?

SpringMVC通过HandlerExceptionResolver接口处理程序的异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常。Controller调用Service,Service调用Dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理

Springmvc 中拦截器如何使用?

定义拦截器 实现HandlerInterceptor接口。接口中提供三个方法。

  • preHandle :进入 Handler方法之前执行,用于身份认证、身份授权,比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
  • postHandle:进入Handler方法之后,返回modelAndView之前执行,应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
  • afterCompletion:执行Handler完成执行此方法,应用场景:统一异常处理,统一日志处理

拦截器配置:
类似全局的拦截器: springmvc框架将配置全局的拦截器注入到每个HandlerMapping中


Spring

Spring框架中的单例bean是线程安全的吗?

不是线程安全的,是这样的

当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这是多个线程会并发执行该请求对应的业务逻辑(成员方法),如果该处理逻辑中有对该单列状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。

Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。

比如:我们通常在项目中使用的Spring bean都是不可可变的状态(比如Service类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。

如果你的bean有多种状态的话(比如 View Model对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用由“singleton”变更为“prototype”。

什么是AOP

aop是面向切面编程,在spring中用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低耦合,一般比如可以做为公共日志保存,事务处理等

你们项目中有没有使用到AOP

我们当时在后台管理系统中,就是使用aop来记录了系统的操作日志

主要思路是这样的,使用aop中的环绕通知+切点表达式,这个表达式就是要找到要记录日志的方法,然后通过环绕通知的参数获取请求方法的参数,比如类信息、方法信息、注解、请求方式等,获取到这些参数以后,保存到数据库

Spring中的事务是如何实现的

spring实现的事务本质就是aop完成,对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

Spring中事务失效的场景有哪些

  1. 第一个,如果方法上异常捕获处理,自己处理了异常,没有抛出,就会导致事务失效,所以一般处理了异常以后,别忘了跑出去就行了
  2. 第二个,如果方法抛出检查异常,如果报错也会导致事务失效,最后在spring事务的注解上,就是@Transactional上配置rollbackFor属性为Exception,这样别管是什么异常,都会回滚事务
  3. 第三,我之前还遇到过一个,如果方法上不是public修饰的,也会导致事务失效

Spring的bean的生命周期

在这里插入图片描述

  1. 第一步是调用构造函数实例化bean
  2. 第二步是bean的依赖注入,比如一些set方法注入,像平时开发用的@Autowire都是这一步完成
  3. 第三步是处理Aware接口,如果某一个bean实现了Aware接口就会重写方法执行
  4. 第四步是bean的后置处理器BeanPostProcessor,这个是前置处理器
  5. 第五步是初始化方法,比如实现了接口InitializingBean或者自定义了方法init-method标签或@PostContruct
  6. 第六步是执行了bean的后置处理器BeanPostProcessor,主要是对bean进行增强,有可能在这里产生代理对象

Spring中的循环引用

循环依赖:循环依赖其实就是循环引用,也就是两个或两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于A

循环依赖在spring中是允许存在,spring框架依据三级缓存已经解决了大部分的循环依赖

  1. 一级缓存:单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象
  2. 二级缓存:缓存早期的bean对象(生命周期还没走完)
  3. 三级缓存:缓存的是ObjectFactory,表示对象工厂,用来创建某个对象的

那具体解决流程清楚吗?

在这里插入图片描述

  1. 第一,先实例A对象,同时会创建ObjectFactory对象存入三级缓存singletonFactories
  2. 第二,A在初始化的时候需要B对象,这个走B的创建的逻辑
  3. 第三,B实例化完成,也会创建ObjectFactory对象存入三级缓存singletonFactories
  4. 第四,B需要注入A,通过三级缓存中获取ObjectFactory来生成一个A的对象同时存入二级缓存,这个是有两种情况,一个是可能是A的普通对象,另外一个是A的代理对象,都可以让ObjectFactory来生产对应的对象,这也是三级缓存的关键
  5. 第五,B通过从通过二级缓存earlySingletonObjects 获得到A的对象后可以正常注入,B创建成功,存入一级缓存singletonObjects
  6. 第六,回到A对象初始化,因为B对象已经创建完成,则可以直接注入B,A创建成功存入一次缓存singletonObjects
  7. 第七,二级缓存中的临时对象A清除

构造方法出现了循环依赖怎么解决?

由于bean的生命周期中构造函数是第一个执行的,spring框架并不能解决构造函数的的依赖注入,可以使用@Lazy懒加载,什么时候需要对象再进行bean对象的创建

SpringMVC

SpringMVC的执行流程知道嘛

在这里插入图片描述
1、用户发送出请求到前端控制器DispatcherServlet,这是一个调度中心
2、DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。
3、HandlerMapping找到具体的处理器(可查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
4、DispatcherServlet调用HandlerAdapter(处理器适配器)。
5、HandlerAdapter经过适配调用具体的处理器(Handler/Controller)。
6、Controller执行完成返回ModelAndView对象。
7、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
8、DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。
9、ViewReslover解析后返回具体View(视图)。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、DispatcherServlet响应用户。

当然现在的开发,基本都是前后端分离的开发的,并没有视图这些,一般都是handler中使用Response直接结果返回在这里插入图片描述

SpringBoot

Springboot自动配置原理

在Spring Boot项目中的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装,分别是:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan
    其中@EnableAutoConfiguration是实现自动化配置的核心注解。

该注解通过@Import注解导入对应的配置选择器。关键的是内部就是读取了该项目和该项目引用的Jar包的的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。

在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。

一般条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的class文件,如果有则加载该类,把这个配置类的所有的Bean放入spring容器中使用。

Spring 的常见注解有哪些?

第一类是:声明bean,有@Component、@Service、@Repository、@Controller

第二类是:依赖注入相关的,有@Autowired、@Qualifier、@Resourse

第三类是:设置作用域 @Scope

第四类是:spring配置相关的,比如@Configuration,@ComponentScan 和 @Bean

第五类是:跟aop相关做增强的注解 @Aspect,@Before,@After,@Around,@Pointcut

SpringMVC常见的注解有哪些?

有@RequestMapping:用于映射请求路径;
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象;
@RequestParam:指定请求参数的名称;
@PathViriable:从请求路径下中获取请求参数(/user/{id}),传递给方法的形式参数;@ResponseBody:注解实现将controller方法返回对象转化为json对象响应给客户端。@RequestHeader:获取指定的请求头数据,还有像@PostMapping、@GetMapping这些。

Springboot常见注解有哪些?

Spring Boot的核心注解是@SpringBootApplication , 他由几个注解组成 :

  • @SpringBootConfiguration: 组合了- @Configuration注解,实现配置文件的功能;
  • @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项
  • @ComponentScan:Spring组件扫描

为什么要用SpringBoot?

Spring Boot 优点非常多,如:

  1. 独立运行:Spring Boot而且内嵌了各种servlet容器,Tomcat、Jetty等,现在不再需要打成war包部署到容器中,Spring Boot只要打成一个可执行的jar包就能独立运行,所有的依赖包都在一个jar包内。
  2. 简化配置:spring-boot-starter-web启动器自动依赖其他组件,简少了maven的配置。
  3. 自动配置:Spring Boot能根据当前类路径下的类、jar包来自动配置bean,如添加一个spring-boot-starterweb启动器就能拥有web的功能,无需其他配置。
  4. 无代码生成和XML配置:Spring Boot配置过程中无代码生成,也无需XML配置文件就能完成所有配置工作,这一切都是借助于条件注解完成的,这也是Spring4.x的核心功能之一。
  5. 应用监控:Spring Boot提供一系列端点可以监控服务及应用,做健康检测。

运行Spring Boot有哪几种方式?

  1. 打包用命令或者放到容器中运行
  2. 用Maven/Gradle 插件运行
  3. 直接执行 main 方法运行

如何理解 SpringBoot 的 Starters

什么是Starters?
Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成Spring及其他技术,而不需要到处找示例代码和依赖包。如你想使用Spring JPA访问数据库,只要加入spring-boot-starter-data-jpa启动器依赖就能使用了。Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。

Starters命名
Spring Boot官方的启动器都是以spring-boot-starter-命名的,代表了一个特定的应用类型。第三方的启动器不能以spring-boot开头命名,它们都被Spring Boot官方保留。一般一个第三方的应该这样命名,像mybatis的mybatis-spring-boot-starter。

常用的Starters:
spring-boot-starter-web 嵌入tomcat和web开发需要servlet与jsp支持
spring-boot-starter-data-jpa 数据库支持
spring-boot-starter-data-redis redis数据库支持
spring-boot-starter-actuator actuator监控支持
mybatis-spring-boot-starter 第三方的mybatis集成starter

SpringBoot中的监视器是什么?

Spring boot actuator是spring启动框架中的重要功能之一。Spring boot监视器可帮助您访问生产环境中正在运行的应用程序的当前状态。有几个指标必须在生产环境中进行检查和监控。即使一些外部应用程序可能正在使用这些服务来向相关人员触发警报消息。监视器模块公开了一组可直接作为HTTP URL访问的REST端点来检查状态。可以通过配置开放端点或者隐藏端点。

如何使用Spring Boot实现异常处理?

Spring提供了一种使用ControllerAdvice处理异常的非常有用的方法。 我们通过实现一个
ControlerAdvice类,来处理控制器类抛出的所有异常。

SpringBoot 如何实现热部署?

  1. 模板热部署
    在SpringBoot中,模板引擎的页面默认是开启缓存的,如果修改了页面的内容,则刷新页面是得不到修改后的页面的,因此我们可以在application.properties中关闭模版引擎的缓存,如下:
    Thymeleaf的配置:spring.thymeleaf.cache=false
    FreeMarker的配置:spring.freemarker.cache=false

  2. 使用调试模式Debug实现热部署
    此种方式为最简单最快速的一种热部署方式,运行系统时使用Debug模式,无需装任何插件即可,但是无法对配置文件,方法名称改变,增加类及方法进行热部署,使用范围有限。

  3. spring-boot-devtools
    在Spring Boot 项目中添加 spring-boot-devtools依赖即可实现页面和代码的热部署。
    此种方式的特点是作用范围广,系统的任何变动包括配置文件修改、方法名称变化都能覆盖,但是后遗症也非常明显,它是采用文件变化后重启的策略来实现了,主要是节省了我们手动点击重启的时间,提高了实效性,在体验上回稍差。
    spring-boot-devtools 默认关闭了模版缓存,如果使用这种方式不用单独配置关闭模版缓存。

  4. Spring Loaded
    此种方式与Debug模式类似,适用范围有限,但是不依赖于Debug模式启动,通过Spring Loaded库文件启动,即可在正常模式下进行实时热部署。此种需要在 run confrgration 中进行配置。

  5. JRebel
    Jrebel是Java开发最好的热部署工具,对Spring Boot 提供了极佳的支持,JRebel为收费软件,试用期14天。可直接通过插件安装。

Spring Boot自助配置原理是什么?

Spring Boot的自动配置原理是基于条件化配置(Conditional Configuration)的概念。自动配置使得在应用程序启动时,Spring Boot可以根据项目的依赖和类路径上的内容,自动配置各种功能和组件,而无需开发者显式地进行大量的配置。

  1. @SpringBootApplication 或 @EnableAutoConfiguration: 在Spring Boot的主类的 main 方法中使用 @SpringBootApplication 或者 @EnableAutoConfiguration 注解,是启动Spring Boot应用程序的入口。这两个注解会触发Spring Boot自动配置的机制。
  2. spring.factories 文件: 在项目的依赖中,每个Spring Boot Starter都包含一个 META-INF/spring.factories 文件。这个文件中列出了各个Starter所提供的自动配置类。当Spring Boot应用启动时,它会扫描这些Starter,加载并应用自动配置类。
  3. 自动配置类的加载: Spring Boot会在启动时扫描项目的依赖中的spring.factories文件,找到各个Starter的自动配置类,并加载这些类。
  4. @Conditional 注解的条件判断: 自动配置类通常会使用 @Conditional 注解来定义一些条件,例如 @ConditionalOnClass、@ConditionalOnMissingBean 等。这些条件会在Spring Boot启动时进行评估,根据条件判断结果来决定是否应用某个自动配置。
  5. 自动配置与Bean注入: 符合条件的自动配置类会在Spring容器中创建和注册一些Bean。这些Bean通常是应用程序所需的基础设施,如数据源、消息队列、缓存等。这些Bean会根据自动配置的条件和配置信息被注入到Spring的应用上下文中。

Spring Boot读取配置的方式有哪些?

  1. 使用 @Value 注解: 通过在类的字段或方法参数上使用 @Value 注解,可以将配置值直接注入到对应的属性中。例如:
@Value("${myapp.database.url}")
private String databaseUrl;
  1. 使用 @ConfigurationProperties 注解:@ConfigurationProperties 注解可以用于将一组相关的配置属性映射到一个Java对象中。首先,创建一个用于保存属性值的POJO类,然后在类上使用 @ConfigurationProperties 注解,并指定属性的前缀。接下来,可以通过注入这个POJO类来获取属性值。例如:
@ConfigurationProperties(prefix = "myapp.database")
public class DatabaseProperties {   
	private String url;   
// ...
}
  1. 通过 Environment 获取属性: 通过在类中注入 Environment 对象,可以使用它来获取配置属性。例如:
@Autowiredprivate Environment environment;
public void someMethod() {
	String url = environment.getProperty("myapp.database.url");
}
  1. 使用 @PropertySource 注解:@PropertySource 注解用于指定外部配置文件的位置,然后可以使用 Environment 或 @Value 注解来读取这些属性值。例如:
@Configuration@PropertySource("classpath:custom.properties")
public class CustomConfig {   
// ...
}

Spring Boot 的核心配置文件有哪几个?

  1. 配置文件种类
  • SpringBoot项目默认的配置文件有两种:bootstrap、application
  • 支持的文件类型有两种:properties和yml。
  • 所以默认的配置文件有四个:bootstrap.properties,application.properties、bootstrap.yml,application.yml,常用的是application.properties。
  • 默认位于src/main/resources/下。
  1. 默认配置文件优先级
    上面的4个配置文件,通常情况下只选择一个即可,如果配置了多个,其加载的顺序为:
    bootstrap.properties -> bootstrap.yml -> application.properties -> application.yml从高到低。

  2. bootstrap常见应用场景:

  • 配置一些固定的,不能被覆盖的属性,用于一些系统级别的参数配置。本地的配置文件是默认不能覆盖远程的配置的
  • 一些需要加密/解密的场景
  • 当你使用了Spring Cloud Config配置中心时,这时需要在boostrap配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息。
  1. application常见应用场景:
  • 常用于SpringBoot项目的自动化配置
  • 用于一些应用级别的参数配置

Spring Boot 如何定义多套不同环境配置?

Spring Boot支持多套不同环境配置,使得在不同的环境(如开发、测试、生产)中使用不同的配置属性。

  1. 创建不同环境的配置文件,命名为 application-{环境名}.properties,
  2. 在application.properties文件中的配置spring.profiles.active 属性来指定要使用的环境。

例如:

  • 创建 application-dev.properties 和 application-prod.properties 文件
  • 在 application.properties 中设置 spring.profiles.active=dev 或 spring.profiles.active=prod

简述SpringBoot的启动流程

  1. 运行 SpringApplication.run() 方法
  2. 源码中确定应用程序类型。默认是Servlet容器。 也可以是reactive响应式容器
  3. 加载所有初始化类,从 META-INF/spring.factories 配置文件中加载的。初始化类实现了ApplicationContextInitializer接口。也可以自定义
  4. 加载所有监视器类,从 META-INF/spring.factories 配置文件中加载的。初始化类实现了ApplicationListener接口。也可以自定义
  5. 开启计时器,此刻才认为开始启动springboot程序, 之前都是准备工作,记录开始时间,用来计算启动过程的用时。
  6. 获取并启用监听器,使得监听器开始生效,工作。
  7. 设置应用程序参数,将执行run方法时传递的参数封装成对象。
  8. 准备环境变量,包含系统属性和JVM运行属性,封装在Environment对象中
  9. 打印banner信息,可以在resources目录下创建banner.txt来自定义banner内容
  10. 创建应用程序上下文对象,也就是ApplicationContext对象。
  11. 实例化异常报告器,只捕获启动过程抛出的全局异常,在META-INF/spring.factories中配置了默认异常报告器
  12. 准备上下文环境,实例化单例的beanName生成器,执行初始化器,将启动参数注册到容器中
  13. 刷新上下文,完成自动装备及一些启动工作。 如tomcat启动等
  14. 执行后置处理,刷新上下文后的一些处理工作,用户可以扩展,重写afterRefresh方法
  15. 结束解释器,springboot程序启动完成, 打印用时的时间。

说一说Spring Boot REST 请求风格?

  1. HTTP 协议是一个广泛应用的 Internet 协议,不同的请求方法,常见的有GET , POST , PUT , DELETE
  2. REST 全称 Representational State Transfer ——(资源)表现层状态转化,是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便, 所以正得到越来越多网站的采用
  3. REST 风格就是通过 Http 请求方式的不同来标识不同的方法,即对于同一个请求路径,可以根据请求方式的不同来区分它们
操作传统风格请求REST风格请求
查询所有记录localhost:8080/sys/findUserAllGET localhost:8080/sys/user
查询一条记录localhost:8080/sys/findUser?uno=1GET localhost:8080/sys/user/1
保存一条记录localhost:8080/sys/saveUserPOST localhost:8080/sys/user
修改一条记录localhost:8080/sys/upateUserPUT locahost:8080/sys/user
  1. 使用@GetMapping , @PostMapping等注解, 配合@PathVariable注解完成请求映射与参数获取。

SpringBoot如何整合第三方框架?

  1. 添加依赖:在项目的pom.xml文件中添加第三方框架的starter启动器依赖,以及一些必须的相关的依赖,
    如整合mybatis框架,需要引入mybatis-sping-boot-starter 和 mysql-connector-java
  2. 配置属性:在application.properties中配置第三方框架的必要属性。
    如:spring.datasource.driver-class-name 等
  3. 配置Bean:在Spring配置中声明第三方框架的Bean,或者使用自动配置特性。
    如:声明SqlSessionFactory
  4. 使用框架:在你的应用代码中注入并使用第三方框架的类和方法。

说一说“@SpringBootApplication”注解在内部是如何工作的?

Spring Boot 应用程序使用此注解执行。实际上它是其他 3 个注释的组合:
ComponentScan、EnableAutoConfiguration和Configuration。

  • “@Configuration” ——所有带注释的类都被视为 Spring Boot 的配置,它们有资格创建 bean 并返回到 IOC 容器。
  • “@ComponentScan” ——所有带注释的类都将通过包(在哪里寻找)进行扫描,并帮助创建这些类的实例。
  • “@EnableAutoConfiguration” ——开启自动配置。基础框架附带了一个名为auto-configure的内置库,它为我们提供了与不同框架整合所需要的自动配置类。通过@ConditionalOnBean”、“@ConditionalOnClass等注解检测每一个配置类的激活条件,满足激活条件,开始自动配置。

MyBatis

MyBatis执行流程

  1. 读取MyBatis配置文件:mybatis-config.xml加载运行环境和映射文件
  2. 构造会话工厂SqlSessionFactory,一个项目只需要一个,单例的,一般由spring进行管理
  3. 会话工厂创建SqlSession对象,这里面就含了执行SQL语句的所有方法
  4. 操作数据库的接口,Executor执行器,同时负责查询缓存的维护
  5. Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息
  6. 输入参数映射
  7. 输出结果映射

Mybatis是否支持延迟加载?

延迟加载的意思是:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。
Mybatis支持一对一关联对象和一对多关联集合对象的延迟加载
在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false,默认是关闭的

延迟加载的底层原理知道吗?

延迟加载在底层主要使用的CGLIB动态代理完成的

  1. 第一是,使用CGLIB创建目标对象的代理对象,这里的目标对象就是开启了延迟加载的mapper
  2. 第二个是当调用目标方法时,进入拦截器invoke方法,发现目标方法是null值,再执行sql查询
  3. 第三个是获取数据以后,调用set方法设置属性值,再继续查询目标方法,就有值了

Mybatis的一级、二级缓存用过吗?

mybatis的一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当Session进行flush或close之后,该Session中的所有Cache就将清空,默认打开一级缓存

关于二级缓存需要单独开启

二级缓存是基于namespace和mapper的作用域起作用的,不是依赖于SQL session,默认也是采用 PerpetualCache,HashMap 存储。

如果想要开启二级缓存需要在全局配置文件和映射文件中开启配置才行。

Mybatis的二级缓存什么时候会清理缓存中的数据

当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了新增、修改、删除操作后,默认该作用域下所有 select 中的缓存将被 clear。

  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值