• 一统java框架的Spring高频话术总结


    Spring

    什么是spring

    spring是一个轻量级的java开发框架,解决企业应用开发的业务逻辑层和各层的耦合问题

    为什么要使用spring

    • 属于低侵入式设计,代码的污染极低

    • Aop面向切面编程

    • IOC控制反转

    • 对于主流的应用框架提供了集成的支持

    你们项目中为什么使用Spring框架?

    这么问的话,就直接说Spring框架的好处就可以了。比如说Spring有以下特点:

    轻量:Spring 是轻量的,基本的版本大约2MB。

    控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找

    依赖的对象们。

    面向切面的编程**(AOP):**Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。

    容器:Spring 包含并管理应用中对象的生命周期和配置。

    MVC**框架**:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。

    事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务

    (JTA)。

    异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛

    出的)转化为一致的unchecked 异常。

    说一下Spring中用到的设计模式

    单例模式:Spring 中的 Bean 默认情况下都是单例的。无需多说。

    工厂模式:工厂模式主要是通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象。

    代理模式:最常见的 AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理。

    模板方法模式:主要是一些对数据库操作的类用到,比如 JdbcTemplate、JpaTemplate,因为查询数据库的建立连接、执行查询、关闭连接几个过程,非常适用于模板方法。

    spring中的两大核心

    AOP

    aop是面向切面编程,用于将一些与业务无关的,但却对多个对象产生影响的公共行为和逻辑,抽取出来封装成一个模块,而这个模块就叫做切面。优点:减少系统中的重复代码,降低了模块间的耦合度,提高了系统的可维护性。主要用权限认证、日志、事务处理

    aop的实现关键主要在于代理模式,分为JDK动态代理和CGLIB动态代理

    JDK动态代理和CGLIB动态代理对比

    • JDK动态代理值提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler通过的是invoke()方法反射来代用目标类中的代码的。动态将逻辑和业务绑定在一起 。Proxy是利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象

    • 如果代理类中没实现InvocationHandler接口,那么Aop会选择使用CGLIB来动态代理目标类。CGLIB是一个代码生成的类库,可以在运行时动态生成指定类的一个子类对象,并且覆盖其中特定的方法来实现的aop。CGLIB是通过继承的方式做的动态代理。所以如果某各类被 标记为final,那么他是无法使用CGLIB代理的

    aop中切面、切点、连接点、通知之间的关系

    1、切面:就是将公共行为封装成模块之后的类

    2、切点:描述何时执行通知的规则

    3、连接点:被切点匹配执行通知的位置

    4、通知:是程序公共行为执行的代码操作

    IOC

    • IOC是控制反转,指的是创建对象的控制权利的转移,以前创建对象的主动权是自己,而现在 是将主动权交给了spring去管理,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,有利用功能的复用。DI依赖注入,和IOC是同一个概念的不同角度的描述,一个程序在运行时依赖IOC容器来动态注入对象 需要的外部资源

    • IOC就是 创建对象的时候不用在去new了,可以通过spring自动生产,使用java的反射机制,根据配置文件运行时动态去创建和管理,之后再去调用

    • spring的IOC是由三种注入方式:构造器注入、set方法注入、根据注解注入

    Spring Bean 的作用域范围

    1、singleton(单例模式):一个bean中只有一个实例 (默认)

    2、prototype:一个bean的定义可以有多 个实例

    3、request

    4、session

    5、global Session

    springMVC 的原理

    客户端发起请求到dispatchservlet,dispatchservlet根据请求调用handlerMappering,解析出一个对应的handler,解析出的handler由handlerAdapter适配器去处理完成之后得到对应的moudleAndView,最后将view返回给客户

     

    Spring事务

    数据库不支持事务

    注解放在了私有方法上

    类内部调用

    未捕获异常

    多线程场景

    spring的传播特性

    传播行为(PROPAGATION)描述
    PROPAGATION_REQUIRED如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
    PROPAGATION_SUPPORTS支持当前事务,如果没有当前事务,就以非事务方法执行。
    PROPAGATION_MANDATORY使用当前事务,如果没有当前事务,就抛出异常。
    PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,把当前事务挂起。
    PROPAGATION_NOT_SUPPORTED以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    PROPAGATION_NEVER以非事务方式执行操作,如果当前事务存在则抛出异常。
    PROPAGATION_NESTED如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED 类似的操作

    负载均衡之feign与ribbon比较

    • feign本身就包含了ribbon

    • feign自身是一个声明式的伪http客户端,写起来更加思路清晰和方便

    • feign是采用接口的注解编程方式

    使用feign造成的问题:

    一般在feign调用相应的service接口时候,第一次调用会因为超时而导致调用失败,所以需要设置超时时长

    spring 中 BeanFactory 和 FactoryBean 的区别

    首先呢,beanFactory是一个factory工厂,factoryBean是一个特殊的bean接口

    beanfactory是一个IOC的特殊工厂,是IOC的一个基本接口,他主要是用来管理和创建bean的实例 的,它提供了通过名字去创建bean的实例、判断此类是否在工厂中以及判断是否为单例模式

    factorybean是一个特殊的bean接口,他主要有三个方法:getbean(),返回实现factorybean的类接口创建bean的实例。getbojecttype()返回该实例的类型,isSingleton()判断是否为单例模式

    AOP的应用场景有哪些呢

    1、日志记录

    2、权限验证

    3、效率检查(个人在代码上,喜欢用注解+切面,实现校验,redis分布式锁等功能)

    4、事务管理(spring 的事务就是用AOP实现的)

    Spring Boot 的底层原理

    Spring Boot 底层实际上主要的有三个注解:

    configuration

    EnableAutoConfiguation

    ComponentScan

    读取 mate-inf下的 spring.factories 文件信息

    约定大于配置 自动装配

    Spring Bean的默认作用域为:singleton。它相比其他作用域的优点是系统开销小,Bean实例一旦创建成功便可重复使用。

    prototype

    request

    session

    global session

    SpringBean 生命周期

    1. 实例化,创建一个Bean对象

    2. 填充属性,为属性赋值

    3. 初始化

      • 如果实现了xxxAware接口,通过不同类型的Aware接口拿到Spring容器的资源

      • 如果实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzationpostProcessAfterInitialization方法

      • 如果配置了init-method方法,则会执行init-method配置的方法

    4. 销毁

      • 容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy方法

      • 如果配置了destroy-method方法,则会执行destroy-method配置的方法

    ###

    Spring中循环依赖的解决方案

    1. 使用context.getBean(A.class),获取容器内的单例A(若A不存在,就会走A这个Bean的创建流程),显然初次获取A是不存在的,因此走A的创建之路~

    2. 实例化A(注意此处仅仅是实例化),并将它放进缓存(此时A已经实例化完成,已经可以被引用了)

    3. 初始化A:@Autowired依赖注入B(此时需要去容器内获取B)

    4. 为了完成依赖注入B,会通过getBean(B)去容器内找B。但此时B在容器内不存在,就走向B的创建之路~

    5. 实例化B,并将其放入缓存。(此时B也能够被引用了)

    6. 初始化B,@Autowired依赖注入A(此时需要去容器内获取A)

    7. 此处重要:初始化B时会调用getBean(A)去容器内找到A,上面我们已经说过了此时候因为A已经实例化完成了并且放进了缓存里,所以这个时候去看缓存里是已经存在A的引用了的,所以getBean(A)能够正常返回

    8. B初始化成功(此时已经注入A成功了,已成功持有A的引用了),return(注意此处return相当于是返回最上面的getBean(B)这句代码,回到了初始化A的流程中~)。

    9. 因为B实例已经成功返回了,因此最终A也初始化成功

    10. 到此,B持有的已经是初始化完成的A,A持有的也是初始化完成的B

      我们开始三级缓存,首先通过A进入已经缓存,去寻找发现没有初始化的B(并且他使用了singlobject 提前曝光了自己) 在去二级缓找发现没有B,就去开启了创建B,

      B开始从一级缓存寻找A发现没有A,但是鱿鱼我们的A刚刚提前曝光了自己,我们B可以获取到A(但是这个A并不是初始化的而是实例化的但是A可以被引用)我们B待着A去三级缓存最实例化了,现在我们的B是实例化的,我回到刚刚的A在去获取b发现可以获得一个实例化好的B,然后在去三级缓存最后把自己也成功了实例化了这个时候我们的A和B都已经实例化过来就不会出现循环依赖的问题了

      spring解决循环依赖

      这是别人总结的三级缓存

      第一级缓存:用来保存实例化、初始化都完成的对象

      第二级缓存:用来保存实例化完成,但是未初始化完成的对象

      第三级缓存:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象

      假设一个简单的循环依赖场景,A、B互相依赖。

      A对象的创建过程:

      1. 创建对象A,实例化的时候把A对象工厂放入三级缓存

      1. A注入属性时,发现依赖B,转而去实例化B

      2. 同样创建对象B,注入属性时发现依赖A,一次从一级到三级缓存查询A,从三级缓存通过对象工厂拿到A,把A放入二级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入一级缓存。

      1. 接着继续创建A,顺利从一级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除二级缓存中的A,同时把A放入一级缓存

      2. 最后,一级缓存中保存着实例化、初始化都完成的A、B对象

      因此,由于把实例化和初始化的流程分开了,所以如果都是用构造器的话,就没法分离这个操作,所以都是构造器的话就无法解决循环依赖的问题了。

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

      不可以,主要是为了生成代理对象。

      因为三级缓存中放的是生成具体对象的匿名内部类,他可以生成代理对象,也可以是普通的实例对象。

      使用三级缓存主要是为了保证不管什么时候使用的都是一个对象。

      假设只有二级缓存的情况,往二级缓存中放的显示一个普通的Bean对象,BeanPostProcessor去生成代理对象之后,覆盖掉二级缓存中的普通Bean对象,那么多线程环境下可能取到的对象就不一致了。

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

    谈到beans线程安全那么就看bean是否有多种状态,如果始终只有一种状态 就是线程安全的,否则需要自己去保证线程的安全,可以采用将singleton变为prototype

    @autowired和@resource注解的区别是什么

    autowired是按照bytype注入的,是由spring提供的,resource是j2ee提供的,按照名字去注入的

    如果一个接口有多个实现,那么采用Qualifier

    什么时候spring事务不生效

  • 相关阅读:
    tomcat之Jdk配置
    JAVA&Android实现MQTT上位机软件功能-订阅主题与发布主题
    SpringMVC(下)
    知识蒸馏NST算法实战:使用CoatNet蒸馏ResNet18
    2024年山东省职业院校技能大赛中职组 “网络安全”赛项竞赛试题-C卷
    【Linux】环境变量
    【两篇就够】异步相关(二)
    数据结构:交换排序
    Docker容器搭建本地私有仓库
    Linux下使用openssl为harbor制作证书
  • 原文地址:https://blog.csdn.net/Fristm/article/details/125607357