[TOC]

JavaWeb

B/S架构与C/S架构是什么?

B/S架构(Browser/Server)

B/S架构(Browser/Server Architecture)是指浏览器/服务器架构,也被称为Web架构。在B/S架构中,应用程序的前端界面(通常是浏览器)与后端服务器进行交互。

  • 交互流程:在B/S架构中,前端界面是通过浏览器上的Web页面来呈现给用户,通常使用HTML、CSS和JavaScript等技术来实现。用户通过浏览器发送请求(如点击链接、填写表单等),请求会被发送到服务器端进行处理。服务器端进行相应的业务逻辑处理,并返回数据或页面给浏览器,浏览器再将这些数据或页面展示给用户。

  • 适应场景:B/S架构适用于跨平台和分布式环境,因为它只需要一个浏览器作为客户端界面,不需要安装额外的客户端软件

  • 示例应用:常见的网站和在线应用一般采用B/S架构,如电子商务网站、新闻网站等

C/S架构(Client/Server)

C/S架构(Client/Server Architecture)是指客户端/服务器架构。在C/S架构中,应用程序被分为客户端和服务器两个部分。

  • 交互流程:在C/S架构中,客户端是安装在用户本地的软件,负责用户界面的显示和用户交互,用户可以在客户端上进行各种操作,客户端会将这些操作转换为请求,发送给服务器。服务器则负责接收客户端的请求,进行相应的处理,并返回结果给客户端。
  • 适应场景:客户端软件需要在各个平台上进行开发和维护,适用于对性能和用户体验要求较高的应用场景。
  • 示例应用: 桌面应用程序和移动应用程序采用C/S架构,如QQ、迅雷等APP。

MVC是什么?

MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分

  • 模型(Model):模型表示应用程序的数据和业务逻辑
  • 视图(View):视图负责展示模型中的数据给用户,并接受用户的输入
  • 控制器(Controller):控制器作为模型和视图之间的中介,处理用户的请求并协调模型和视图的交互

在浏览器输入网址后请求的过程?

在浏览器输入一个网址后,以下是请求的一般过程:

  1. DNS解析:浏览器首先会解析输入的网址中的域名部分,将域名解析为对应的IP地址。浏览器会向本地DNS服务器发送查询请求,如果本地DNS服务器没有缓存该域名对应的IP地址,则会向根DNS服务器逐级查询,最终获取到目标服务器的IP地址。
  2. 建立TCP连接:浏览器使用HTTP协议与目标服务器建立TCP连接。TCP连接的建立需要进行”三次握手”,即客户端向服务器发送连接请求,服务器回复确认连接请求,最后客户端再次回复确认。
  3. 向服务器发起HTTP请求:建立TCP连接后,浏览器会构建HTTP请求报文,包括请求行、请求头和请求体等信息。请求行中包含了请求方法(GET、POST等)、请求URL和协议版本等。请求头中包含了一些附加的信息,如Cookie、Referer、User-Agent等。请求体中通常包含了一些表单数据或上传的文件等内容。
  4. 服务器处理请求:目标服务器接收到浏览器发送的HTTP请求后,会进行请求的处理。服务器根据请求的URL找到对应的资源(如静态文件或动态程序),执行相应的操作。这可能涉及到数据库查询、业务逻辑处理等。
  5. 服务器发送HTTP响应:服务器处理完请求后,会生成HTTP响应报文,包括响应行、响应头和响应体等信息。响应行中包含了响应状态码(如200表示成功、404表示资源未找到等)和协议版本等。响应头中包含了一些附加的信息,如响应的内容类型、长度、缓存策略等。响应体中包含了服务器返回给浏览器的数据或页面内容。
  6. 接收响应并渲染页面:浏览器接收到服务器发送的HTTP响应后,会根据响应的内容进行页面渲染。如果响应是一个HTML页面,浏览器会解析HTML代码,并加载其中引用的其他资源(如CSS、JavaScript文件等)。最终,浏览器将页面展示给用户。
  7. 关闭TCP连接:当页面全部加载完成后,浏览器会关闭与服务器的TCP连接,释放资源。在后续的操作中,如果需要再次请求同一服务器的资源,浏览器会重新建立TCP连接。

MVC工作流程是什么?

MVC(Model-View-Controller)的工作流程如下:

  1. 用户发送请求:用户在浏览器中输入URL或者与应用程序进行交互,发送请求给服务器。
  2. 控制器接收请求:服务器接收到请求后,控制器(通常是一个Servlet)负责接收并处理请求。控制器根据请求的类型和参数,选择合适的处理方法。
  3. 模型处理请求:控制器根据请求的类型和参数,调用相应的模型来处理数据。模型负责处理业务逻辑,包括数据的获取、处理、验证、存储等操作。
  4. 视图展示数据:模型处理完数据之后,将处理结果返回给控制器。控制器根据处理结果选择适当的视图来展示数据。视图负责将数据渲染成可视化的界面供用户查看。
  5. 用户与视图交互:用户在浏览器中与视图进行交互,例如填写表单、点击按钮等。用户的操作可能会触发新的请求。

HTTP请求方式?

最常见的有四种:

  • GET:用于获取资源。
  • POST:用于新增或更新资源。
  • PUT:用于更新资源。
  • DELETE:用于删除资源。

HTTP常见响应码有哪些?

响应成功(200)、未找到(404)、客户端请求错误(400)、服务器内部错误(500)

  • 信息类(1XX):表示收到 http 请求,正在进行下一步处理,通常是一种瞬间的响应状态
  • 成功类(2XX):表示用户请求被正确接收、理解和处理
  • 重定向类(3XX):表示没有请求成功,必须采取进一步的动作
  • 客户端错误(4XX):表示客户端提交的请求包含语法错误或不能正确执行
  • 服务端错误(5XX):表示服务器不能正确执行一个正确的请求

GET和POST的区别?

GET和POST是HTTP协议中最常用的两种请求方法,它们之间有以下区别:

  • 用途不同:GET一般用来获取数据,POST一般用来添加或修改数据
  • 参数传递方式:GET请求将参数放在URL的后面,而POST请求则将参数放在请求体中。
  • 请求的安全性:由于GET方法直接暴露参数在URL中,安全性低;POST方法则将数据放在请求体中,相对更为安全
  • 请求长度限制:GET请求的参数长度有限制,具体根据浏览器和Web服务器的不同而不同,通常为2048字节。而POST请求的传输数据量没有限制。

POST和PUT的区别?

POST和PUT都是HTTP协议中常用的请求方法,它们之间的主要区别有以下几点:

  • 用途不同:POST一般用来添加或修改数据;PUT用于更新数据
  • 覆盖请求:POST不具备幂等性,每个请求都是独立的,多次调用相同的POST请求可能会创建多个相同的资源;PUT请求具备幂等性,多次调用相同的PUT请求只会对资源进行一次更新。

Session与Cookie的区别?

Session与Cookie是两种用来在Web应用中保持状态的机制。

  • 存储方式:Cookie的value只能存储字符串类型的数据,而Session的value可以存储任意类型的数据,包括对象和数组等复杂数据结构。
  • 存储位置:Cookie的数据存储在客户端。Session的数据存储在服务端
  • 安全性:Cookie在客户端容易受到窃取、截获和修改的风险,不安全;Session对客户端是不可见的,因此相对更安全一些。
  • 数据大小:Cookie的存储大小受到浏览器的限制,一般情况下最大只能存储约3KB的数据,而Session的数据存储大小受服务端内存的限制,一般没有明确的大小限制。
  • 销毁时机:Cookie的生命周期是当浏览器关闭的时候就消亡了,Session默认生命周期一般是30分钟,可以根据需要在服务器端进行配置。

转发与重定向的区别?

转发(Forwarding)和重定向(Redirect)是两种不同的HTTP请求处理机制,区别如下:

  1. 请求次数:转发只涉及一次请求,服务器接收到请求后直接将请求转发给其他资源进行处理;而重定向涉及两次请求,服务器接收到请求后返回特殊响应,告诉客户端去请求新的URL。
  2. 浏览器地址栏显示:转发时,浏览器地址栏仍然显示的是初始请求的URL;而重定向时,浏览器地址栏会显示新的URL。
  3. 完成过程:转发是在服务器端完成的,客户端不知道有转发的存在;而重定向是在浏览器端完成的,服务器告诉客户端去请求新的URL。

Tomcat是什么?

Tomcat(全名为Apache Tomcat)是一个开源的、轻量级的Web应用服务器,由Apache软件基金会开发和维护。

Tomcat有什么特点?

Tomcat具有以下几个主要特点:

  1. 轻量级:Tomcat是一个相对轻量级的Servlet容器,它具有较小的内存占用和快速启动的特点。由于其设计简单,它在资源消耗方面比一些其他大型JavaEE服务器(如WebLogic、WebSphere)更加节省。
  2. 独立性:Tomcat是一个独立的服务,可以独立于其他Web服务器(如Apache HTTP Server)运行。它可以作为独立的Servlet容器使用,也可以与其他Web服务器配合使用,通过反向代理或负载均衡实现更复杂的部署架构。
  3. 开源性:Tomcat是一个开源项目,代码完全公开,并且遵循Apache许可证。这意味着任何人都可以查看、使用和修改Tomcat的源代码,可以根据自己的需求进行定制和扩展,使得它具有较好的灵活性和可定制性。
  4. 可扩展性:Tomcat提供了可插拔的架构,允许用户通过添加或配置插件(例如Valve、Realm、Servlet等)来扩展其功能。这使得开发人员可以根据需要增加新的功能组件,或者替换默认的组件实现,以满足特定的需求。
  5. 易用性:Tomcat提供了一个简单易用的管理界面(Tomcat Manager),可以通过该界面对Web应用程序进行部署、启停和监控。它还支持热部署特性,在不重启服务器的情况下更新Web应用程序,方便开发和调试。无论是小型的个人网站还是大型的企业级应用,都可以选择Tomcat作为其运行环境。同时,许多Java Web框架都默认支持Tomcat,使得开发人员更容易上手和开发应用程序。
  6. 多协议支持:Tomcat不仅支持HTTP协议,还支持其他常用的网络协议,如HTTPS、AJP(Apache JServ Protocol)等。这使得Tomcat可以与其他应用程序和Web服务器进行协同工作,提供更灵活的部署方式。
  7. 多线程支持:Tomcat使用多线程技术来处理并发请求,提高系统的并发性能。它为每个请求创建一个独立的线程,这样可以同时处理多个请求,提升Web应用程序的吞吐量。
  8. 安全性支持:Tomcat提供了多种安全措施,例如基于角色的访问控制、SSL/TLS加密等。它通过配置文件和管理界面来管理用户认证、授权和安全设置,以确保Web应用程序的安全性。
  9. JSP支持:Tomcat还支持JavaServer Pages(JSP)技术。JSP是用于创建动态Web页面的Java标准,可以在其中嵌入Java代码和HTML标记。Tomcat可以编译和执行JSP页面,将其转化为Servlet并进行处理,从而生成最终的HTML响应。
  10. Java WebSocket支持:Tomcat对Java WebSocket API提供了支持,可以加载和执行WebSocket相关的类和方法,从而实现WebSocket通信功能。开发人员可以使用Tomcat来构建实时的双向通信应用程序。
  11. Servlet容器:Tomcat作为一个Servlet容器,它能够加载、实例化和管理Servlet组件。它接收来自客户端的HTTP请求,并将请求转发给相应的Servlet进行处理,然后将处理结果返回给客户端。Tomcat负责管理Servlet的生命周期、线程处理和请求-响应的过程。

Tomcat有什么作用?

Tomcat作为一个Servlet容器,在Java Web开发中具有以下主要作用:

  1. 提供Servlet容器环境:Tomcat是一个Servlet容器,遵循Java Servlet规范,能够运行Java编写的Servlet代码。
  2. 提供Servlet管理:Tomcat可以管理和处理Servlet的生命周期,包括初始化、加载、调用和销毁。
  3. 提供连接池管理:Tomcat可以管理数据库连接池,提供了一组API和配置选项,用于管理数据库连接的创建、复用和回收,从而提高数据库访问的效率和性能。
  4. URL映射:Tomcat接收来自客户端的HTTP请求,URL映射将客户端请求转发给相应的Servlet进行处理。这样,开发人员可以根据URL的不同将请求分发到不同的Servlet,实现灵活的请求处理机制。
  5. 运行JSP页面:Tomcat内置了JSP引擎,可以将JSP页面编译成Servlet,并在运行时动态地生成HTML响应。开发人员可以使用JSP编写动态的Web页面,通过Tomcat来解析和执行这些JSP页面。
  6. 处理静态资源:除了动态生成的Servlet和JSP页面,Web应用程序还可能包含静态资源,如HTML、CSS、JavaScript、图片等。Tomcat可以直接处理这些静态资源的访问,并将其发送给客户端,无需额外的配置或处理。
  7. Web应用部署:Tomcat提供了一个简单易用的管理界面(Tomcat Manager),允许用户对Web应用程序进行部署、启停和监控。开发人员可以通过Tomcat Manager来管理多个Web应用程序,进行版本管理和灰度发布等操作。

Servlet是什么?

Servlet在Java Web开发中扮演着重要的角色,是一种用于在Web服务器上运行的Java程序组件

  • 狭义Servlet:指Java语言中的javax.servlet.Servlet接口,这个接口定义了处理客户端请求和生成响应的方法
  • 广义Servlet:指任何实现了javax.servlet.Servlet接口的类,包括通过实现该接口或继承已有实现的类来创建的Servlet类。

Servlet运行在服务器端,主要作用是使用Java语言与Servlet容器(如Tomcat)进行交互,处理Web请求和生成Web响应。

  1. 处理Web请求:Servlet可以接收来自客户端的HTTP请求,并根据请求的内容进行相应的处理。它可以读取请求参数、处理表单数据、解析请求头等。通过编写Servlet类,开发者可以定义自己的业务逻辑来处理不同类型的请求。
  2. 生成Web响应:Servlet可以根据业务逻辑和请求内容动态生成HTTP响应。它可以生成HTML页面、JSON数据、XML文档等各种形式的响应内容。开发者可以通过设置响应状态码、头信息和内容体等来构建合适的响应,以满足客户端的需求。

Servlet容器是什么?

  1. Servlet是一种用于在Web服务器上基于Java语言编写的服务器端程序,本身不能独立运行,需要在支持Servlet规范的容器中才能被加载和执行
  2. Servlet容器,也称为Web容器或Servlet引擎,提供了运行和管理Servlet的环境,可以加载和执行Java编写的Servlet代码
  3. 常见的Servlet容器有Apache Tomcat、Jetty、IBM WebSphere和Oracle WebLogic等。这些容器实现了Servlet规范,可以加载和执行Java编写的Servlet代码

为什么将Tomcat称为Servlet容器?

Tomcat被称为Servlet容器,是因为它是支持Java Servlet规范的Web服务器,提供了运行Servlet代码的环境,能够管理Servlet的生命周期,包括初始化、加载、调用和销毁。

Servlet生命周期

Servlet生命周期指的是Servlet对象从创建到销毁的整个过程,它由Servlet容器来管理。

  1. 加载和实例化:当Servlet容器启动或者在首次请求到达时,会加载Servlet类的字节码文件,并实例化Servlet对象将其保存在内存中,以便后续使用。
  2. 初始化:在Servlet实例化后,Servlet容器会调用Servlet的init()方法进行初始化操作。在init()方法中,可以进行一些必要的准备工作,如读取配置文件、建立数据库连接等。init()方法在Servlet的生命周期中只会被调用一次
  3. 服务:一旦Servlet初始化完成,就可以接收客户端的请求了,每当有请求到达时,Servlet容器会创建一个新的线程,并在该线程上调用Servlet的service()方法,service()方法会根据请求的类型(GET、POST等)调用相应的doGet()、doPost()等方法来处理具体的业务逻辑。service()方法在Servlet的生命周期中每次客户端发送请求都会调用
  4. 销毁:当Servlet容器关闭或者Web应用程序被卸载时,会触发Servlet的销毁过程,此时,Servlet容器会调用Servlet的destroy()方法来销毁Servlet实例。在destroy()方法中,可以进行一些清理工作,如释放资源、关闭数据库连接等。destroy()方法在Servlet的生命周期中只会被调用一次

JavaWeb三大组件是什么?

JavaWeb 的三大组件分别是Servlet程序、Filter过滤器、Listener 监听器

  • Servlet 程序:Servlet 是在服务器端运行的 Java 类,用于接收客户端的请求并生成响应。
  • Filter 过滤器:Filter 是用于对请求和响应进行预处理和后处理的组件。
  • Listener 监听器:Listener 是用于监听 Web 应用中事件发生的组件。

Filter是什么?

过滤器(Filter)用于对请求和响应进行预处理和后处理。当客户端发送请求时,过滤器会先执行,然后再将请求传递给目标Servlet进行处理。同样,在目标Servlet处理完请求后,过滤器还可以对响应进行处理,最后将响应返回给客户端。

Listener是什么?

Listener监听器用于监听Web应用中的事件,并在事件发生时执行相应的操作。它实现了一种观察者模式,用于观察和响应特定的事件。

三层架构是什么?

三层架构是一种软件设计模式,将应用程序按照功能和责任划分为三个独立的层次,每个层次都有自己的职责和功能,且彼此之间独立操作,提高了系统的可维护性、可扩展性和可测试性。通常由以下三个层级组成:

  • 表示层(Presentation Layer):表示层是系统与用户进行交互的界面部分,包括用户界面(如Web页面、移动应用界面、桌面应用界面等)和用户输入处理逻辑。主要作用是将用户的请求传递给业务逻辑层,并将处理结果展示给用户
  • 业务逻辑层(Business Logic Layer):业务逻辑层是应用程序的核心部分,包含了应用程序的业务规则、算法、流程等。主要作用是处理来自表示层的请求,调用数据访问层提供的数据实现系统的业务逻辑
  • 数据访问层(Data Access Layer):数据访问层是与数据存储系统(如数据库或文件系统)交互的部分,包括数据的存储、检索、更新等操作。主要作用是与数据存储系统(如数据库或文件系统)交互进行交互,执行对数据的增删改查等操作,并将操作结果返回给业务逻辑层

Linux

Linux常用命令?

  1. ls:列出当前目录下的文件和子目录。
  2. cd:切换当前工作目录。
  3. pwd:显示当前工作目录的路径。
  4. mkdir:创建新目录。
  5. rm:删除文件或目录。
  6. cp:复制文件或目录。
  7. mv:移动文件或目录,或重命名文件或目录。
  8. cat:显示文件内容。
  9. ps:显示当前运行的进程。
  10. kill:终止进程。
  11. chmod:修改文件或目录的权限。
  12. reboot:重新启动系统。
  13. ping:向指定的目标发送网络数据包以测试连接。
  14. ifconfig:显示和配置网络接口。
  15. wget:从网络下载文件。

Linux怎么看进程号?

ps命令:ps命令用于列出当前正在运行的进程信息。可以使用不同的选项来获取所需的输出。

1
2
3
4
5
6
7
8
# 以全格式显示所有进程信息,包括进程号(PID)
ps aux
# 以全格式显示所有进程信息,包括进程号(PID)
ps -ef
# 列出所有正在运行的进程,仅显示进程号(PID)
ps -e
# 仅显示进程号(PID)和命令
ps -eo pid,cmd

top命令:top命令用于实时查看系统资源占用情况,并且可以显示进程号(PID)

1
2
# 实时查看系统资源占用情况
top

pgrep命令:pgrep命令用于根据进程的名称查找相应的进程号(PID)

1
2
# 根据进程名查找对应的进程号(PID)
pgrep firefox

Linux怎样给文件授权?

在Linux中,可以使用chmod命令来给文件或目录设置权限。

  • 符号模式:每个字符代表一类用户(所有者、群组、其他用户)以及权限类型(读取、写入、执行)。所有者(u)、群组(g)、其他用户(o)、所有用户权限(a,相当于u+g+o)、添加(+)、移除(-)、设置(=)

  • 数字模式:数字模式是使用数字来表示权限的方式。每个数字代表一类用户以及对应的权限。每个用户类别的权限可以通过将其对应的数值相加得到。其中4表示读权限、2表示写权限、1表示执行权限。而0表示没有任何权限。

1
2
3
4
# 给文件file.txt的所有者添加读、写、执行权限。
chmod u+rwx 文件
# 给文件设置权限为:所有者 具有 读、写、执行 权限(7), 群组和其他用户 具有 读、执行 权限(5)
chmod 755 文件

Mybatis

Mybatis是什么?

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

Mybatis的${}和#{}区别?

${}:字符串拼接,存在SQL注入的风险。

#{}:标记占位符,可以防止SQL注入攻击。

Mybatis常用标签?

MyBatis是一个Java持久化框架,提供了许多用于编写SQL映射的标签。以下是MyBatis中常用的一些标签:

  1. <select>:用于执行查询操作的标签。
  2. <insert>:用于执行插入操作的标签。
  3. <update>:用于执行更新操作的标签。
  4. <delete>:用于执行删除操作的标签。
  5. <resultMap>:定义结果集的映射关系的标签。
  6. <association>:用于处理一对一关联关系的标签。
  7. <collection>:用于处理一对多或多对多关联关系的标签。
  8. <if>:条件判断标签,根据条件动态生成SQL。
  9. <choose><when><otherwise>:条件选择标签,根据多个条件选择不同的分支。
  10. <foreach>:用于循环遍历集合或数组,并在SQL语句中使用遍历的元素。
  11. <trim><where><set>:用于处理动态SQL的标签,可以去除多余的空格和逗号。
  12. <include>:用于将其他XML文件中定义的SQL片段包含进来,实现代码复用。
  13. <sql>:用于定义可重用的SQL片段的标签。

ResultType和ResultMap的区别?

resultType:用于指定查询结果的返回类型

resultMap:用于定义复杂的对象映射关系。

Mybatis是如何实现分页的?

使用数据库方言:例如使用MySQL中的limit关键字,在配置文件里面直接写分页SQL

1
2
3
<select id="getUserList" resultType="User">
SELECT * FROM user_table LIMIT #{offset}, #{limit}
</select>

使用 RowBounds 类:使用Mybatis提供的RowBounds对象,实现逻辑分页,也就是一次性加载所有符合查询条件的目标数据,根据分页参数值在内存中实现分页。这种方式不适合数据量较大的场景,而且有可能会频繁访问数据库造成比较大的压力

1
2
3
// offset 表示起始行,limit 表示返回的行数
RowBounds rowBounds = new RowBounds(offset, limit);
List<User> userList = sqlSession.selectList("getUserList", null, rowBounds);

Interceptor拦截器实现:通过拦截需要分页的select语句,然后在这个sql语句里面动态拼接分页关键字,从而实现分页查询。

使用插件:PageHelper是一个第三方实现的分页拦截器插件,使用起来灵活且方便。本质上也是使用Mybatis的拦截器来实现的。

Mybatis中物理分页(数据库分页)与逻辑分页(内存分页)

物理分页(数据库分页):使用SQL语句实现的分页,直接使用limit关键字实现的分页查询。PageHelper分页插件通过拼接 limit 实现,属于物理分页。MP的分页插件 PaginationInterceptor 通过拼接 limit 实现,属于物理分页

逻辑分页(内存分页):先查询数据到内存,在内存中进行分页。Mybatis自带的分页方案是通过 RowBounds 实现,属于逻辑分页。

Mybatis的分页插件运行原理?

MyBatis插件的运行是基于JDK 动态代理 + 拦截器链实现,步骤如下

  • 拦截器拦截SQL:在执行SQL之前拦截器拦截
  • 修改SQL加上分页:在拦截逻辑中,对 SQL 进行修改,添加limit 分页
  • 执行目标方法:执行目标方法

Mybatis的执行流程?

MyBatis的执行流程主要包括以下几个步骤:

  1. 加载配置文件:MyBatis会读取并解析配置文件,其中包含了数据库连接信息、映射关系配置等重要内容。
  2. 创建SqlSessionFactory会话工厂对象:根据配置文件的内容,MyBatis会创建一个SqlSessionFactory对象,它是MyBatis的主要入口,用于创建SqlSession对象。
  3. 会话工厂创建SqlSession会话对象:通过SqlSessionFactory打开一个SqlSession对象,SqlSession是与数据库交互的核心接口,可以进行数据库操作。
  4. 创建操作数据库的接口Executor执行器对象:SqlSession内部通过Executor执行器来实际执行SQL语句,它负责与数据库进行交互,执行SQL并处理结果。
  5. 构建MappedStatement对象封装映射信息:在执行SQL之前,MyBatis会根据接口方法的映射配置,构建一个MappedStatement对象,其中包含了SQL语句、参数映射、结果映射等信息。
  6. 执行SQL语句:Executor执行器根据MappedStatement中的配置信息,执行相应的SQL语句,并将查询结果或影响行数返回给调用方。
  7. 封装返回结果:根据配置的结果映射,MyBatis会将查询结果封装成Java对象或集合,并返回给调用方。
  8. 关闭SqlSession:在完成数据库操作后,需要手动关闭SqlSession,释放资源。可以通过调用SqlSession的close()方法来关闭。

Mybatis是否支持延迟加载?

MyBatis支持延迟加载(Lazy Loading)的功能。延迟加载是指在访问对象的某个属性时才去加载该属性的数据,而不是一次性将所有关联数据都加载到内存中。

在MyBatis中,可以通过配置来实现延迟加载。具体的实现方式有两种:

基于属性配置的延迟加载:可以在映射文件中对需要延迟加载的属性进行配置。通过在查询语句中使用fetchType="lazy"或者fetchType="lazy"来标识延迟加载。

1
<result property="author" column="authorId" select="selectAuthorById" fetchType="lazy"/>

基于关联关系的延迟加载:可以配置一对一、一对多等关联关系,并通过associationcollection元素来添加关联属性。通过设置fetchType="lazy"来实现延迟加载。当访问关联对象时会触发加载。

1
<association property="author" column="authorId" select="selectAuthorById" fetchType="lazy"/>

Mybatis的一级、二级缓存?

默认情况下,MyBatis的二级缓存是基于内存的,但也支持集成第三方缓存框架如Redis、Ehcache等。

一级缓存

  • 一级缓存是MyBatis默认开启的,不需要手动配置,作用域是同一个SqlSession。

  • 在同一个SqlSession中,如果执行相同的查询操作,MyBatis会首先去检查一级缓存中是否已经存在该查询结果。如果存在则直接从一级缓存中获取结果,而不会再向数据库发送查询请求,从而提高了查询速度。

  • 一级缓存底层实际上是在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

1
2
3
4
5
6
7
8
9
10
11
// 获取SqlSession对象,用它来执行sql,只需要保持同一个SqlSession对象,MyBatis就会自动启用一级缓存
SqlSession sqlSession = sqlSessionFactory.openSession(true);

// 获取UserMapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

// 第一次查询操作,会从数据库中查询数据,并将结果保存到一级缓存中
User user1 = userMapper.selectUserById(1);

// 第二次查询操作,同一个 SqlSession 中,再次执行相同的查询,会直接从一级缓存获取结果,而不会再向数据库发送查询请求
User user2 = userMapper.selectUserById(1);

二级缓存

  • 二级缓存需要手动配置开启,作用域是同一个命名空间(Mapper接口)下的多个SqlSession之间的共享缓存,不同的命名空间之间的缓存是独立的,同一个命名空间下的多个SqlSession可以共享缓存数据。

  • 当执行一个查询语句时,如果启用了二级缓存,MyBatis会首先去检查二级缓存中是否已经存在该查询结果。如果命中缓存,则直接从缓存中获取结果,而不会再向数据库发送查询请求;如果未命中缓存,则执行查询操作,并将结果保存到二级缓存中。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 获取SqlSession对象,用它来执行sql
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);

// 获取UserMapper的代理实现类对象
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);

// 第一次查询操作,会从数据库中查询数据,并将结果保存到二级缓存中
User user1 = userMapper1.selectUserById(1);

// 第二次查询操作,不同的 SqlSession 中,再次执行相同的查询,会直接从二级缓存中获取结果,而不会再向数据库发送查询请求
User user2 = userMapper2.selectUserById(1);

MybatisPlus是什么?

MybatisPlus(简称MP)是 Mybatis 的增强工具,在 Mybatis 的基础上封装了更多的功能,简化了开发流程,提高了开发效率。MybatisPlus 提供了许多实用的功能,包括:

  1. 简化的 CRUD 操作:MybatisPlus 提供了一系列的通用 CRUD 方法,无需编写 SQL 语句,只需定义实体类和 Mapper 接口即可进行数据库的增删改查操作。
  2. 自动注入:MybatisPlus 可以自动生成实体类的主键策略,如自增、UUID、雪花算法等,并自动注入创建时间、更新时间等字段值。
  3. 自动填充:MybatisPlus 支持自动填充功能,可以在插入或更新数据时,自动填充一些固定的字段值,如创建人、更新人等。
  4. 分页查询:MybatisPlus 提供了简单易用的分页查询功能,可以方便地进行分页查询操作。
  5. 条件构造器:MybatisPlus 提供了强大的条件构造器,可以通过链式调用的方式拼接查询条件,避免手动拼接 SQL 语句带来的问题。
  6. 逻辑删除:MybatisPlus 支持逻辑删除功能,即在删除数据时,不是真正地删除数据,而是将删除标记设置为一个特定的值,以便后续恢复或查看删除记录。
  7. 乐观锁插件:MybatisPlus 内置了乐观锁插件,可以实现乐观锁的功能,解决并发更新数据时的数据一致性问题。

MybatisPlus的常用注解?

MybatisPlus 提供了一些常用的注解,用于简化开发过程和增强功能

  1. @TableName:用于指定实体类对应的数据库表名,可以在实体类上使用。示例:@TableName(“user”)
  2. @TableId:用于指定实体类的主键字段,可以与 @TableName 注解一起使用,也可以单独使用。示例:@TableId(value = “id”, type = IdType.AUTO)
  3. @TableField:用于指定实体类属性与数据库字段的映射关系,可以在实体类的属性上使用。示例:@TableField(“user_name”)

Spring

Spring是什么?

Spring一般是指Spring Framework,是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。

Spring包含的模块有哪些?

Spring Framework包含了很多模块,常见的有

  1. Spring Core(核心):提供了 Spring 框架的基本组成部分,包括 IoC(控制反转)和 DI(依赖注入)等功能。
  2. Spring Context(上下文):建立在核心模块之上,为应用程序提供了大量的企业级服务,例如国际化、事件传播、资源加载和声明式事务管理等。
  3. Spring AOP(面向切面编程):通过 AOP 提供了方法拦截和声明式事务管理等能力。
  4. Spring JDBC(数据库访问):提供了简化的 JDBC 操作接口,使得数据库访问更加方便。
  5. Spring ORM(对象关系映射):支持集成流行的 ORM 框架,如 Hibernate、MyBatis 等。
  6. Spring Web(Web 开发):提供了创建 Web 应用程序的功能,包括 Web MVC、RESTful 服务等。
  7. Spring Test(测试):提供了对 Spring 应用程序进行单元测试和集成测试的支持。
  8. Spring Security(安全):用于身份验证和授权等安全相关的功能,帮助保护应用程序的安全性。
  9. Spring WebFlux(反应式编程):基于 Reactor 框架提供了响应式编程模型,支持构建高性能的异步非阻塞 Web 应用程序。
  10. Spring Data(数据访问):简化数据访问层的开发。提供了一种统一的、基于注解的编程模型,以及许多通用的功能和增强特性,使得与各种数据存储技术(如关系型数据库、NoSQL 数据库、搜索引擎等)集成变得更加容易。

IOC是什么?

控制反转IOC(Inversion of Control),是一种设计思想,把对象的创建、赋值、管理的工作都交给代码之外的容器(Spring容器)实现,而不是由自己来创建和管理依赖对象,使资源可以配置和集中管理,降低了使用资源双方的依赖程度(耦合度)

  • 自己创建和管理对象:在面向对象编程(OOP)中,对象的创建通常会采用new 类名的方式手动完成,这种方式会使得调用者与被调用者之间的耦合性增加,不利于后期项目的升级和维护
  • 容器创建和管理对象:在Spring中,通过在xml配置文件(容器)中使用标签配置对象,将对象的创建、赋值和生命周期的管理等工作全部交给容器来完成,降低组件之间的耦合度,使得应用程序更加灵活、可扩展、易于维护

AOP是什么?

AOP(面向切面编程)是一种编程范式。通过将的代码逻辑封装成切面(Aspect),并在运行时通过动态代理技术将这些切面织入到目标方法中,从而实现不修改源代码的情况下对目标方法进行增强的效果,常见的应用场景有日志记录、事务管理、缓存优化、安全控制、异常处理等。在Spring框架中,提供了JDK动态代理和CGLIB动态代理两种方式来实现AOP(面向切面编程)。具体使用哪种代理方式取决于被代理的对象是否实现了接口。

  • JDK动态代理如果被代理的对象实现了接口,Spring AOP会使用JDK动态代理来创建代理对象。JDK动态代理是通过反射机制,在运行时动态生成一个实现被代理接口的代理类,并将方法的调用委托给目标对象执行。
  • CGLIB动态代理如果被代理的对象没有实现接口,Spring AOP会使用CGLIB动态代理来生成一个被代理对象的子类作为代理对象。CGLIB(Code Generation Library)是一个强大的高性能代码生成库,它通过在运行时生成目标类的子类来实现代理。
  • AspectJ框架:除了JDK动态代理和CGLIB动态代理,Spring还支持使用AspectJ框架来实现AOP。AspectJ是一个独立的AOP框架,它使用编译时或者运行时的字节码增强,可以更灵活地实现切面功能。

DI是什么?

依赖注入(Dependency Injection,DI)是控制反转(IOC)技术的实现方式,其核心思想是让容器来负责对象的创建和管理,并在需要使用这些对象时主动将它们注入到目标对象中,注入一个对象时,容器会自动扫描类路径下所有的组件对象,找到与该对象类型匹配的组件对象,并将其自动注入到目标对象中

依赖注入(DI)怎么实现?

在Spring框架中,有三种主要的依赖注入方式:

  1. 构造函数注入:通过构造函数来注入依赖。在类的构造函数中声明依赖的参数,并在创建对象时传入相应的依赖对象。
  2. Setter 方法注入:通过 setter 方法来注入依赖。在类中定义一个 setter 方法,通过该方法设置依赖对象。
  3. 接口注入:通过对象实现特定接口,在接口中定义注入依赖项的方法,在程序运行时通过接口方法注入依赖项。
  4. 注解注入:通过注解来注入依赖。在类中使用特定的注解标记依赖对象,并在容器或框架中进行相应的配置,以实现依赖的注入。

自动装配是什么?

自动装配(Autuwiring)是Spring框架中实现依赖注入的一种方式。它可以自动地将需要依赖的对象注入到目标对象中,而无需手动配置每个对象之间的依赖关系。

自动装配怎么实现?

Spring的自动装配可以分为基于XML配置和基于注解两种情况

基于XML配置

在XML配置文件中,可以使用<bean>元素来定义Bean,并利用<property>元素或<constructor-arg>元素来指定依赖关系。通过设置autowire属性为”byType”或”byName”,可以实现自动装配。

  1. 不使用自动注入(默认):当不设置autowire属性或将其设置为默认值时,不会进行自动注入。需要手动在XML配置文件中通过<property>元素或<constructor-arg>元素指定依赖关系。
  2. 根据类型(byType):通过将autowire属性设置为”byType”,容器会根据依赖类型自动装配。在需要注入的Bean类中,如果存在与依赖类型匹配的Bean,则自动将其注入。
  3. 根据名称(byName):通过将autowire属性设置为”byName”,容器会根据依赖名称自动装配。在需要注入的Bean类中,如果存在与依赖名称匹配的Bean,则自动将其注入。
  4. 构造器(constructor):使用构造函数注入依赖关系。通过<constructor-arg>元素在XML配置文件中指定构造函数参数的值或引用。这是一种主动的方式,需要显式地定义构造函数并传递依赖项。
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 默认不使用自动注入,需要显式地指定依赖关系。 -->
<bean id="userRepository" class="com.example.UserRepositoryImpl" />

<!-- 根据类型注入,通过设置autowire属性为"byType" -->
<bean id="userService" class="com.example.UserService" autowire="byType" />

<!-- 根据名称注入,通过设置autowire属性为"byName" -->
<bean id="userService" class="com.example.UserService" autowire="byName" />

<!-- 使用构造器注入,通过<constructor-arg>元素指定依赖 -->
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userRepository" />
</bean>

基于注解

使用注解可以更方便地进行自动装配,减少了大量的XML配置。使用注解实现自动装配时,需要在配置文件中启用注解扫描或者使用@ComponentScan注解来指定扫描的基础包或类。

在配置文件中启用注解扫描:

1
<context:component-scan base-package="com.example" />

使用@ComponentScan注解来指定扫描的基础包或类:

1
2
3
4
5
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// 配置其他的Bean
}

常用的自动装配注解有:

  • @Autowired:用于标记需要自动装配的字段、构造器或方法。
  • @Qualifier:结合@Autowired使用,用于指定具体的Bean名称。
  • @Resource:类似于@Autowired,但更灵活地支持根据名称或类型进行自动装配。
  • @Inject:与@Autowired类似,也可以用于自动装配。但是需要注意的是,@Inject是Java规范提供的注解,而@Autowired是Spring框架特有的。

@Autowired和@Resouce的区别?

@Autowired@Resource 都是常见的用于依赖注入的注解

  • @Autowired :Spring 框架提供的注解,按照类型进行依赖查找和注入,当多个 Bean 类型匹配时,可以通过 @Qualifier 注解指定具体的 Bean 名称。
  • @Resource :JDK 提供的注解,按照名称进行依赖查找和注入,当多个 Bean 名称匹配时,可以通过 name 属性指定具体的 Bean 名称

Bean是什么?

Bean 指由 Spring 容器管理的对象。Spring Bean 提供了一种依赖注入(Dependency Injection)的机制,通过将 Bean 注入到其他对象中,实现了对象之间的解耦。

Bean怎么声明?

XML 配置文件声明 Bean

在 XML 配置文件中使用 <bean> 标签来声明一个 Bean。

1
2
3
4
5
6
<bean id="userService" class="com.example.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.example.UserDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

注解声明 Bean

在 Spring 4.x 版本之后,可以使用 @Component@Service@Controller@Repository@Configuration 等注解来声明 Bean。

1
2
3
4
5
@Repository
public class UserDaoImpl implements UserDao {}

@Service
public class UserServiceImpl implements UserService {}

Bean生命周期?

实例化—>依赖注入(属性赋值)—>前置处理(初始化前的操作)—>初始化—>后置处理(初始化后的操作)—>使用—>销毁

  1. 实例化(Instantiation):在这个阶段,Spring 容器根据配置信息创建 Bean 的实例,通常使用构造函数来实例化对象。
  2. 依赖注入(Dependency Injection):在实例创建完成后,Spring 容器会通过 setter 方法或构造函数来注入所需的依赖项,即属性赋值。
  3. 前置处理(Post Process Before Initialization):在初始化之前,Spring 提供了一些扩展点,可以在 Bean 初始化之前对其进行自定义操作。例如,可以通过实现 BeanPostProcessor 接口来创建前置处理器,以在初始化之前对 Bean 进行自定义修改。
  4. 初始化(Initialization):在这个阶段,Spring 容器会对 Bean 进行初始化,包括调用初始化方法和设置其他相应的配置信息。可以通过实现 InitializingBean 接口或在配置文件中指定 init-method 属性来定义初始化方法。
  5. 后置处理(Post Process After Initialization):在初始化完成后,Spring 提供了另一个扩展点,可以在 Bean 初始化之后对其进行自定义操作。与前置处理类似,可以通过实现 BeanPostProcessor 接口来创建后置处理器。
  6. 使用(Bean in Use):在初始化完成后,Bean 可以被应用程序使用。在这个阶段,Bean 将服务于它所属的对象或应用程序。可以调用 Bean 的方法、访问其属性等。
  7. 销毁(Destroy):当应用程序关闭或销毁 Spring 容器时,Spring 容器会触发 Bean 的销毁过程。可以通过实现 DisposableBean 接口或在配置文件中指定 destroy-method 属性来定义销毁方法。

Bean的作用域有哪些?

Spring官方文档介绍的Bean作用域:单例(Singleton)原型(Prototype)、请求(Request)、会话(Session)、应用上下文(Application)、Websocket

  1. Singleton(单例):默认的作用域。在整个应用程序中,只会存在一个 Bean 实例。无论何时都会返回相同的实例引用。
  2. Prototype(原型):每次通过容器获取该 Bean 时,都会创建一个新的实例。因此,每次获取的实例都是独立的。
  3. Request(请求):在每次 HTTP 请求到达时,都会创建一个新的 Bean 实例。该实例仅在当前 HTTP 请求范围内有效,不同请求之间不共享。
  4. Session(会话):在每个用户会话期间只创建一个 Bean 实例。即使是同一用户的不同请求,也会共享同一个 Bean 实例。
  5. Application(应用上下文):在整个 Web 应用程序生命周期中,只会存在一个 Bean 实例。不同 HTTP 请求之间共享同一个 Bean 实例,但不同 Web 应用程序之间不共享。
  6. Websocket:在每个 WebSocket 连接期间只创建一个 Bean 实例。即使是同一连接的不同请求,也会共享同一个 Bean 实例。

Bean是线程安全的吗?

Bean是否线程安全取决于Bean的作用域,默认情况下,Bean的作用域是单例作用域,线程不安全。

  • 单例作用域:线程不安全。Bean只会创建一个实例,任何实例都共享这个实例。
  • 原型作用域:线程安全。每次获取时都会创建一个新的Bean,不同线程获取的实例是独立的,不会共享数据。
  • 请求作用域:线程安全。每个请求时创建一个新的实例,不同请求之间的实例不会共享。
  • 会话作用域:线程不安全。每个用户会话期间只有一个实例,多个请求共享同一个实例。
  • 应用上下文作用域:线程不安全。在整个应用程序生命周期中只有一个实例,多个线程共享同一个实例
  • Websocket作用域:线程不安全。每个 WebSocket 连接期间只有一个实例,多个请求共享同一个实例。

BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext都是Spring框架中用于管理和创建Bean对象的接口

  • BeanFactory:Spring的早期接口,称为Spring的Bean工厂,提供了最基本的Bean容器功能,包括Bean的注册、创建、依赖注入和生命周期管理等
  • ApplicationContext:是BeanFactory的扩展,对BeanFactory进行了封装,提供了更多的功能,例如自动装配、AOP支持等。

循环依赖是什么?

循环依赖是指在Spring容器中,两个或两个以上Bean之间相互依赖,形成环形依赖结构的情况。

循环依赖怎么解决?

大部分的循环依赖问题Spring内部会使用三级缓存进行解决。当发现循环依赖时,Spring会尝试通过以下步骤解决:

  1. 创建早期的对象引用:当一个Bean A依赖于另一个Bean B时,Spring会先创建Bean A的实例,并将其放入三级缓存中。这个实例是一个未完成初始化的早期对象。
  2. 注入早期的对象引用:接着,Spring会开始创建Bean B,并将早期的Bean A的引用注入到Bean B中,同时将Bean B也放入三级缓存中。
  3. 解析循环依赖:当Bean B依赖于Bean A的其他属性时,Spring会检测到循环依赖关系,并尝试从三级缓存中获取已经创建的早期对象引用。
  4. 提前暴露Bean引用:如果在三级缓存中找到了早期对象引用,Spring会将其提前暴露给其他需要引用它的Bean,以解决循环依赖。
  5. 完成Bean的创建:最后,Spring会继续完成Bean的创建和初始化过程,包括调用初始化方法和设置其他属性等。

三级缓存是什么?

三级缓存是Spring框架中用于解决循环依赖问题的一种机制。创建Bean的时候,优先从一级缓存获取对象,如果没有,就从二级缓存中获取,如果还没有,就尝试从三级缓存获取ObjectFactory来创建对象

  • 一级缓存:单例池,缓存已经经历了完整的生命周期,已经初始化完成的Bean对象
  • 二级缓存:缓存早期的Bean对象(生命周期还没走完)存储半成品的bean对象
  • 三级缓存:缓存ObjectFactory(创建Bean的工厂实例),用来创建某个对象的工厂实例

事务是如何实现的?

Spring提供了两种管理事务的方式:编程式事务和声明式事务

  • 编程式事务:通过编写代码,显式地控制事务的开启、执行、提交、回滚以及手动释放资源等,可以灵活地控制事务的范围和行为,适用于对事务控制需求较复杂的场景。
  • 声明式事务:通过在XML配置文件中进行事务配置或使用@Transactional注解定义事务规则,将事务管理的责任交给Spring框架来处理,开发者只需要通过配置或注解的方式声明哪些方法需要进行事务管理,而不需要编写额外的代码来处理事务。

编程式事务和声明式事务优缺点?

编程式事务的优缺点:

  • 优点:可以灵活控制事务的开启、执行、提交、回滚以及手动释放资源等,实现细粒度的事务控制
  • 缺点:代码复杂度高,对代码有侵入性,容易出错

声明式事务的优缺点:

  • 优点:代码简洁、可读性强,配置灵活、易于维护
  • 缺点:不够灵活,最小粒度只能作用在方法上,需要注意事务的失效场景

@Transactional声明式事务为什么不推荐使用?

@Transactional使用不当可能会失效

  1. 只适用于公共方法:由于声明式事务是基于代理机制实现的,所以只能应用于公共(public)的方法上,而不能应用于私有(private)或受保护(protected)的方法。
  2. 类内部的自调用问题:在同一个类内部的一个方法自调用时,@Transactional注解可能无法生效。这是因为Spring事务默认是通过代理对象实现的,自调用时不会经过代理对象。
  3. 异常处理:声明式事务可以通过设置rollbackFor来指定哪些异常会回滚事务,但需要注意未捕获的异常可能无法被事务捕获,从而导致事务无法回滚。

@Transactional事务失效的场景有哪些?

@Transactional事务失效场景:

  • @Transactional 应用在非 public 修饰的方法上:事务只能被 public 方法拦截,如果将 @Transactional 注解应用在了非 public 方法上,那么该方法不会被事务拦截器拦截,从而导致事务失效。
  • 非事务方法调用事务方法:如果一个非事务方法调用了一个带有 @Transactional 注解的事务方法,那么事务将无法生效。
  • 事务方法内部调用事务方法:如果一个事务方法调用了另一个带有 @Transactional 注解的事务方法,其中两个方法属于同一个对象,则外层 @Transactional 注解会被忽略,内层的事务方法将以非事务方式执行。这是因为 Spring 默认使用 AOP 基于动态代理实现事务管理,同一对象中的方法调用不会触发代理对象上的拦截器。如果要实现嵌套事务,可以考虑使用基于 AspectJ 的编译时织入。
  • 异常未被捕获:如果在事务中的方法抛出了未被捕获的异常,而没有在方法内部进行处理或在上层调用栈中进行捕获和处理,事务将会失效。

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

Spring 框架中使用了多种设计模式,以下是其中一些主要的设计模式:

  • 单例设计模式:Spring容器默认使用单例模式管理Bean对象,保证整个应用程序中只有一个实例。
  • 工厂设计模式:Spring 使用工厂模式创建和管理 Bean 对象。即通过 BeanFactoryApplicationContext 创建 Bean 对象。
  • 代理设计模式:Spring AOP (面向切面编程)基于代理模式实现,使用代理模式在目标方法执行前、执行后或出现异常时插入横切逻辑,实现面向切面编程。
  • 模板方法模式:Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,使用到了模板模式。
  • 观察者模式:Spring事件驱动模型基于观察者模式。Spring 的事件机制允许对象注册为事件监听器,当某个事件发生时,这些监听器将被通知并执行相应的操作。这种机制实现了解耦,让对象之间能够松散地交互。
  • 适配器模式:Spring MVC 中的 HandlerAdapter 使用适配器模式,帮助将请求从 Servlet 容器适配到 Controller 方法,并支持多种不同的处理器。
  • 策略模式:Spring的资源访问策略和事务管理策略的选择是基于策略模式的。通过配置选择不同的策略实现类,可以根据需要动态地切换实现。

Spring、SpringMVC、SpringBoot之间的关系?

Spring 是一个全栈式的 Java 开发框架,提供了容器、AOP、事务管理、ORM、MVC 等众多功能,是一个非常强大的框架。

Spring MVC 是 Spring 框架中的一个模块,用于开发 Web 应用程序,提供了 MVC 模式的实现,可以很方便地处理 HTTP 请求和响应。

Spring Boot 是 Spring 框架的一个子项目,它可以帮助开发者快速搭建 Spring 应用程序,提供了自动配置、快速开发、独立运行等特性,可以大大提高开发效率。

Spring MVC的理解?

SpringMVC的执行流程?

前端控制器—>处理器映射器—>处理器适配器—>处理器—>视图解析器—>渲染视图并响应

  1. 客户端发送请求:客户端(浏览器)发送请求到服务器;
  2. 前端控制器拦截请求:Servlet 容器会将请求交给 Spring 的 前端控制器(DispatcherServlet),进行拦截请求,并委托给处理器映射器(HandlerMapping)进行处理
  3. 处理器映射器处理请求:处理器映射器(HandlerMapping)根据请求 URL 找到对应的 处理器(Controller)或 处理器链(HandlerExecutionChain)返回给 前端控制器(DispatcherServlet)
  4. 处理器适配器处理请求:前端控制器(DispatcherServlet)将找到的处理器(Controller)或 处理器链(HandlerExecutionChain)交给处理器适配器(HandlerAdapter)去调用合适的处理器(Controller)
  5. 处理器处理请求:处理器(Controller)执行业务逻辑,处理请求并生成模型数据,然后返回一个逻辑视图名(Logical View Name)或 ModelAndView 对象,返回给前端控制器(DispatcherServlet);
  6. 视图解析器解析视图:前端控制器(DispatcherServlet)将逻辑视图名或 ModelAndView 对象传递给视图解析器(ViewResolver),视图解析器根据逻辑视图名解析出一个具体的视图对象(如 JSP、Thymeleaf 或 FreeMarker 等)并响应给前端控制器(DispatcherServlet)
  7. 渲染视图并响应:前端控制器(DispatcherServlet)调用视图对象(View)的渲染方法,将模型数据填充到视图中,并生成最终的响应结果,将其返回给客户端(浏览器)。

过滤器与拦截器有什么区别?

功能定位

  • 监听器:主要用于监听和响应特定事件,对事件进行处理。
  • 过滤器:用于对请求进行预处理和后处理,对请求和响应进行筛选和修改。
  • 拦截器:在请求和响应的处理过程中,拦截并插入额外的逻辑来实现附加功能。

使用场景

  • 监听器:适用于需要侦听和响应应用程序中的事件的情况,如服务器启动/关闭、会话的创建/销毁等。
  • 过滤器:常用于对请求进行过滤和处理,如身份验证、请求参数处理、字符编码等。
  • 拦截器:通常用于在应用程序级别上实现横切关注点,如日志记录、权限验证、性能监控等。

执行顺序

  • 监听器:由事件的发生顺序决定的,是被动的组件,它通过事件监听机制等待特定事件的发生,并在事件触发时执行相应的处理逻辑
  • 过滤器:过滤器通常形成一个过滤器链(Filter Chain),按照配置的顺序依次执行
  • 拦截器:由框架或应用程序维护拦截器链,通过拦截器链中的调用顺序依次执行拦截器的前置和后置逻辑

技术实现

  • 监听器:使用事件监听机制,通过实现特定接口或注解来定义监听器,并在配置文件或代码中进行注册。
  • 过滤器:使用Servlet规范中的Filter接口,通过编写过滤器类并在配置文件中进行配置和映射。
  • 拦截器:通常由框架或应用程序提供,通过定义拦截器类,并在配置或代码中进行配置和使用。

SpringBoot自动装配原理

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

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

  • @ComponentScan

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

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

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

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

SpringBoot的启动过程?

Spring Boot的启动过程可以分为以下几个步骤:

  1. 加载启动类:Spring Boot通过Java的反射机制加载启动类(通常是带有@SpringBootApplication注解的类)。启动类是整个应用的入口点,它包含了Spring Boot的配置和启动逻辑。
  2. 启动应用上下文:Spring Boot创建并启动一个应用上下文(ApplicationContext)。应用上下文是Spring框架的核心容器,负责管理和组装各个Bean对象。
  3. 执行自动配置:Spring Boot会根据依赖和配置信息,自动配置应用的各项功能。自动配置是Spring Boot的核心特性之一,它通过条件判断和自动装配机制,根据应用的环境和依赖,智能地配置和初始化相关组件。
  4. 扫描和注册Bean:Spring Boot会扫描并注册所有标记有@Component、@Service、@Controller等注解的Bean对象。这些注解通过元数据的方式告诉Spring框架哪些类是需要被管理和使用的。
  5. 运行应用:Spring Boot在完成Bean的注册后,会执行一些应用的初始化和准备工作,例如加载配置文件、连接数据库等。最后,启动内嵌的Servlet容器(如Tomcat、Jetty等),并将应用部署到容器中,使应用可以响应外部请求。
  6. 应用就绪:一旦应用启动成功并完全初始化,Spring Boot会发送一个应用就绪的事件。开发者可以通过编写监听器来监听该事件,执行一些自定义的操作。

SpringBoot常用注解?

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

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

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

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

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