2021年Spring面试核心知识

Spring优势

  • 轻量级、非侵入
  • IOC容器管理
  • DI机制将对象之间的依赖关系交由框架处理,降低组件的耦合性
  • 提供了AOP技术,将一些通用任务进行集中管理,从而提供更好的复用。
  • 方便集成
  • 丰富的功能

Spring的七大模块

  • Spring Core:框架中最基础的部分,提供Ioc容器,对Bean进行管理
  • Spring Context:基于bean,提供上下文信息,扩展出其他功能
  • Spring DAO:提供JDBC的抽象层,可以消除冗长的JDBC编码,以及提供了声明式事务管理
  • Spring ORM:提供常用的“对象/关系”映射APIs的集成层。包括JPA、JDO、Hibernate、MyBatis
  • Spring AOP:提供面向切面的编程实现
  • Spring Web:提供了基础的Web开发的上下文信息,可与其他Web进行集成
  • Spring Web MVC:提供了Web应用的MVC全功能实现

什么是Spring Framework

Spring是一个轻量级的控制反转(Ioc)和面向切面(AOP)的非侵入式框架

Spring配置文件

Spring配置文件是XMl文件。该文件主要包括类信息。描述了这些类是如何配置以及相互引用的。

Spring IOC容器

IOC就是控制反转,创建对象的控制权的转移,IOC让对象的创建不用去new了,而是可以由Spring自动产生,使用java的反射机制,根据配置文件在运行时动态的去创建和管理对象,并调用对象的方法

  • 注入方式

    • 构造器注入
    • Setter方法注入
    • 注解注入
  • 优点

    • 最小化应用程序中的代码量
    • 使得应用程序易于测试
    • 以最小的影响和最少的侵入机制促进松耦合
    • 支持即时的实例化和延迟加载服务

依赖注入(DI)

在依赖注入中,不必创建对象,但必须描述如何创建它们。不用直接在代码中将组件和服务连接在一起,而是描述配置文件中哪些组件需要哪些服务。由 IoC 容器将它们装配在一起。

依赖注入的方式
  • 构造函数注入
  • Setter注入
  • 接口注入

构造函数注入和setter注入

  • 构造函数注入:

    • 没有部分注入
    • 不会覆盖setter属性
    • 任何修改都会创建一个新实例
    • 适用于设置很多属性
  • setter方法注入

    • 可以部分注入
    • 会覆盖setter属性
    • 任意修改不会创建一个新实例
    • 适用于设置少量属性

BeanFactory和ApplicationContext

  • BeanFactory;

    • 使用懒加载
    • 使用语法显示提供资源对象
    • 不支持国际化
    • 不支持基于依赖的注解
  • ApplicationContext

    • 使用即时加载
    • 自己创建和管理资源对象
    • 支持国际化
    • 支持基于依赖的注解

什么是Spring bean

  • 是构成用户应用程序主干的对象
  • Bean由Spring IOC容器管理
  • 有Spring IoC容器实例化,配置,装配和管理
  • Bean是基于用户提供给容器的配置元数据创建

Spring的配置方式

  • 基于XML的配置Bean所需的依赖项和服务在XML格式的配置文件中指定

  • 基于注解的配置,可以通过相关的类,方法或字段声明上使用注解,将bean配置为组件类本身,而不是使用XML来描述bean配置。

  • 基于Java API配置

    • 通过@Bean和@Configuration来实现
      • @Bean注解与元素相同的角色
      • @Configuration类允许通过简单地调用同一个类中的其他@Bean方法来定义bean之间的依赖关系

Spring Bean的作用域

  • singleton(单例模式):仅存在一个Bean实例,默认实现
  • prototypr(原型模式):每次调用Bean都会返回一个新的实例
  • request(HTTP请求):每次HTTP请求会创建一个新的Bean
  • session(会话请求):同一个HTTP Session贡献一个Bean
  • globalSession(全局会话):一般用于Portlet环境。

Spring Bean的生命周期

总体来说就是实例化Bean、利用依赖注入设置对象属性、处理Aware接口、BeanPostProcessor前置方法,初始化方法、BeanPostProcessor的后置方法、DisposableBean、destroy

  • 实例化Bean对象:Spring 容器根据配置中的 bean 定义中实例化 bean。
  • 设置Bean属性:Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
  • 如果通过Aware接口声明了依赖关系,则会注入Bean对容器基础设施层面的依赖:BeanNameAware(Bean ID)、BeanFactoryAware(Bean Factory)和ApplicationContextAware(ApplicationContext)
  • 调用BeanPostProcessors的前置初始化方法preProcessBeforeInitialization() 。
  • 如果为 bean 指定了 init 方法( 的 init-method 属性),那么将调 用它。
  • 最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。
  • 如果 bean 实现DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
  • 如果为bean 指定了 destroy 方法( 的 destroy-method 属性),那么将 调用它。

自动装配

  • 自动装配方式

    • no:默认设置,表明没有自动装配。使用显式bean引用进行装配
    • byName:根据bean的名称注入对象依赖项
    • byType:根据类型注入对象依赖项
    • autodetect:首先容器尝试通过构造函数使用aytowire装配,如果不能,则尝试通过bytype自动装配
  • 自动装配局限

    • 重写:始终可以通过 和 设置指定依赖项,这将覆盖自动装配。
    • 基本数据类型:简单属性(如原数据类型,字符串和类)无法自动装配。
    • 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。

常见注解

@Component:

将这个java标记为bean。是任何Spring管理组件的通用构造型。spring的组件扫描机制可以将其拾取并将其拉入应用程序环境中

@Controller:web层

标有它的Bean 会自动导入到 IoC 容器中

@Service:service层

此注解是组件注解的特化

@Repository:dao层

此注解是组件注解的特化

@Service
@Required

应用于bean属性setter方法。此注解仅指示必须在配置时使用bean 定义中的显式属性值或使用自动装配填充受影响的 bean 属性。如果尚未填充受影响的 bean 属性,则容器将抛出 BeanInitializationException。

@Autowired

可以更准确地控制应该在何处以及如何进行自动装配

@Qualifier

当您创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,您可以使用其消除歧义

@RequestMapping

用于将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。此注释可应用于两个级别:类级别:映射请求的 URL 方法级别:映射 URL 以及 HTTP 请求方法

使用Spring访问Hibernate的方法

  • 使用 Hibernate 模板和回调进行控制反转
  • 扩展 HibernateDAOSupport 并应用 AOP 拦截器节点

Spring支持的事务管理类型

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring是无法提供事务功能的。真正的数据库层的事务提交和回归是通过binlog或者redo log实现的。

  • 程序化事务管理:在此过程中,在编程的帮助下管理事务。它为您提供极大的灵活性,但维护起来非常困难。
  • 声明式事务管理:在此,事务管理与业务代码分离。仅使用注解或基于 XML的配置来管理事务。

什么是AOP

面向切面编程, 它与OOP( 面向对象编程) 相辅相成, 提供了与OOP 不同的抽象软件结构的视角。用于将那些与业务无关,但对多个对象产生影响的公共行为和逻辑,抽象并封装为一个可重用的模块。

Aspect(切面)

被抽象的公共模块。可能会横切多个对象。在Spring AOP中,切面可以使用通用类或者在普通类中以@AspectJ注解来实现

连接点(JoinPoint)

程序运行中的一些时间点,在Spring AOP中,一个连接点总是代表一个方法的执行

通知(Advice)

在切面的某个特定的连接点上执行动作,并且通常以拦截器作为通知模型,并维护一个以连接点为中心的拦截器链。

切入点(Pointcut)

切入点是指我们要对那些连接点进行拦截的定义。通过切入点表达式,指定拦截的方式

引入(Introduction)

声明额外的方法或者某个类型的字段。Spring允许引入新的接口道任何被代理的对象。

目标对象(Target Object)

被一个或者多个切面所通知的对象。

织入(Weaving)

指把增强应用到目标对象来创建新的代理对象的过程。Spring是在允许时完成织入的。

Spring AOP中有哪些类型的通知(Advice)

  • 前置通知Before:这些类型的Advice在joinpoint方法之前执行
  • 返回后通知After Returning:这些类型的Advice在连接点方法正常执行后执行
  • 跑出异常后通知After Throwing:这个类型的Advice仅在joinpoint方法通过排除异常退出
  • 后通知After(finally):这些类型的Advice在连接点方法以后执行,无论方法退出是正常还是异常返回。
  • 环绕通知3
  • Around:这些类型的Advice在连接点之前和之后执行。

Spring AOP中concern和cross-cuttingconcern不同之处

concern

我们想要在应用程序的特定模块中定义的行为。它可以定义为我们想要实现的功能

cross-cuttingconcern

是一个适用于整个应用的行为,这会影响整个应用程序。例如,日志记录,安全性和数据传输是应用程序几乎每个模块都需要关注的问题,因此它们是跨领域的问题。

Spring中用到哪些设计模式

  • 工厂模式:BeanFactory就是简单工厂模式,用来创建对象的实例
  • 单例模式:Bean默认为单例模式
  • 代理模式:AOP功能中用到了JDK的动态代理
  • 模板方式:主要是一些对数据库操作的类,
  • 观察者模式:定义对象键一种一对多的依赖关系

Spring AOP和AspectJ AOP有什么区别

Spring AOP 是基于动态代理实现的,属于运行时增强,不需要单独编译,性能差一些

  • 默认如果使用接口的话使用JDK提供的动态代理实现,如果是方法则使用CGLIB实现

AspectJ则属于编译时增强,主要有三种方法:

  • 编译时织入:指的是增强的代码和源代码我们都有,直接使用AspectJ编译器编译即可,编译以后生成一个新的类,他会作为一个正常的Java类装载在JVM中
  • 编译后织入:指的是代码已经被编译成Class文件或者打包成jar包,这个时候要增强的话,就是编译后织入,比如当你依赖第三方的类库时,又需要对其增强的话,就可以使用这种方式
  • 加载时织入:指的是在JVM加载类的时候进行织入

JDK动态代理和CGLIB代理有什么区别

  • JKD动态代理、

    • JDK动态代理实现了InvocationHandler接口,重写的invoke方法
    • 其基础是反射机制
  • CGlib

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

CGLib性能较高,但是在创建代理对象时花费时间较多,所以在单例模式下更加有优势

CGLib采用的是动态创建子类的方法,所以对于final方法无法代理

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

Spring是如何解决循环依赖

解决循环依赖有两个前提条件

  • 不全是构造器方式的循环依赖
  • 必须是单例模式

基于上面的问题,我们知道Bean的生命周期,本质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化的对象

三级缓存
  • 一级缓存:用来保存实例化、初始化都完成的对象
  • 二级缓存:用来保存实例化完成,但未初始化完成的对象
  • 三级缓存:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象
AB互相依赖问题

A对象的创建过程:

  • 创建A对象,实例化的时候把A对象工厂放入三级缓存
  • A注入属性时,发现依赖B,转而去实例化B
  • 同样创建对象B,注入属性时发现依赖A,依次从一级到三级缓存中查询A,从三级缓存中通过对象工厂拿到A,把A放入到二级缓存中,同时删除三级缓存中的A,此时B已经实例化并且初始化完成,把B放入一级缓存。
  • 接着继续创建A,顺利从一级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除二级缓存中的A,同时把A放入一级缓存中
  • 最后一级缓存中保存着实例化、初始化都完成的A、B对象

因此由于把实例化和初始化的流程分开了,所以就解决了构造器不好解决的循环依赖

为什么要三级缓存,二级缓存不行吗

不可以,三级缓存的目的就是要生成代理对象。

因为三级缓存中放的是生成具体对象的匿名内部类,他可以生成代理对象,也可以是普通的实例对象。使用三级缓存是为了保证不管什么时候使用的都是一个对象。

@Component和@Bean的区别

  • 作用对象不同

    • @Component作用于类
    • @Bean作用于方法
  • 作用

    • @Component通常是通过类路径来自动侦测以及自动装配到Spring容器中
    • @Bean注解通常是我们在标有该注解的方法中定义这个bean,@Bean告诉了Spring这是个类的实例。
  • 另外@Bean注解自定义性更强,很多地方比如第三方库中的类需要装配到spring容器中的时候只能通过@Bean实现

Spring事务

Spring管理事务的方式有几种
  • 编程式事务,在代码中硬编码(不推荐使用)

  • 声明式事务,在配置文件中配置(推荐使用)

    • 基于XML的声明式事务
    • 基于注解的声明式事务
Spring事务中的隔离级别有哪几种

TransactionDefinition接口中定义了五个表示隔离级别的常量。

  • ISOLATION_DEFAULT: 后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
  • ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
Spring事务中有几种事务传播行为

支持当前事务的情况:

  • PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

不支持当前事务的情况:

  • PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

其他情况:

  • PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

@Transaction注解

Java中的异常Exception分为运行时异常和非运行时异常。事务的管理对于企业应用来说是十分重要的,即使出现异常情况,可可以保证数据的一致性。

当@Transaction注解作用于类上时,该类的所有public方法都具有该类型的事务属性。同时也可以在方法级别使用该标注来覆盖类级别的定义。

类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。

rollbackFor

如果在@Transaction注解中不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚

Spring中单例Bean的线程安全问题

  • 在Bean对象中尽量避免定义可变的成员变量
  • 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐使用)

SpringMVC工作原理

  • 客户端(浏览器)发送请求,直接请求到 DispatcherServlet。
  • DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。
  • 解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。
  • HandlerAdapter 会根据 Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
  • 处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。
  • ViewResolver 会根据逻辑 View 查找实际的 View。
  • DispaterServlet 把返回的 Model 传给 View(视图渲染)。
  • 把 View 返回给请求者(浏览器)

Spring MVC 中一个URL请求的执行过程

其本质就是:request是浏览器传过来的数据;response里面添加相应到浏览器的数据

  • 根据请求URL找到相应的Servlet

    • 在SpringMVC中采用通配的方式,即所有的请求都是到DispatcherServlet中
  • 在DispatcherServlet的doGet中根据对应的URl找到相应的Controller

  • 根据Controller返回值,通过渲染句柄找到对应的jsp进行处理,最终以字符串的方式返回给浏览器

最后
  • 如果觉得看完有收获,希望能关注一下,顺便给我点个赞,这将会是我更新的最大动力,感谢各位的支持
  • 欢迎各位关注我的公众号【java冢狐】,专注于java和计算机基础知识,保证让你看完有所收获,不信你打我
  • 求一键三连:点赞、转发、在看。
  • 如果看完有不同的意见或者建议,欢迎多多评论一起交流。感谢各位的支持以及厚爱。

——我是冢狐,和你一样热爱编程。

image

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值