框架知识点

Spring

1. 什么是Spring

Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架。

目的是 用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。

常见的配置方式有三种:基于 XML的配置、基于注解的配置、基于Java的配置。

2. 说一下你对 Spring 的理解

Spring框架核心特性包括:

  • IOC容器:Spring通过控制反转实现了对象的创建和对象间的依赖关系管理。开发者只需要定义好Bean及其依赖关系,Spring容器负责创建和组装这些对象。
  • AOP:面向切面编程,运行开发者定义横切关注点,例如事务管理、安全控制等,独立于业务逻辑的代码。通过AOP,可以将这些关注的模板化,提高了代码的可维护性和可重用性。
  • 事务管理:Spring提供了一致的事务管理接口,支持声明式和编程式事务。
  • MVC框架:Spring MVC是一个基于Servlet API构建的Web框架,采用了模型-视图-控制器(MVC)架构。它支持灵活的URL到页面控制器的映射,以及多种视图技术。

3. Spring IoC和AOP 介绍一下

IOC:

  • IOC(Inverse Of Controll,控制反转):就是原来代码里面需要自己手动创建的对象,依赖,反转给Spring来帮忙实现。我们需要创建⼀个容器,同时需要⼀种描述来让容器知道要创建的对象与对象之间的关系。
  • 在Spring中BeanFactory就是IOC容器,在Spring初始化的时候,创建容器,并将需要创建对象和对象的关系 (xml,注解)通过BeanDefinitionReader加载到BeanDefinition中并保存在BeanDefinitionMap中,然后再 由IOC容器创建bean对象.

两种bean的注册方式

  • 通过@Bean+@Configuration的方式直接定义要创建的对象与对象的关系
  • 通过@Component定义类,这种方式必须使用@ComponetScan定位Bean扫描路径

AOP

  • AOP 在面向对象编程(oop)思想中,我们将事物纵向抽成⼀个个的对象。而在面向切面编程中,我们将⼀个个的对象某些类似的方面横向抽成⼀个切面,对这个切面进行⼀些如权限控制、事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。AOP底层是动态代理,如果是接口采用JDK 动态代理,如果是类采用CGLIB方式实现动态代理

4. Spring的aop介绍一下

我们知道,Java 就是一门面向对象编程的语言,在 OOP 中最小的单元就是“Class 对象”,但是在 AOP 中最小的单元是“切面”。一个“切面”可以包含很多种类型和对象,对它们进行模块化管理,例如事务管理。

在面向切面编程的思想里面,把功能分为两种

  • 核心业务:登陆、注册、增、删、改、查、都叫核心业务
  • 周边功能:日志、事务管理这些次要的为周边业务

AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码降低模块间的耦合度,并有利于未来的可拓展性和可维护性

Spring AOP 是基于 JDK 动态代理和 Cglib 提升实现的,两种代理方式都属于运行时的一个方式,所以它没有编译时的一个处理,那么因此 Spring 是通过 Java 代码实现的。

5. IOC和AOP是通过什么机制来实现的?

Spring IOC实现机制

  • 反射:Spring IOC容器利用Java的反射机制动态的加载类、创建对象实例以及调用对象方法,反射运行在运行时检测类、方法、属性的信息,从而实现灵活的对象实例化和管理。
  • 依赖注入:IOC的核心概念就是依赖注入,即容器负责管理应用程序组件之间的依赖关系。Spring有三种注入方式:构造器注入、setter方法注入和根据注解注入。
  • 工厂模式:Spring IOC容器通常采用工厂模式来管理对象的创建和生命周期。容器作为工厂负责实例化Bean并管理它们的生命周期,将Bean的实例化过程交给容器来管理。
  • 容器实现:Spring IOC容器是实现IOC的核心,通常使用BeanFactory或ApplicationContext来管理Bean。BeanFactory是IOC容器的基本形式,提供基本的IOC功能;ApplicationContext是BeanFactory的扩展,并提供更多企业级功能。

Spring AOP 实现机制

Spring AOP的实现依赖于动态代理技术。动态代理是在运行时动态生成代理对象,而不是在编译时。它允许开发者在运行时指定要代理的接口和行为,从而实现在不修改源码的情况下增强方法的功能。

Spring AOP支持两种动态代理:

  • 基于JDK的动态代理:使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。这种方式需要代理的类实现一个或多个接口。
  • 基于CGLIB的动态代理:当被代理的类没有实现接口时,Spring会使用CGLIB库生成一个被代理类的子类作为代理。CGLIB(Code Generation Library)是一个第三方代码生成库,通过继承方式实现代理。

6. 怎么理解Spring IOC?

IOC(控制反转):就是原来代码里面需要自己手动创建的对象,依赖,反转给Spring来帮忙实现。我们需要创建⼀个容器,同时需要⼀种描述来让容器知道要创建的对象与对象之间的关系。

所谓控制就是对象的创建、初始化、销毁。

  • 创建对象:原来是 new 一个,现在是由 Spring 容器创建。
  • 初始化对象:原来是对象自己通过构造器或者 setter 方法给依赖的对象赋值,现在是由 Spring 容器自动注入。
  • 销毁对象:原来是直接给对象赋值 null 或做一些销毁操作,现在是 Spring 容器管理生命周期负责销毁对象。

这个反转是指:我们由对象的控制者变成了 IOC 的被动控制者。

7. 依赖倒置,依赖注入,控制反转分别是什么?

  • 控制反转:就是原来代码里面需要自己手动创建的对象,依赖,反转给Spring来帮忙实现。

  • 依赖注入:我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。

  • 依赖倒置:(是软件设计六大之一原则)高层模块不依赖低层模块,它们共同依赖同一个抽象。抽象不要依赖具体实现细节,具体实现细节依赖抽象。

    简单来说,就是一台电脑有很多组件,比如cpu+硬盘等等,我们可以用不同品牌的cpu和不同品牌的硬盘。但不能一台电脑只能用专门的cpu而不能换吧!

8. 如果让你设计一个SpringIoc,你觉得会从哪些方面考虑这个设计?

  • Bean生命管理:需要设计Bean的创建、初始化、销毁等生命周期管理机制,可以考虑使用工厂模式和单例模式实现。
  • 依赖注入:需要实现依赖注入功能,包括属性注入、构造函数注入、方法注入等,可以考虑使用反射机制和XML配置文件来实现。
  • Bean的作用域:需要支持多种Bean作用域,比如单例、原型、会话、请求,可以考虑使用Map来存储不同作用域的Bean的实例。
  • AOP功能的实现:需要支持AOP功能,可以考虑使用动态代理机制和面向切面编程实现。
  • 异常处理:需要考虑异常处理机制,包括Bean创建异常、依赖注入异常等,可以考虑使用try-catch机制来处理异常。
  • 配置文件加载:需要支持从不同的配置文件中加载Bean的相关信息,可以考虑使用XML、注解或者Java配置类来实现。

9. SpringAOP的原理了解吗

Spring AOP的实现依赖于动态代理技术。动态代理是在运行时动态生成代理对象,而不是在编译时。它允许开发者在运行时指定要代理的接口和行为,从而实现在不修改源码的情况下增强方法的功能。

支持两种代理模式:

  • 基于JDK的动态代理:使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。这种方式需要代理的类实现一个或多个接口。
  • 基于CGLIB的动态代理:当被代理的类没有实现接口时,Spring会使用CGLIB库生成一个被代理类的子类作为代理。CGLIB是一个第三方代码生成库,通过继承方式实现代理。

10. 动态代理是什么?

Java的动态代理是一种在运行是动态创建代理对象的机制,主要用于在不修改原始类的情况下对方法调用进行拦截和增强。

动态代理主要分为两种类型

  • 基于接口的代理:这种类型的代理要求目标对象必须实现至少一个接口。Java动态代理会创建一个实现了相同接口的代理类,然后在运行时动态生成该类的实例。
  • 基于类的代理:CGLIB是一个强大的高性能的代码生成库,它可以在运行时动态生成一个目标类的子类。CGLIB代理不需要目标类实现接口,而是通过继承的方式创建代理类。

11. 动态代理和静态代理的区别

区别:

  • 静态代理:由程序员创建或者是由特定工具创建,在代码编译时就确定了被代理的类是一个静态代理。静态代理通常只代理一个类;
  • 动态代理:在代码运行期间,运用反射机制动态创建生成。动态代理代理的是一个接口下的多个实现类。

12. AOP实现有哪些注解?

  • @Aspect:用于定义切面,标注在切面类上。
  • @Pointcut:定义切点,标注在方法上,用于指定连接点。
  • @Before:在方法之前执行通知。
  • @After:在方法执行之后执行通知。
  • @Around:在方法执行前后都执行通知。
  • @Advice:通用的通知类型。

13. 什么是反射?有哪些使用场景?

Java的反射机制是指在运行时获得类的信息,创建类的对象,调用其中的方法和属性。

优点

  • 可以动态的获取类信息。
  • 可以动态的创建类对象。
  • 可以动态的调用类对象的方法以及属性。

缺点:

  • 不安全,反射能够获取所有类对象,包括私有的,破坏了程序的封装性。
  • 效率低,反射的效率较低。

应用场景:

  • 动态代理,因为不确定需要代理的类,所以需要通过反射动态的获取
  • RPC 框架,RPC 框架就是动态的生成类对象,然后调用方法的。

14. spring是如何解决循环依赖的?

循环依赖是指两个类中的属性相互依赖对方:例如A类中有B类的属性,B类有A类的属性。

循环依赖主要有三种情况

  • 通过构造方法进行依赖注入时产生
  • 通过setter方法进行依赖注入且是在多例模式下产生的循环依赖问题。
  • 通过setter方法进行依赖注入而且是在单例模式下产生的循环依赖问题。

只有【第三种方式】的循环依赖问题被 Spring 解决了,其他两种方式在遇到循环依赖问题时,Spring都会产生异常。

Spring 解决单例模式下的setter循环依赖问题的主要方式是通过三级缓存解决循环依赖。

pAYMsqH.png

  • A 和 B 两个 bean 出现循环依赖的执行流程
    • 获取到需要进行生成 bean 的 BeanDefinition 集合
    • 生成 A
      • 将 A 放入正在创建的 bean 集合中
      • 依次查看一二三缓存中是否有 A, 如果有则返回
      • 没有则通过反射实例化 A 对象; 并将存入三级缓存中; key: beanId, value: 获取 Abean 的 lambda 方法
      • 开始填充属性
      • 发现需要 B 进行填充
      • 生成 B
        • 将 B 放入正在创建的 bean 集合中
        • 从一二三级缓存中一次查找是否有 B
        • 通过反射实例化 B, 并将存入三级缓存中
        • 填充属性, 发现需要 A
        • 从一二三级缓存中查找 A, 在三级缓存中查找到 A, 获取 A 的 value (即为 lambda 函数)
          • 如果 A 被代理了, 那么就在这里提前代理 A, 并返回被代理后的 A bean (属性未完整填充)
          • 若没有被代理, 那么就直接返回 A bean (属性未完整填充)
        • 因为此时 A 的 bean 是属性不完整的所以将获取到的对象保存到二级缓存中, 将三级缓存中的 A 移除
        • 用不完整的 A 对 B 进行字段填充, 得到完整的 B 对象
        • 将 B 对象移动到一级缓存中
      • 从一二三级缓存中查找 B, 成功查找到 B 为 A 进行字段赋值
      • 得到完整的 A 对象将 A 对象移动到一级缓存中
    • 生成 B
      • 依次查找一二三级缓存中是否有 B
      • B 已经存在返回

pAY3eyT.png

  • 为什么要二级缓存, 一级缓存能实现吗?

理论上可以的, 只要在设计一级缓存的过程中能准确的标识当前 bean 是处于完成状态还是半成品状态即可; 但是如果通过二级缓存, 可以简化代码开发, 并且能提高每次的判断执行效率, 所以引入二级缓存

  • 为什么要引入三级缓存, 不引入三级缓存可以吗?

如果不引入三级缓存的话会造成一下问题, 如果 B 通过二级缓存将 A 的值进行填充了那么 B 中 A 的对象就是 A 的原始 bean 对象; 因为 bean 的生命周期中 bean 的字段填充是发生在初始化之前的, 所以当 A 进行后续操作中被代理了功能得到增强了, 那么 B 中的 A 字段是无法被更新和感知的额; 所以引入三级缓存的概念, 如果 A 被代理了, 那么在 B 在进行赋值的时候就可以将代理提前

15. spring 常用注解有什么?

@Autowired注解

主要用于自动装配bean

@Component

这个注解用于标记一个类作为Spring的bean。当一个类被@Component注解标记时,Spring会将其实例化为一个bean,并将其添加到Spring容器中。

@Configuration

@Configuration,注解用于标记一个类作为Spring的配置类。配置类可以包含@Bean注解的方法,用于定义和配置bean,作为全局配置。

@Bean

@Bean注解用于标记一个方法作为Spring的bean工厂方法。当一个方法被@Bean注解标记时,Spring会将该方法的返回值作为一个bean,并将其添加到Spring容器中。

@Service

Repository

@Controller

16. Spring的事务什么情况下会失效?

  • 未捕获异常:事务方法中发生了未捕获的异常,并且异常未被处理或传播到事务边界之外,那么事务会失效
  • 事务传播属性设置不当:如果在多个事务之间存在事务嵌套,且事务传播属性配置不正确,可能导致事务失效。
  • 跨方法调用事务问题:如果一个事务方法内部调用另一个方法,而这个被调用的方法没有 @Transactional 注解,这种情况下外层事务可能会失效。
  • 事务在非公开方法中失效:如果 @Transactional 注解标注在私有方法上或者非 public 方法上,事务也会失效。

17. Spring的事务,使用this调用是否生效?

不能生效。

Spring事务是通过代理对象来控制的。

当使用this直接调用时,是绕过了Spring的代理机制,因此不会应用事务设置。

18. Bean的生命周期说一下?

pAYJY60.png

  • 实例化Bean:Spring启动,查找并加载需要被Spring管理的bean
  • 设置对象属性(依赖注入):Bean实例化后对将Bean的引入和值注入到Bean的属性中。
  • 处理Aware接口:Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean
    • 如果实现了BeanNameAware接口:Spring将Bean的Id传递给setBeanName()方法
    • 如果实现了BeanFactoryAware接口:将BeanFactory容器实例传入
    • 如果实现了ApplicationContextAware接口:调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
  • 如果实现BeanPostProcessor
  • 如果实现了InitializingBean
  • 如果实现了BeanPostProcessor
  • 此时Bean就已经被正确创建了。
  • 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法。

19. Bean是否单例?

Spring 中的 Bean 默认都是单例的。

但是,Spring也支持将Bean设置为多例模式,可以在Bean定义中通过设置scope属性为”prototype”来实现。

20. Bean的单例和非单例,生命周期是否一样

不一样的。Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 Bean,Spring 在创建好交给使用者之后,则不会再管理后续的生命周期。

21. Spring bean的作用域有哪些?

  • Singleton(单例):整个应用程序中只存在一个 Bean 实例,默认作用域。
  • Prototype(原型):每次请求时都会创建一个新的 Bean 实例。
  • Request(请求):每个 HTTP 请求都会创建一个新的 Bean 实例。
  • Session(会话):Session 范围内只会创建一个 Bean 实例。

22. Spring容器里存的是什么?

在Spring容器中,存储的主要是Bean对象

Bean是Spring框架中的基本组件,用于表示应用程序中的各种对象。

23. 在Spring中,在bean加载/销毁前后,如果想实现某些逻辑,可以怎么做?

可以使用Spring的生命周期回调接口或注解。这些接口和注解允许你定义在Bean生命周期的关键点执行的代码。

使用init-method和destory-method

在XML配置中,你可以通过init-method和destroy-method属性来指定Bean初始化后和销毁前需要调用的方法。

然后在Bean类中实现这个方法。

实现initializing和disposableBean接口

分别实现afterPropertiesSet和destroy方法。

1
2
3
4
5
6
7
8
9
10
11
12
ublic class MyBeanClass implements InitializingBean, DisposableBean {  

@Override
public void afterPropertiesSet() throws Exception {
// 初始化逻辑
}

@Override
public void destroy() throws Exception {
// 销毁逻辑
}
}

使用@PostConstruct和@PreDestory注解

1
2
3
4
5
6
7
8
9
10
11
12
public class MyBeanClass {  

@PostConstruct
public void init() {
// 初始化逻辑
}

@PreDestroy
public void destroy() {
// 销毁逻辑
}
}

24. Bean注入和xml注入最终得到了相同的效果,它们在底层是怎样做的

XML注入

  • Bean 定义解析:Spring 容器通过 XmlBeanDefinitionReader 类解析 XML 配置文件,读取其中<bean>标签以获取Bean的定义信息。
  • 注册Bean定义:解析后的 Bean 信息被注册到

BeanDefinitionRegistry中。

  • 实例化和依赖注入:首先,使用反射机制创建该 Bean 的实例。然后,根据 Bean 定义中的配置,通过 setter 方法、构造函数或方法注入所需的依赖 Bean。

注解注入

  • 类路径扫描:当 Spring 容器启动时,它首先会进行类路径扫描,查找带有特定注解。
  • 注册Bean定义:找到的类会被注册到 BeanDefinitionRegistry 中,Spring 容器将为其生成 Bean 定义信息。
  • 依赖注入:Spring 在实例化 Bean 时,也会检查字段上是否有 @Autowired@Inject@Resource 注解。如果有,Spring 会根据注解的信息进行依赖注入。

25. 什么是SpringMVC

首先聊聊什么是 MVC,MVC 是一种编程思想, 他规定了 Model,view,Controller 三个层次; 而 SpringMVC 是 spring 生态在对 MVC 的一种实现, 他在传统的 MVC 框架上做了拓展, 将 Model 层拆分层了业务模型和数据模型分别是 Service 和 Repository, Contoller 才拆分成了前端控制器和后端控制器分别是 DispatcherServlet 和 Controller; 简单来说 SpringMVC 就是在 Spring 和 Sevlet 的基础上实现的 MVC 模式让我们更方便更清晰的开发网络服务

26. Spring的父子容器是什么

  • 父容器:负责管理应用程序中通用的bean,比如数据库连接、事务管理器等,生命周期与整个应用程序一致

  • 子容器:负责特定模块或组件的容器,可以共享父容器中的bean并且子容器中的bean不会影响父容器,比如controller控制器,生命周期与模块或组件一致

SpringBoot

1. 为什么使用springboot

  • 简化开发:Spring Boot通过提供一系列的组件和自动装配,简化了项目的配置和开发过程。
  • 快速启动:Spring Boot提供了快速的应用程序启动方式,可以通过内嵌的Tomcat、Jetty等容器快速启动应用程序。
  • 自动化配置:通过自动配置功能,根据项目中的依赖关系和约定俗成的规则来配置应用程序,减少了配置的复杂性。

2. SpringBoot比Spring好在哪里

  • 自动配置:提供了自动化配置,大大简化了项目的配置过程。通过约定优于配置的原则,很多常用的配置可以自动完成。
  • 快速启动:提供了快速的项目启动器,通过引入不同的 Starter,可以快速集成常用的框架和库,极大的提高了开发效率。
  • Spring Boot 默认集成了多种内嵌服务器(如Tomcat、Jetty、Undertow),无需额外配置,即可将应用打包成可执行的 JAR 文件,方便部署和运行。

3. SpringBoot用到哪些设计模式?

  • 代理模式:Spring的AOP通过动态代理方式实现方法级别的切面增强。
  • 策略模式:Spring AOP 支持 JDK 和 Cglib 两种动态代理实现方式,通过策略接口和不同策略类,运行时动态选择,其创建一般通过工厂方法实现。
  • 单列模式:Spring Bean 默认是单例模式。
  • 简单工厂模式:Spring 中的 BeanFactory 是简单工厂模式的体现。
  • 工厂方法模式:Spring中的 FactoryBean 体现工厂方法模式,为不同产品提供不同工厂。
  • 观察者模式:Spring 观察者模式包含 Event 事件、Listener 监听者、Publisher 发送者,通过定义事件、监听器和发送者实现,观察者注册在 ApplicationContext 中,消息发送由 ApplicationEventMulticaster 完成。
  • 模板方法模式:Spring Bean 的创建过程涉及模板模式,体现扩展性,类似 Callback 回调实现方式。
  • 适配器模式:Spring MVC 中针对不同方式定义的 Controller,利用适配器模式统一函数定义,定义了统一接口 HandlerAdapter 及对应适配器类。

4. 怎么理解SpringBoot中的约定大于配置

  • 自动化配置:Spring Boot 提供了大量的自动化配置,通过分析项目的依赖和环境,自动配置应用程序的行为。开发者无需显式地配置每个细节,大部分常用的配置都已经预设好了。
  • 默认配置:Spring Boot 在没有明确配置的情况下,会使用合理的默认值来初始化应用程序。
  • 约定优于配置:遵循了约定优于配置的设计哲学,即通过约定好的方式来提供默认行为,减少开发者需要做出的决策。例如,约定了项目结构、Bean 命名规范等,使得开发者可以更快地上手并保持团队间的一致性。

Spring Boot通过「自动化配置」和「起步依赖」实现了约定大于配置的特性。

  • 自动化配置:根据项目的依赖和环境自动配置应用程序,无需手动配置大量的XML或Java配置文件。
  • 起步依赖:Spring Boot提供了一系列起步依赖,这些依赖包含了常用的框架和功能,可以帮助开发者快速搭建项目。

5. SpringBoot自动装配原理是什么?

文章结束!