2022-Java 后端工程师面试指南 -(SSM)

news2024/11/29 9:44:11

前言

种一棵树最好的时间是十年前,其次是现在

Tips

面试指南系列,很多情况下不会去深挖细节,是小六六以被面试者的角色去回顾知识的一种方式,所以我默认大部分的东西,作为面试官的你,肯定是懂的。

上面的是脑图地址

叨絮

SSM 框架,这个是我们平时用的最多的,所以面试中也是经常被问到,今天我们就来看看这几个框架呗

什么是 Spring

Spring 是一种轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性。我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发。这些模块是:核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。比如:Core Container 中的 Core 组件是 Spring 所有组件的核心,Beans 组件和 Context 组件是实现 IOC 和依赖注入的基础,AOP 组件用来实现面向切面编程。

谈谈自己对于 Spring IoC 和 AOP 的理解

IoC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。 IoC 在其他语言中也有应用,并非 Spring 特有。 IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象。

将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。 IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。 在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能要每次都要搞清这个 Service 所有底层类的构造函数,这可能会把人逼疯。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。

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

Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib ,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理.

一般我们可以使用 AspectJ ,Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。

使用 AOP 之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。

那你聊聊 Spring AOP 和 AspectJ AOP 有什么区别? 平时在项目中你一般用的哪个

Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。

Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,

我们一般在项目中用的 AspectJ AoP 比较多点

Spring 的 bean 作用域(scope)类型,Spring Bean 是否是线程安全的

Spring 容器中的 Bean 是否线程安全,容器本身并没有提供 Bean 的线程安全策略,因此可以说 Spring 容器中的 Bean 本身不具备线程安全的特性,但是具体还是要结合具体 scope 的 Bean 去研究。

Spring 的 bean 作用域(scope)类型

  • singleton:单例,默认作用域。

  • prototype:原型,每次创建一个新对象。

  • request:请求,每次 Http 请求创建一个新对象,适用于 WebApplicationContext 环境下。

  • session:会话,同一个会话共享一个实例,不同会话使用不用的实例。

线程安全这个问题,要从单例与原型 Bean 分别进行说明。

  • 对于原型 Bean,每次创建一个新对象,也就是线程之间并不存在 Bean 共享,自然是不会有线程安全的问题。

  • 对于单例 Bean,所有线程都共享一个单例实例 Bean,因此是存在资源的竞争。

  • 如果单例 Bean,是一个无状态 Bean,也就是线程中的操作不会对 Bean 的成员执行查询以外的操作,那么这个单例 Bean 是线程安全的。比如 Spring mvc 的 Controller、Service、Dao 等,这些 Bean 大多是无状态的,只关注于方法本身。总结下

  • 在 @Controller/@Service 等容器中,默认情况下,scope 值是单例-singleton 的,也是线程不安全的。

  • 尽量不要在 @Controller/@Service 等容器中定义静态变量,不论是单例(singleton)还是多实例(prototype)他都是线程不安全的。

  • 默认注入的 Bean 对象,在不设置 scope 的时候他也是线程不安全的。

  • 一定要定义变量的话,用 ThreadLocal 来封装,这个是线程安全的

那你说说 @Component 和 @Bean 的区别是什么?

  • 作用对象不同: @Component 注解作用于类,而 @Bean 注解作用于方法。

  • @Component 通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中(我们可以使用 @ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean 告诉了 Spring 这是某个类的示例,当我需要用它的时候还给我。

  • @Bean 注解比 Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册 bean。比如当我们引用第三方库中的类需要装配到 Spring 容器时,则只能通过 @Bean 来实现。

那你聊聊什么是 spring 装配,自动装配有哪些方式?

当 bean 在 Spring 容器中组合在一起时,它被称为装配或 bean 装配。 Spring 容器需要知道需要什么 bean 以及容器应该如何使用依赖注入来将 bean 绑定在一起,同时装配 bean。

Spring 容器能够自动装配 bean。也就是说,可以通过检查 BeanFactory 的内容让 Spring 自动解析 bean 的协作者。

自动装配的不同模式:

  • no - 这是默认设置,表示没有自动装配。应使用显式 bean 引用进行装配。

  • byName - 它根据 bean 的名称注入对象依赖项。它匹配并装配其属性与 XML 文件中由相同名称定义的 bean。

  • byType - 它根据类型注入对象依赖项。如果属性的类型与 XML 文件中的一个 bean 名称匹配,则匹配并装配属性。

  • 构造函数 - 它通过调用类的构造函数来注入依赖项。它有大量的参数。

  • autodetect - 首先容器尝试通过构造函数使用 autowire 装配,如果不能,则尝试通过 byType 自动装配。

你知道 @Autowired 注解有什么用? 那 @Qualifier 呢?

  • @Autowired 可以更准确地控制应该在何处以及如何进行自动装配。此注解用于在 setter 方法,构造函数,具有任意名称或多个参数的属性或方法上自动装配 bean。默认情况下,它是类型驱动的注入。

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

说说 Spring Bean 的生命周期

准确的了解 Spring Bean 的生命周期是非常必要的。我们通常使用 ApplicationContext 作为 Spring 容器。这里,我们讲的也是 ApplicationContext 中 Bean 的生命周期。而实际上 BeanFactory 也是差不多的,只不过处理器需要手动注册。

image.png

image.png

其实在整个 Bean 的生命周期,也就是 Bean 初始化完成之前,我们的 spring 给我们提供了太多的拓展点了,可以让我们灵活的去解决我们不同的需求,下面来总结总结这些钩子函数 Bean 的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:

  • Bean 自身的方法  :  这个包括了 Bean 本身调用的方法和通过配置文件中的 init-method 和 destroy-method 指定的方法

  • Bean 级生命周期接口方法  :  这个包括了 BeanNameAware、BeanFactoryAware、InitializingBean 和 DiposableBean 这些接口的方法

  • 容器级生命周期接口方法  :  这个包括了 InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。

image.png

聊聊 Web 容器的启动过程吧,说说它的启动方式

首先我们来聊聊 Spring 容器的启动方式,也就是我们整个 web 项目的一个启动方式,目前主流的公司一般分为 2 种,一种基于 ssm 的启动流程,一种是基于 SpringBoot 的启动过程,今天我就来说说 ssm 的一个启动流程,springboot 的下次和 springcloud 系列一起讲

SSM 的 SpringBoot 的启动流程

image.png

  • 首先,对于一个 web 应用,其部署在 web 容器中,web 容器提供其一个全局的上下文环境,这个上下文就是 ServletContext,其为后面的 spring IoC 容器提供宿主环境;

  • 然后就是我们的 web.xml,在几年前的项目我想大家都有碰到过吧,在 web.xml 中会提供有 contextLoaderListener。在 web 容器启动时,会触发容器初始化事件,此时 contextLoaderListener 会监听到这个事件,其 contextInitialized 方法会被调用,在这个方法中,spring 会初始 化一个启动上下文,这个上下文被称为根上下文,即 WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是 XmlWebApplicationContext。这个就是 spring 的 IoC 容器,其对应的 Bean 定义的配置由 web.xml 中的 context-param 标签指定。在这个 IoC 容器初始化完毕后,spring 以 WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE 为属性 Key,将其存储到 ServletContext 中,便于获取;

  • 再 次,contextLoaderListener 监听器初始化完毕后,开始初始化 web.xml 中配置的 Servlet,这里是 DispatcherServlet,这个 servlet 实际上是一个标准的前端控制器,用以转发、匹配、处理每个 servlet 请 求。DispatcherServlet 上下文在初始化的时候会建立自己的 IoC 上下文,用以持有 spring mvc 相关的 bean。在建立 DispatcherServlet 自己的 IoC 上下文时,会利用 WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE 先从 ServletContext 中获取之前的根上下文(即 WebApplicationContext)作为自己上下文的 parent 上下文。有了这个 parent 上下文之后,再初始化自己持有的上下文。这个 DispatcherServlet 初始化自己上下文的工作在其 initStrategies 方 法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个 servlet 自己持有的上下文默认实现类也是 XmlWebApplicationContext。初始化完毕后,spring 以与 servlet 的名字相关(此处不是简单的以 servlet 名为 Key,而是通过一些转换,具体可自行查看源码)的属性为属性 Key,也将其存到 ServletContext 中,以便后续使用。这样每个 servlet 就持有自己的上下文,即拥有自己独立的 bean 空间,同时各个 servlet 共享相同的 bean,即根上下文(第 2 步中初始化的上下文)定义的那些 bean。

上面就是我们整个 SSM 的启动过程了,也是几年前大多数企业级开发的一个整个项目启动流程哦,至于 SpringBoot 的方式,下一篇 springboot 再在

那你聊聊 Spring 容器的加载过程呗(ioc 的启动流程)

上面的过程是整个 web 容器的启动过程,它里面包含了我们 spring 容器的启动流程,我现在就给大家详细的讲解我们 ioc 启动的加载过程

AbstractApplicationContext.java 里的 refresh() 方法,这个方法就是构建整个 IoC 容器过程的完整代码,只要把这个方法里的每一行代码都了解了,基本上了解了大部分 ioc 的原理和功能。

image.png

  • prepareRefresh() 方法:为刷新准备新的上下文环境,设置其启动日期和活动标志以及执行一些属性的初始化。主要是一些准备工作,不是很重要的方法,可以先不关注

  • obtainFreshBeanFactory() 方法:该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。常见的,如果解析到<context:component-scan base-package=“com.joonwhee.open” /> 注解时,会扫描 base-package 指定的目录,将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的 bean 定义也同样封装成 BeanDefinition,加载到 BeanFactory 中。 上面提到的“加载到 BeanFactory 中”的内容主要指的是以下 3 个缓存:

  • beanDefinitionNames 缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合。

  • beanDefinitionMap 缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射。

  • aliasMap 缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。

  • prepareBeanFactory(beanFactory) 方法:配置 beanFactory 的标准上下文特征,例如上下文的 ClassLoader、后置处理器等。这个方法会注册 3 个默认环境 bean:environment、systemProperties 和 systemEnvironment,注册 2 个 bean 后置处理器:ApplicationContextAwareProcessor 和 ApplicationListenerDetector。

  • postProcessBeanFactory(beanFactory) 方法:允许子类对 BeanFactory 进行后续处理,默认实现为空,留给子类实现。

  • invokeBeanFactoryPostProcessors(beanFactory) 方法:实例化和调用所有 BeanFactoryPostProcessor,包括其子类 BeanDefinitionRegistryPostProcessor。

  • registerBeanPostProcessors(beanFactory) 方法:注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。

  • initMessageSource() 方法:初始化消息资源 MessageSource

  • initApplicationEventMulticaster() 方法:初始化应用的事件广播器 ApplicationEventMulticaster。

  • onRefresh() 方法:该方法为模板方法,提供给子类扩展实现,可以重写以添加特定于上下文的刷新工作,默认实现为空。(在 springboot 中这个方法可是加载 tomcat 容器的)

  • registerListeners() 方法:注册监听器。

  • finishBeanFactoryInitialization(beanFactory) 方法:该方法会实例化所有剩余的非懒加载单例 bean。除了一些内部的 bean、实现了 BeanFactoryPostProcessor 接口的 bean、实现了 BeanPostProcessor 接口的 bean,其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。(这个方法其实是核心方法了,包含我们的 bea 从 beandifinition 变成我们的容器中的 bean 最核心的方法了)

  • finishRefresh() 方法:完成此上下文的刷新,主要是推送上下文刷新完毕事件(ContextRefreshedEvent )到监听器。

比较重要的是下面几个点

  • obtainFreshBeanFactory 创建一个新的 BeanFactory、读取和解析 bean 定义。

  • invokeBeanFactoryPostProcessors 提供给开发者对 BeanFactory 进行扩展。

  • registerBeanPostProcessors 提供给开发者对 bean 进行扩展。

  • finishBeanFactoryInitialization 实例化剩余的所有非懒加载单例 bean。

SpringMVC 工作原理了解吗? 基于页面 Controller 的类型

  • 客户端(浏览器)发送请求,直接请求到 DispatcherServlet。

  • DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。

  • 解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。

  • HandlerAdapter 会根据 Handler 来调用真正的处理器来处理请求,并处理相应的业务逻辑。

  • 处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。

  • ViewResolver 会根据逻辑 View 查找实际的 View。

  • DispaterServlet 把返回的 Model 传给 View(视图渲染)。

  • 把 View 返回给请求者(浏览器)

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

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

  • 代理设计模式 : Spring AOP 功能的实现。

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

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

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

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

spring 事务熟悉不,一般你用哪种实现方式

  • 编程式事务,在代码中硬编码。(不推荐使用)

  • 声明式事务,在配置文件中配置(推荐使用)一般在我们企业级开发的过程中,一般都是用的声明式事务,声明式事务也分为 2 种一种是基于 xml 的,一种基于注解的,一般用注解的多点

说说 Spring 事务中哪几种事务传播行为?

支持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

  • TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

  • TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)不支持当前事务的情况:

  • TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。

  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。

  • TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。

说说 BeanFactory 和 FactoryBean 的区别?

  • BeanFactory 是个 Factory,也就是 IOC 容器或对象工厂,在 Spring 中,所有的 Bean 都是由 BeanFactory(也就是 IOC 容器)来进行管理的,提供了实例化对象和拿对象的功能。

  • FactoryBean 是个 Bean,这个 Bean 不是简单的 Bean,而是一个能生产或者修饰对象生成的工厂 Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。

聊聊 Spring 的循环依赖吧

  • spring 的循环依赖主要是指两个类相互之间通过 @Autowired 自动依赖注入对方,即类 A 包含一个类 B 的对象引用并需要自动注入,类 B 包含一个类 A 的对象引用也需要自动注入。

  • 对于循环依赖问题,spring 根据注入方式的不同,采取不同的处理策略,对于双方都是使用属性值注入或者 setter 方法注入,则 spring 可以自动解决循环依赖注入问题,应用程序可以成功启动;对于双方都是使用构造函数注入对方或者主 bean 对象(Spring 在启动过程中,先加载的 bean 对象)使用构造函数注入,则 spring 无法解决循环依赖注入,程序报错无法启动。

首先 spring 在单例的情况下是默认支持循环引用的;在不做任何配置的情况下,两个 bean 相互依赖是能初始化成功的;spring 源码中在创建 bean 的时候先创建这个 bean 的对象,创建对象完成之后通过判断容器对象的 allowCircularReferences 属性决定是否允许缓存这个临时对象,如果能被缓存成功则通过缓存提前暴露这个临时对象来完成循环依赖;而这个属性默认为 true,所以说 spring 默认支持循环依赖的,但是这个属性 spring 提供了 api 让程序员来修改,所以 spring 也提供了关闭循环引用的功能;

那你说说 Spring 是如何解决循环引用的

首先,Spring 内部维护了三个 Map,也就是我们通常说的三级缓存。

笔者翻阅 Spring 文档倒是没有找到三级缓存的概念,可能也是本土为了方便理解的词汇。

在 Spring 的 DefaultSingletonBeanRegistry 类中,你会赫然发现类上方挂着这三个 Map:

  • singletonObjects 它是我们最熟悉的朋友,俗称“单例池”“容器”,缓存创建完成单例 Bean 的地方。

  • singletonFactories 映射创建 Bean 的原始工厂

  • earlySingletonObjects 映射 Bean 的早期引用,也就是说在这个 Map 里的 Bean 不是完整的,甚至还不能称之为“Bean”,只是一个 Instance.后两个 Map 其实是“垫脚石”级别的,只是创建 Bean 的时候,用来借助了一下,创建完成就清掉了。

所以笔者前文对“三级缓存”这个词有些迷惑,可能是因为注释都是以 Cache of 开头吧。

为什么成为后两个 Map 为垫脚石,假设最终放在 singletonObjects 的 Bean 是你想要的一杯“凉白开”。

那么 Spring 准备了两个杯子,即 singletonFactories 和 earlySingletonObjects 来回“倒腾”几番,把热水晾成“凉白开”放到 singletonObjects 中。

循环引用的不同的场景,有哪些方法可以解决循环引用

image.png

为啥有些注入方式不能解决循环依赖问题呢?源码中看出,他们并没有用到那个 earlySingletonObjects 这个缓存,所以就不能解决循环依赖

解决 Spring 无法解决的循环依赖的一些方式

项目中如果出现循环依赖问题,说明是 spring 默认无法解决的循环依赖,要看项目的打印日志,属于哪种循环依赖。目前包含下面几种情况:

image.png

生成代理对象产生的循环依赖这类循环依赖问题解决方法很多,主要有:

  • 使用 @Lazy 注解,延迟加载

  • 使用 @DependsOn 注解,指定加载先后关系

  • 修改文件名称,改变循环依赖类的加载顺序

说说什么是 Mybatis?

  • Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,加载驱动、创建连接、创建 statement 等繁杂的过程,开发者开发时只需要关注如何编写 SQL 语句,可以严格控制 sql 执行性能,灵活度高。

  • 作为一个半 ORM 框架,MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。

说说 #{}和 ${}的区别是什么?

  • #{}是预编译处理,${}是字符串替换。

  • Mybatis 在处理 #{}时,会将 sql 中的 #{}替换为?号,调用 PreparedStatement 的 set 方法来赋值;

  • Mybatis 在处理时,就是把{}替换成变量的值。

  • 使用 #{}可以有效的防止 SQL 注入,提高系统安全性。

说说 Mybatis 的一级、二级缓存:

一级缓存 事务范围:缓存只能被当前事务访问。缓存的生命周期 依赖于事务的生命周期当事务结束时,缓存也就结束生命周期。 在此范围下,缓存的介质是内存。 二级缓存 进程范围:缓存被进程内的所有事务共享。这些事务有 可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。 缓存的生命周期依赖于进程的生命周期,进程结束时, 缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据, 所以存放的介质可以是内存或硬盘。

聊聊 Mybatis 的一个整体的架构吧

image.png

其实哈,我觉得 mybatis 框架主要需要做的事情我们是知道的,为啥呢?因为其实如果我们没有 mybatis 我们也可以做数据库操作对吧,那就是 jdbc 的操作呗,那其实 mybatis 就是在封装在 jdbc 之上的一个框架而已,它所需要做的就是那么多,我来总结下

  • 首先就是一些基础组件 连接管理,事务管理,配置的加载,缓存的处理

  • 然后是核心的功能,我们参数映射,我们的 sql 解析,sql 执行,我们的结果映射

  • 之上就是封装我们统一的 crud 接口就好了,对就这么多咯。

上面就是整个 mybatis 做的事情了,当然每一块功能处理起来也是不那么简单的。

对 Mybatis 的源码熟悉吗,找你熟悉的地方聊聊呗

image.png

上面的图是整个 mybatis 的一个核心流程,其实不过是 spring 也好,mybatis 也好,所有的框架我们都可以把他们分为 2 个部分,一个就是初始化的过程,就是相当于做好准备工作来接客的过程,第二个就是实际的接客过程了,所以不管是讲哪个框架的源码都是这样来的,mybatis 当然也是不例外的

  • 初始化过程 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(“configuration.xml”));

就是我们 mybatis 的核心在 SqlSessionFactory,首先 SqlSessionFactory build 出来 这个过程就会涉及到解析各种配置文件,第一个要解析的就是 configuration 然后他的里面有很多的标签,你比如说 properties 等节点,然后里面有一个 mapper 节点,就是可以找到我们的 mapper.xml 然后又去解析里面的节点,报告各种 cach,select 等等,之后把解析好之后 xml 通过命名空间和我们的 mapper 接口绑定,并生成代码对象,把他放到 konwsmapper 这个 map 容器里面。最后就可以生成这个 SqlSessionFactory

  • 真正的执行过程就是当我们的 mybatis 准备好之后呢?我们拿到这个 sqlsession 对象之后,如果是不要 spring 集成的话,那么接下来当然是要去获取我们的 mapper 对象了 sqlsession.getMapper,当然这个获取的也是代理对象拉,然后到 MapperMethod,然后 SqlSession 将查询方法转发给 Executor。Executor 基于 JDBC 访问数据库获取数据。Executor 通过反射将数据转换成 POJO 并返回给 SqlSession。将数据返回给调用者。

结束

接下来我们看看 SpringBoot 和 SpringCloud 的组件哈,东西还很多,大家一起加油
【这里想说,因为自己也走了很多弯路过来的,所以才下定决心整理,收集过程虽不易,但想到能帮助到一部分自学或者是想提升java技术、成为Java架构师,提升技术P5-P6-P7-P8 的人,心里也是甜的!有需要的伙伴请点㊦方】↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3384.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mybatis之foreach

文章目录一、foreach属性二、使用foreach批量删除(法一)1.接口2.mapper文件3.测试类4.运行结果三、使用foreach批量删除(法二)1.mapper文件四、使用foreach批量插入1.接口2.mapper文件3.测试类4.运行结果一、foreach属性 collection&#xff1a;指定数组或者集合 item&#xf…

FPGA时序约束01——基本概念

前言1. 越来越多的时序问题 随着FPGA时钟频率加快与其实现的逻辑功能越来越复杂&#xff0c;开发者遇到的问题很多时候不再是代码逻辑的问题&#xff0c;而是时序问题。一些开发者可能有这样的经历&#xff0c;一个模块在100MHz时钟运行没问题&#xff0c;而将时钟频率改为150…

【仿牛客网笔记】 Spring Boot进阶,开发社区核心功能-事务管理

添加评论中会用到事务管理。 解决的程度不同&#xff0c;层级不同。我们一般选择中间的级别。 选择时既能满足业务的需要&#xff0c;又能保证业务的安全性&#xff0c;在这样的前提下我们追求一个更高的性能。 第一类丢失更新 图中是没有事务隔离的情况 第二类丢失更新 脏…

需求工程方法的学习

作业要求&#xff1a;总结尽可能多的需求工程的方法和技术&#xff0c;要求归纳总结各种方法的适用场景、优缺点等。说明&#xff1a;其中需求工程包括需求获取、需求分析、规格说明、验证、管理等。只要是用于需求工程相关的技术和方法都可以算。 软件需求工程划分为需求开发…

Linux 中 man手册中函数后面括号数字释义

文章目录简介参考资料简介 Linux手册页项目记录了用户空间程序使用的Linux内核和C库接口。 用man手册查看系统命令&#xff0c;系统调用&#xff0c;glibc函数时&#xff0c;会发现其后面会有个括号&#xff0c;括号里面是一个数字&#xff0c;比如&#xff1a; access(2), …

一文了解Spring框架

目录 SpringBoot VS Servlet Spring是什么&#xff1f; loC&#xff1a;控制反转 DI 创建一个Spring项目 创建一个Spring IOC容器 注册Bean对象 获取Bean对象 注意事项&#xff1a; 类注解 为什么有这么多类注解&#xff1f; 注册与注入 方法注解 Bean Spr…

《R语言数据分析》2022-2023第一学期课程分析报告

1 (30分)基本操作题 1.1 (10分) 请写出下面问题的R代码 1.(2分)安装并加载gtools扩展包。 install.packages(“gtools”) library(gtools) 2.(2分)查看当前已经加载的所有包。 as.data.frame(installed.packages())$Package 3.(2分)查看gtools包的帮助网页。 ?gtools…

《清单革命》内容梳理随笔

《清单革命》内容梳理&随笔 起 书即是将四散的知识按照逻辑和网状联系编排起来。你应该这样去读&#xff0c;高屋建瓴、层次有秩、显得貌似自己有经验&#xff08;褒义&#xff09;的读&#xff0c;读出一些感想和方法论&#xff0c;无论是读出书里的还是书外的&#xff…

【MySQL高级】SQL优化

5. SQL优化 5.1 大批量插入数据 环境准备 &#xff1a; CREATE TABLE tb_user_2 (id int(11) NOT NULL AUTO_INCREMENT,username varchar(45) NOT NULL,password varchar(96) NOT NULL,name varchar(45) NOT NULL,birthday datetime DEFAULT NULL,sex char(1) DEFAULT NULL,…

【数据库】实验五 数据库综合查询|多表查询、聚集函数、orderby、groupby

文章目录参考文章本文在实验四的基础上增加了orderby、聚集函数、groupby、多表查询的知识点&#xff0c;相较于上一次实验的难度变大了&#xff0c;嵌套表达更多了&#xff0c;逐渐开始套娃…… 其实可以看成一个偏正短语来拆分&#xff0c;再写成SQL语句&#xff0c;比如查询…

微信小程序|基于小程序实现人脸数量检测

一、文章前言二、具体流程及准备三、开发步骤四、完整代码一、文章前言 此文主要通过小程序实现检测图片中的人脸数量并标记出位置信息。 当近视的小伙伴看不清远处的人时&#xff0c;用小程序一键识别就可以在手机上看清楚啦&#xff0c;是不是很实用呢。 典型应用场景&#x…

2022年还在做手动测试?是该好好反思了

为什么会写这篇文章呢&#xff1f;主要是前段时间有个朋友在QQ上和我交流&#xff0c;说他干了10年的手工测试了&#xff0c;现在还能不能转行。 说实话&#xff0c;当时我听完非常惊讶&#xff01;由此&#xff0c;我写了今天这篇文章。内容纯属个人观点&#xff0c;如果对你…

STM32CubeMX学习笔记(46)——USB接口使用(HID自定义设备)

一、USB简介 USB&#xff08;Universal Serial BUS&#xff09;通用串行总线&#xff0c;是一个外部总线标准&#xff0c;用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、…

浅刷牛客链表题,逐步深入链表,理解链表

作者&#xff1a;渴望力量的土狗 博客主页&#xff1a;渴望力量的土狗的博客主页 专栏&#xff1a;手把手带你刷牛客 工欲善其事必先利其器&#xff0c;给大家介绍一款超牛的斩获大厂offer利器——牛客网 点击免费注册和我一起刷题吧 目录 1、反转链表 2、删除链表的倒数第n个…

RocketMQ 消息重新投递 解析——图解、源码级解析

&#x1f34a; Java学习&#xff1a;Java从入门到精通总结 &#x1f34a; 深入浅出RocketMQ设计思想&#xff1a;深入浅出RocketMQ设计思想 &#x1f34a; 绝对不一样的职场干货&#xff1a;大厂最佳实践经验指南 &#x1f4c6; 最近更新&#xff1a;2022年11月4日 &#x…

35、Java——一个案例学会Dao+service层对数据表的增删改查

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;乐趣国学的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java案例分…

deployment html--->JDBC--->mysql

spec: 相关属性定义 spec.selector: 符合该条件的收到该deployment管理 #spec.selector.matchLables 和 spec.template.metadata.labels 标签要一致 mysql Service metadata.name: Service的服务名 spec.ports: 虚拟端口 spec.selector: 哪些pod&#xff08;实列&…

《Java》深浅拷贝解析(还不会区分深浅拷贝吗?快进来)

目录 一、深浅拷贝的意义 浅拷贝 深拷贝 二、深浅拷贝举例 浅拷贝 深拷贝 一、深浅拷贝的意义 首先我们来了解一下深浅拷贝的意义 浅拷贝 浅拷贝是会将对象的每个属性进行依次复制&#xff0c;但是当对象的属性值是引用类型时&#xff0c;实质复制的是其引用&#xff0c…

全网最全【数据结构与算法】408真题实战(含代码+详解)—— 线性表专题(持续更新...)

线性表专题 每道题目均有对应的代码&#xff0c;大家自行查看哦&#xff01; 顺序表 ADT&#xff1a;SeqList 文件名&#xff1a;SeqList.hpp #include <iostream> #include <cstdlib> using namespace std; // 以上是实际运行所需依赖&#xff0c;考试不用写t…

怎样编写裸片启动程序-ARMv8的Boot Code和ROM程序

ROM程序就是固化在芯片的ROM里面&#xff0c;把应用程序从存储器里加载/搬移到RAM中并使处理器开始执行应用程序的一段程序 1 Boot Code和ROM程序 从多普通单核MCU&#xff08;如STM32&#xff09;的使用者的角度来看&#xff0c;只需要把编译好的hex文件烧写到片上Flash中&am…