目录
1.SpringBoot 打成的jar包和普通的jar包有什么区别?
如何让SpringBoot打的jar包可依赖?
2. http 和 https 的区别?
一、安全性
二、连接方式
三、性能影响
四、应用场景
五、总结:
3. GC是什么,为什么要使用GC?
一、GC(Garbage Collection,垃圾回收)的概念
二、为什么要使用 GC
4. 排序有哪几种方法?说一说冒泡排序的原理。
一、常见的排序方法
二、冒泡排序的原理
以下是具体步骤:
5. 简述一下动态sql的执行原理
一、动态 SQL 的组成部分
二、执行原理
解析阶段:
生成 SQL 语句:
参数绑定和执行:
6. 什么是控制反转IOC?如何使用
IoC的基本概念
IoC的实现方式
7. 什么是AOP 应用场景是什么?
AOP的应用场景
AOP的实现原理
8. 什么是内存溢出,什么是内存泄漏
一、基本概念
二、内存溢出的常见情况
1、java.lang.OutOfMemoryError: PermGen space (持久带溢出)
2、java.lang.OutOfMemoryError: Java heap space (堆溢出)
3、虚拟机栈和本地方法栈溢出
三、内存溢出的原因及解决方法
内存溢出的解决方案
四、内存泄漏分类
五、内存泄漏的解决方法
六、总结
1.关系:
2.区别:
9. 静态代理和动态代理的区别?
1.创建时机
2.类型限制
3.灵活性
4.维护成本
5.适用场景
6.具体实现方式
10. 常见的http状态码是怎么分类的,列举常见的http状态码
1xx Informational(信息性状态码)
2xx Success(成功状态码)
3xx Redirection(重定向状态码)
4xx Client Error(客户端错误状态码)
5xx Server Error(服务端错误状态码)
后续的会下次更新 ...
[[[[ 10.25 续更... ]]]]
11. java中堆和栈的理解?
一、栈(Stack)
二、堆(Heap)
12. Spring 中的隔离级别?
ISOLATION_DEFAULT:
ISOLATION_READ_UNCOMMITTED(读未提交):
ISOLATION_READ_COMMITTED(读已提交):
ISOLATION_REPEATABLE_READ(可重复读):
ISOLATION_SERIALIZABLE(可串行化):
13. Spring事物的传播性?
14. 简述一下SpringMVC 的执行流程?
用户发起请求:
前端控制器(DispatcherServlet)接收请求:
处理器映射器(HandlerMapping)查找处理器:
处理器适配器(HandlerAdapter)调用处理器:
处理器(Controller)执行业务逻辑:
处理器返回模型和视图(ModelAndView):
视图解析器(ViewResolver)解析视图:
渲染视图并返回响应:
15. 如何处理SpringMVC 中的跨域问题?
一、使用@CrossOrigin注解
1.在控制器方法上添加@CrossOrigin注解:
2.在控制器类上添加@CrossOrigin注解
二、使用过滤器(Filter)
1. 创建过滤器类:
2. 在 Spring 配置中注册过滤器:
三、使用 Spring 的WebMvcConfigurer接口
16. 什么是SpringBoot? 有哪些优点?
一、Spring Boot 是什么
二、Spring Boot 的优点
快速开发:
独立可运行:
微服务友好:
生产就绪特性:
易于测试:
社区活跃:
17. SpringBoot 的 自动装配原理是什么?
@SpringBootConfiguration:
@EnableAutoConfiguration:
@ComponentScan:
19. SpringBoot 在启动的时候会做那几件事情?
加载引导类(Bootstrap Class)
20. Spring 、SpringBoot 、SpringMVC 有什么区别?
一、Spring
二、Spring Boot
三、Spring MVC
1.SpringBoot 打成的jar包和普通的jar包有什么区别?
Spring Boot 中打包成的 jar包:
Spring Boot 中默认打包成的 jar 叫做
可执行 jar
,这种jar包可以通过可以通过命令(java -jar xxx.jar)来运行的,但这种jar包不能被其他项目所依赖,因为它和普通 jar 的结构不同,即使被依赖了也不能直接使用其中的类。
普通的jar包:
普通的jar包,解压后直接就是包名,包里就是我们的代码,而 Spring Boot 打包成的可执行 jar 解压后,在 \BOOT-INF\classes 目录下才是我们的代码,因此无法被直接引用。 如果非要引用,可以在 pom.xml 文件中增加配置,将 Spring Boot 项目打包成两个 jar ,一个可执行,一个可引用。
如何让SpringBoot打的jar包可依赖?
在pom文件中增加以下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<!--可以把依赖的包都打包到生成的Jar包中 -->
<goal>repackage</goal>
</goals>
<!--可以生成不含依赖包的不可执行Jar包 -->
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
如下图,一次性打包生成两个jar,其中XXX.jar可被其它工程依赖,XXX-exec.jar可执行。
2. http 和 https 的区别?
HTTP(HyperText Transfer Protocol)和 HTTPS(HyperText Transfer Protocol Secure)主要有以下区别:
一、安全性
- 加密方式:
- HTTP 是明文传输,数据在网络中以未加密的形式传输,容易被窃听、篡改或劫持。
- HTTPS 在传输层使用 SSL(Secure Sockets Layer)或 TLS(Transport Layer Security)协议进行加密。客户端和服务器之间的通信会先进行 SSL/TLS 握手,协商出一个对称加密密钥,然后用这个密钥对数据进行加密传输。这使得数据在传输过程中即使被截获也很难被解密。
- 证书验证:
- HTTPS 要求服务器拥有数字证书,证书由权威的证书颁发机构(CA)颁发。客户端在与服务器建立连接时,会验证服务器证书的合法性,包括证书的颁发机构、有效期、域名匹配等。如果证书不合法或验证不通过,客户端会发出警告或拒绝连接。
- HTTP 没有证书验证机制,无法确保连接的服务器是真实可靠的。
二、连接方式
- 端口号:
- HTTP 默认使用 80 端口进行通信。
- HTTPS 默认使用 443 端口。
- 握手过程:
- HTTP 连接建立相对简单,客户端向服务器发送请求,服务器响应请求,即可开始数据传输。
- HTTPS 在建立连接时,需要进行 SSL/TLS 握手。这个过程包括客户端发送支持的加密算法列表给服务器,服务器选择一种加密算法并发送证书等信息给客户端,客户端验证证书并生成对称加密密钥发送给服务器,服务器使用该密钥进行确认等步骤。握手过程相对复杂,会增加一定的连接建立时间。
三、性能影响
- 加密开销:
- 由于 HTTPS 需要进行加密和解密操作,会消耗一定的计算资源,对服务器的性能有一定影响。特别是在高并发的情况下,可能需要更强大的服务器硬件来处理加密任务。
- HTTP 没有加密开销,相对来说在性能上可能会稍好一些。但是,在现代硬件和优化的加密算法下,HTTPS 的性能影响通常是可以接受的,并且可以通过使用硬件加速等技术来减轻性能压力。
- 缓存:
- HTTP 的响应内容可以被浏览器和中间代理服务器缓存,以提高后续访问的速度。
- HTTPS 的响应内容通常由于加密的原因,缓存机制相对复杂。一些浏览器和代理服务器可能会对 HTTPS 内容进行有限的缓存,或者需要特定的配置才能进行缓存。这可能会导致 HTTPS 在某些情况下的访问速度稍慢于 HTTP。
四、应用场景
- 敏感信息传输:
- 对于涉及用户隐私数据(如登录密码、信用卡信息等)、金融交易、企业内部敏感数据等的传输,必须使用 HTTPS 来确保数据的安全性。
- HTTP 不适合传输敏感信息,容易导致信息泄露。
- 电子商务和金融网站:
- 在线购物、银行网站、支付网关等涉及资金交易和个人信息的网站通常都使用 HTTPS 来保护用户的财产安全和隐私。
- 如果这些网站使用 HTTP,用户的信息可能会被窃取,导致严重的安全问题。
- 企业内部网络:
- 企业内部的重要业务系统和数据管理平台也越来越多地采用 HTTPS,以防止内部数据被恶意窃取或篡改。
- 特别是在企业与外部合作伙伴进行数据交换时,使用 HTTPS 可以确保数据在传输过程中的安全。
五、总结:
总的来说,HTTPS 比 HTTP 更加安全,但在性能和部署成本上可能会有一些影响。随着网络安全意识的提高和技术的发展,越来越多的网站和应用正在从 HTTP 切换到 HTTPS,以保护用户数据和提高整体的网络安全水平。
3. GC是什么,为什么要使用GC?
一、GC(Garbage Collection,垃圾回收)的概念
在编程语言中,尤其是像 Java、C#、Python 等具有自动内存管理功能的语言中,垃圾回收是一种自动管理内存的机制。其主要作用是识别和回收不再被程序使用的内存空间,以防止内存泄漏和提高程序的稳定性。
二、为什么要使用 GC
- 防止内存泄漏:
- 在没有垃圾回收机制的情况下,程序员需要手动管理内存的分配和释放。如果程序员忘记释放不再使用的内存,就会导致内存泄漏。随着程序的运行,内存泄漏会逐渐积累,最终可能导致程序耗尽系统内存而崩溃。
- 例如,在 C 或 C++ 等语言中,程序员需要使用
malloc
和free
或new
和delete
来分配和释放内存。如果在分配内存后没有正确地释放,就会发生内存泄漏。而在具有垃圾回收机制的语言中,如 Java,程序员不需要手动管理内存,垃圾回收器会自动回收不再使用的对象所占用的内存,从而避免了内存泄漏的问题。
- 提高开发效率:
- 手动管理内存是一项复杂且容易出错的任务。程序员需要时刻关注内存的分配和释放,这不仅增加了编程的难度,还容易导致错误。而垃圾回收机制使得程序员可以专注于业务逻辑的实现,而不必担心内存管理的细节,从而提高了开发效率。
- 例如,在 Java 中,程序员可以创建对象而不必担心何时释放这些对象所占用的内存。垃圾回收器会在适当的时候自动回收这些内存,使得程序员可以更专注于实现业务功能。
- 增强程序的稳定性:
- 手动管理内存容易出现错误,如释放已经释放的内存、访问已经释放的内存等,这些错误可能导致程序崩溃或出现不可预测的行为。而垃圾回收机制可以避免这些错误,从而增强了程序的稳定性。
- 例如,在 C 或 C++ 中,如果程序员错误地释放了已经释放的内存,可能会导致程序崩溃。而在具有垃圾回收机制的语言中,这种情况不会发生,因为垃圾回收器会自动管理内存的释放。
总之,垃圾回收机制是现代编程语言中非常重要的一部分,它可以自动管理内存,防止内存泄漏,提高开发效率,增强程序的稳定性。
4. 排序有哪几种方法?说一说冒泡排序的原理。
一、常见的排序方法
- 冒泡排序(Bubble Sort)
- 选择排序(Selection Sort)
- 插入排序(Insertion Sort)
- 希尔排序(Shell Sort)
- 归并排序(Merge Sort)
- 快速排序(Quick Sort)
- 堆排序(Heap Sort)
- 计数排序(Counting Sort)
- 桶排序(Bucket Sort)
- 基数排序(Radix Sort)
二、冒泡排序的原理
冒泡排序是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
以下是具体步骤:
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
例如,对数组[5, 3, 8, 4, 2]
进行冒泡排序:
第一次遍历:
- 比较
5
和3
,交换得到[3, 5, 8, 4, 2]
。- 比较
5
和8
,不交换。- 比较
8
和4
,交换得到[3, 5, 4, 8, 2]
。- 比较
8
和2
,交换得到[3, 5, 4, 2, 8]
。此时最大的数8
已在正确位置。第二次遍历:
- 比较
3
和5
,不交换。- 比较
5
和4
,交换得到[3, 4, 5, 2, 8]
。- 比较
5
和2
,交换得到[3, 4, 2, 5, 8]
。第三次遍历:
- 比较
3
和4
,不交换。- 比较
4
和2
,交换得到[3, 2, 4, 5, 8]
。第四次遍历:
- 比较
3
和2
,交换得到[2, 3, 4, 5, 8]
。至此,数组已排序完成。
5. 简述一下动态sql的执行原理
动态 SQL 是指在 SQL 语句中包含了变量或者根据不同的条件动态生成不同的 SQL 语句部分。以常见的数据库如 MySQL、Oracle 等结合 Java 中的框架如 MyBatis 为例,简述其执行原理如下:
一、动态 SQL 的组成部分
- 条件判断:可以根据不同的条件来决定是否添加特定的 SQL 片段。例如在 MyBatis 中使用
<if>
标签进行条件判断。- 循环遍历:用于遍历集合或者数组,并根据其中的元素动态生成 SQL 片段。例如
<foreach>
标签。- 动态参数绑定:可以将程序中的变量动态地绑定到 SQL 语句中的参数位置。
二、执行原理
-
解析阶段:
- 当数据库框架(如 MyBatis)遇到包含动态 SQL 的语句时,首先会对 SQL 语句进行解析。这个过程会识别出动态 SQL 中的各种标签和表达式。
- 对于条件判断标签,框架会评估其中的条件表达式,确定该部分 SQL 是否应该被包含在最终生成的 SQL 语句中。
- 对于循环遍历标签,框架会遍历给定的集合或数组,并根据每个元素生成相应的 SQL 片段。
-
生成 SQL 语句:
- 根据解析阶段的结果,框架会动态地生成实际执行的 SQL 语句。如果条件判断为真,对应的 SQL 片段就会被包含在生成的 SQL 语句中;如果条件判断为假,该部分 SQL 就会被忽略。
- 对于循环遍历,会根据集合中的每个元素生成相应的 SQL 子句,并将它们组合起来形成完整的 SQL 语句。
-
参数绑定和执行:
- 一旦生成了最终的 SQL 语句,框架会将程序中传递的参数绑定到 SQL 语句中的占位符上。这个过程通常是通过数据库连接的参数绑定机制来实现的。
- 然后,框架将生成的 SQL 语句发送到数据库服务器进行执行。数据库服务器会根据接收到的 SQL 语句进行查询、插入、更新或删除等操作,并返回相应的结果。
例如,在 MyBatis 中使用以下动态 SQL 查询用户信息:
<select id="getUsersByConditions" resultType="User">
SELECT * FROM users
WHERE 1 = 1
<if test="username!= null">
AND username = #{username}
</if>
<if test="age!= null">
AND age = #{age}
</if>
</select>
在这个例子中,根据传入的参数不同,最终生成的 SQL 语句也会不同。如果只传入了 username
参数,那么生成的 SQL 语句就是:
SELECT * FROM users WHERE 1 = 1 AND username =?
如果同时传入了 username
和 age
参数,生成的 SQL 语句就是:
SELECT * FROM users WHERE 1 = 1 AND username =? AND age =?
小结:
总之,动态 SQL 通过在运行时根据不同的条件和参数动态生成 SQL 语句,提高了 SQL 的灵活性和可维护性,使得开发人员可以更方便地构建复杂的数据库查询和操作。
6. 什么是控制反转IOC?如何使用
控制反转(IoC)是一种设计思想,旨在将应用程序中对象的创建和依赖关系的控制权从应用程序代码转移到外部容器中。在传统的编程中,对象之间的依赖关系通常由程序代码直接控制,而在IoC模式下,这些依赖关系由外部容器(如Spring框架)来管理,从而降低了代码之间的耦合度,提高了代码的可维护性和可测试性。
IoC的基本概念
IoC(Inversion of Control)即“控制反转”,是一种设计思想,而不是一种技术。在Java开发中,IoC意味着将设计好的对象交给容器控制,而不是在对象内部直接控制。对于Spring框架来说,就是由Spring来负责控制对象的生命周期和对象间的关系1。
IoC的实现方式
IoC的实现方式主要有两种:依赖注入(Dependency Injection, DI)和依赖查找(Dependency Lookup)。在依赖注入中,容器在创建对象时会自动注入其依赖的对象;而在依赖查找中,对象自己通过某种方式去查找和获取所需的依赖对象
7. 什么是AOP 应用场景是什么?
AOP(Aspect Oriented Programming,面向切面编程)是一种编程范式,旨在通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态添加辅助功能的技术。 AOP关注的是横切关注点,如日志记录、事务管理、安全性检查等,这些功能与业务逻辑紧密相关,但又不属于业务逻辑本身。通过AOP,可以将这些功能封装成切面,然后在运行时动态地织入到业务逻辑中,从而降低代码之间的耦合度,提高代码的可维护性和可重用性 。
AOP的应用场景
- 日志记录:在方法调用前后插入切面逻辑,记录方法名、参数和返回值等信息,方便调试和问题追踪24。
- 事务管理:在方法调用前开启事务,调用后提交或回滚事务,简化事务管理代码24。
- 安全性检查:在方法调用前进行权限检查,确保只有授权用户才能访问特定资源2。
- 性能监控:记录方法的执行时间,帮助识别性能瓶颈2。
- 异常处理:统一处理异常,避免在每个方法中都进行异常处理,简化代码2。
- 缓存管理:在方法调用前检查缓存,减少数据库访问,提高系统性能2。
- 日志审计:记录用户的操作日志,方便审计和追踪2。
AOP的实现原理
AOP通过切面(Aspect)、连接点(Join Point)、切点(Pointcut)、通知(Advice)和织入(Weaving)等核心概念实现。切面定义了通知和切点的组合,连接点是指在程序执行过程中可以插入切面的地方。切点定义了切面在哪些连接点上起作用。通知是切面实际执行的操作,包括前置通知、后置通知、返回通知、异常通知和环绕通知。织入是将切面应用到目标对象上的过程 。
通过AOP,开发者可以将那些与业务逻辑紧密相关的功能(如日志记录、事务管理等)封装成切面,然后在运行时动态地织入到业务逻辑中,从而简化代码维护和提高系统的可扩展性。
8. 什么是内存溢出,什么是内存泄漏
一、基本概念
内存溢出(out of memory):简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提供的内存,导致无法申请到足够的内存,于是就发生了内存溢出。
内存泄漏(memory leak):内存泄漏指程序运行过程中分配内存给临时变量,用完之后却没有被GC回收,始终占用着内存,既不能被使用也不能分配给其他程序,于是就发生了内存泄漏。
二、内存溢出的常见情况
1、java.lang.OutOfMemoryError: PermGen space (持久带溢出)
我们知道jvm通过持久带实现了java虚拟机规范中的方法区,而运行时常量池就是保存在方法区中的,因此发生这种溢出可能是运行时常量池溢出,或是由于程序中使用了大量的jar或class,使得方法区中保存的class对象没有被及时回收或者class信息占用的内存超过了配置的大小。
2、java.lang.OutOfMemoryError: Java heap space (堆溢出)
发生这种溢出的原因一般是创建的对象太多,在进行垃圾回收之前对象数量达到了最大堆的容量限制。
3、虚拟机栈和本地方法栈溢出
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError。
如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError。
三、内存溢出的原因及解决方法
- 内存溢出原因
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
- 集合类中有对对象的引用,使用完后未清空,产生了堆积,使得JVM不能回收;
- 代码中存在死循环或循环产生过多重复的对象实体;
- 使用的第三方软件中的BUG;
- 启动参数内存值设定的过小
内存溢出的解决方案
- 第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
- 第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
- 第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。
四、内存泄漏分类
内存泄漏的根本原因是长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象已经不再需要,但由于长生命周期对象持有它的引用而导致不能被回收。
以发生的方式来分类,内存泄漏可以分为4类:
1、常发性内存泄漏
发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
2、偶发性内存泄漏
发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3、一次性内存泄漏
发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
4、隐式内存泄漏
程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
五、内存泄漏的解决方法
- 内存泄漏也许是因为活动已经被使用完毕,但是仍然在其他地方被引用,导致无法对其进行回收。我们只需要给对活动进行引用的类独立出来或者将其变为静态类,该类随着活动的结束而结束,也就没有了当活动结束但仍然还被其他类引用的情况。
- 资源性对象在不使用的时候,应该调用它的close()函数将其关闭掉
- 集合容器中的内存泄露 ,我们通常把一些对象的引用加入到了集合容器(比如ArrayList)中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了。
- 需要在退出程序之前,将集合里的东西clear,然后置为null,再退出程序。
- WebView造成的泄露,当我们不使用WebView对象时,应该调用它的destory()函数来销毁它,并释放其占用的内存,否则其长期占用的内存也不能被回收,从而造成内存泄露。
- 我们应该为WebView另外开启一个进程,通过AIDL与主线程进行通信,WebView所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。
六、总结
1.关系:内存泄露最终会导致内存溢出,由于系统中的内存是有限的,如果过度占用资源而不及时释放,最后会导致内存不足,从而无法给所需要存储的数据提供足够的内存,从而导致内存溢出。导致内存溢出也可能是由于在给数据分配大小时没有根据实际要求分配,最后导致分配的内存无法满足数据的需求,从而导致内存溢出。
2.区别:
- 内存泄露:是由于GC无法及时或者无法识别可以回收的数据进行及时的回收,导致内存的浪费;
- 内存溢出:是由于数据所需要的内存无法得到满足,导致数据无法正常存储到内存中。内存泄露的多次表现就是会导致内存溢出。
9. 静态代理和动态代理的区别?
创建时机、类型限制、灵活性、维护成本
静态代理和动态代理的主要区别包括创建时机、类型限制、灵活性和维护成本等方面。
1.创建时机
- 静态代理:在编译时就已经创建好代理类,代理类和委托类的关系在运行前就确定了 。
- 动态代理:在运行时动态生成代理类,通过Java反射机制生成 。
2.类型限制
- 静态代理:需要为每个被代理类创建一个代理类,因此被代理类必须事先定义好 。
- 动态代理:可以代理任意实现了接口的类,不需要为每个被代理类单独创建代理类 。
3.灵活性
- 静态代理:结构在编译时就确定了,无法在运行时动态地改变代理行为 。
- 动态代理:可以在运行时根据需要改变代理行为,可以动态地添加、修改或删除代理逻辑 。
4.维护成本
- 静态代理:需要为每个被代理类创建代理类,如果被代理类发生改变,代理类也需要相应地进行修改,维护成本较高 。
- 动态代理:不需要为每个被代理类创建代理类,维护成本相对较低 。
5.适用场景
- 静态代理:适用于代理类较少且固定的情况 。
- 动态代理:适用于代理类较多且需要动态改变代理行为的情况 。
6.具体实现方式
- 静态代理:由程序员创建或工具生成代理类的源码,再编译代理类 。
- 动态代理:通过实现JDK里的InvocationHandler接口的invoke方法,或者使用CGLIB动态修改字节码来实现 。
10. 常见的http状态码是怎么分类的,列举常见的http状态码
HTTP 状态码用于描述 HTTP 请求的结果,比如 2xx 就代表请求被成功处理。
常见 HTTP 状态码
1xx Informational(信息性状态码)
相比于其他类别状态码来说,1xx 你平时你大概率不会碰到,所以这里直接跳过。
2xx Success(成功状态码)
- 200 OK:请求被成功处理。例如,发送一个查询用户数据的 HTTP 请求到服务端,服务端正确返回了用户数据。这个是我们平时最常见的一个 HTTP 状态码。
- 201 Created:请求被成功处理并且在服务端创建了
一个新的资源。例如,通过 POST 请求创建一个新的用户。- 202 Accepted:服务端已经接收到了请求,但是还未处理。例如,发送一个需要服务端花费较长时间处理的请求(如报告生成、Excel 导出),服务端接收了请求但尚未处理完毕。
- 204 No Content:服务端已经成功处理了请求,但是没有返回任何内容。例如,发送请求删除一个用户,服务器成功处理了删除操作但没有返回任何内容。
这里格外提一下 204 状态码,平时学习/工作中见到的次数并不多。
HTTP RFC 2616 对 204 状态码的描述如下:
简单来说,204 状态码描述的是我们向服务端发送 HTTP 请求之后,只关注处理结果是否成功的场景。也就是说我们需要的就是一个结果:true/false。
举个例子:你要追一个女孩子,你问女孩子:“我能追你吗?”,女孩子回答:“好!”。我们把这个女孩子当做是服务端就很好理解 204 状态码了。
3xx Redirection(重定向状态码)
- 301 Moved Permanently:资源被永久重定向了。比如你的网站的网址更换了。
- 302 Found:资源被临时重定向了。比如你的网站的某些资源被暂时转移到另外一个网址。
4xx Client Error(客户端错误状态码)
- 400 Bad Request:发送的 HTTP 请求存在问题。比如请求参数不合法、请求方法错误。
- 401 Unauthorized:未认证却请求需要认证之后才能访问的资源。
- 403 Forbidden:直接拒绝 HTTP 请求,不处理。一般用来针对非法请求。
- 404 Not Found:你请求的资源未在服务端找到。比如你请求某个用户的信息,服务端并没有找到指定的用户。
- 409 Conflict:表示请求的资源与服务端当前的状态存在冲突,请求无法被处理。
5xx Server Error(服务端错误状态码)
- 500 Internal Server Error:服务端出问题了(通常是服务端出 Bug 了)。比如你服务端处理请求的时候突然抛出异常,但是异常并未在服务端被正确处理。
- 502 Bad Gateway:我们的网关将请求转发到服务端,但是服务端返回的却是一个错误的响应。
后续的会下次更新 ...
[[[[ 10.25 续更... ]]]]
11. java中堆和栈的理解?
在 Java 中,堆(Heap)和栈(Stack)是两种不同的内存区域,它们有以下特点和区别:
一、栈(Stack)
存储内容:
- 主要存放基本数据类型的值(如 int、double、boolean 等)以及对象的引用。
- 当一个方法被调用时,该方法中定义的局部变量也会被存储在栈中。
生命周期:
- 与方法的调用和执行密切相关,方法执行时入栈,方法执行完毕后出栈,局部变量的生命周期随着方法的执行结束而结束。
特点:
- 内存空间相对较小,但是存取速度快。
- 数据的存储和释放遵循 “先进后出”(Last In First Out,LIFO)的原则。
二、堆(Heap)
存储内容:
- 存放对象实例。所有通过
new
关键字创建的对象都存储在堆中。- 例如创建一个
Person
对象,这个对象就会在堆中分配内存空间。生命周期:
- 由垃圾回收器(Garbage Collector)管理,对象的生命周期取决于是否还有引用指向它。当没有任何引用指向一个对象时,该对象就可能被垃圾回收器回收,释放其所占用的内存空间。
特点:
- 内存空间相对较大,可以动态地分配和释放内存。
- 分配和回收内存的开销相对较大,存取速度比栈慢。
public class Main {
public static void main(String[] args) {
int num = 10; // 基本数据类型的值存储在栈中
Person person = new Person("Alice"); // 对象存储在堆中,person 变量存储在栈中,保存对象的引用
}
}
class Person {
private String name;
public Person(String name) {
this.name = name;
}
}
在这个例子中,num
这个基本数据类型的值存储在栈中,而 Person
对象存储在堆中,变量 person
在栈中保存指向堆中对象的引用。
12. Spring 中的隔离级别?
在 Spring 中,事务的隔离级别是定义事务之间如何相互隔离以避免并发问题的属性。Spring 支持的事务隔离级别与数据库事务的隔离级别相对应,通常有以下几种:
-
ISOLATION_DEFAULT
:- 使用底层数据库的默认隔离级别。
- 不同的数据库有不同的默认隔离级别,比如 MySQL 默认采用的是
REPEATABLE READ
(可重复读)隔离级别。
-
ISOLATION_READ_UNCOMMITTED
(读未提交):- 允许一个事务读取另一个事务尚未提交的数据。这是隔离级别最低的一种设置。
- 可能会导致脏读(一个事务读取到了另一个事务未提交的修改,而这些修改可能会被回滚)、不可重复读和幻读问题。
-
ISOLATION_READ_COMMITTED
(读已提交):- 一个事务只能读取另一个事务已经提交的数据。
- 可以避免脏读,但可能会出现不可重复读(一个事务在两次读取同一数据时,由于其他事务的修改导致结果不一致)和幻读问题。
-
ISOLATION_REPEATABLE_READ
(可重复读):- 一个事务在执行过程中多次读取同一数据时,结果是一致的。
- 可以避免脏读和不可重复读,但可能会出现幻读问题(当一个事务在两次查询之间,另一个事务插入了满足查询条件的数据行)。
-
ISOLATION_SERIALIZABLE
(可串行化):- 最高的隔离级别,通过强制事务串行执行来避免所有可能的并发问题。
- 可以完全避免脏读、不可重复读和幻读问题,但会极大地降低数据库的并发性能。
13. Spring事物的传播性?
在 Spring 中,事务的传播行为定义了被修饰的方法在事务上下文中的行为方式。当一个带有事务的方法调用另一个带有事务的方法时,事务的传播行为决定了如何处理这些事务。Spring 定义了七种事务传播行为:
-
PROPAGATION_REQUIRED
(默认值):- 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。
-
PROPAGATION_SUPPORTS
:- 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式执行。
-
PROPAGATION_MANDATORY
:- 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
-
PROPAGATION_REQUIRES_NEW
:- 总是创建一个新事务,并在该新事务中执行。如果当前存在事务,则将当前事务挂起。
-
PROPAGATION_NOT_SUPPORTED
:- 以非事务的方式执行。如果当前存在事务,则将当前事务挂起。
-
PROPAGATION_NEVER
:- 以非事务的方式执行。如果当前存在事务,则抛出异常。
-
PROPAGATION_NESTED
:- 如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则与
PROPAGATION_REQUIRED
类似。嵌套事务是一个独立的事务,它可以独立地提交或回滚,而不会影响外部事务。但是,如果外部事务回滚,嵌套事务也会被回滚。
- 如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则与
14. 简述一下SpringMVC 的执行流程?
Spring MVC 的执行流程主要包括以下几个关键步骤:
-
用户发起请求:
- 用户通过浏览器或其他客户端向服务器发送一个 HTTP 请求。
-
前端控制器(DispatcherServlet)接收请求:
- Spring MVC 的前端控制器
DispatcherServlet
是整个框架的核心,它负责接收所有的 HTTP 请求。
- Spring MVC 的前端控制器
-
处理器映射器(HandlerMapping)查找处理器:
DispatcherServlet
将请求委托给处理器映射器,处理器映射器根据请求的 URL 等信息查找相应的处理器(Controller)。- 处理器可以是一个 Java 类中的方法,它负责处理特定类型的请求。
-
处理器适配器(HandlerAdapter)调用处理器:
- 找到处理器后,
DispatcherServlet
再通过处理器适配器调用具体的处理器方法。 - 处理器适配器负责将请求适配到特定的处理器方法,并执行该方法。
- 找到处理器后,
-
处理器(Controller)执行业务逻辑:
- 处理器(Controller)接收请求并执行相应的业务逻辑,可能会与服务层、数据访问层等进行交互,处理数据。
-
处理器返回模型和视图(ModelAndView):
- 处理器处理完业务逻辑后,通常会返回一个
ModelAndView
对象,其中包含模型数据和视图名称。
- 处理器处理完业务逻辑后,通常会返回一个
-
视图解析器(ViewResolver)解析视图:
DispatcherServlet
将ModelAndView
对象传递给视图解析器,视图解析器根据视图名称解析出具体的视图对象,例如 JSP、Thymeleaf 模板等。
-
渲染视图并返回响应:
- 视图对象使用模型数据进行渲染,生成最终的 HTML 或其他格式的响应内容。
DispatcherServlet
将响应内容返回给客户端,完成一次请求的处理。
总之,Spring MVC 通过前端控制器、处理器映射器、处理器适配器、视图解析器等组件的协作,实现了对 Web 请求的高效处理和响应,将业务逻辑与视图分离,提高了开发效率和可维护性。
15. 如何处理SpringMVC 中的跨域问题?
在 Spring MVC 中,可以通过以下几种方式处理跨域问题:
一、使用@CrossOrigin
注解
1.在控制器方法上添加@CrossOrigin
注解:
@RestController
public class MyController {
@CrossOrigin(origins = "http://example.com")
@GetMapping("/myendpoint")
public String myMethod() {
return "Hello from Spring MVC!";
}
}
这将允许来自http://example.com
的跨域请求访问这个方法。
可以通过设置origins
属性指定允许的源,还可以设置methods
属性指定允许的 HTTP 方法,如@CrossOrigin(origins = "http://example.com", methods = RequestMethod.GET)
只允许来自特定源的 GET 请求。
2.在控制器类上添加@CrossOrigin
注解
@CrossOrigin(origins = "*", maxAge = 3600) @RestController public class MyController { // 控制器方法 }
这将对整个控制器中的所有方法应用跨域设置,允许来自任何源的请求(
origins = "*"
),并设置最大缓存时间为 3600 秒。
二、使用过滤器(Filter)
实现一个自定义的过滤器来处理跨域请求:
1. 创建过滤器类:
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CORSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
response.setHeader("Access-Control-Max-Age", "3600");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {}
}
2. 在 Spring 配置中注册过滤器:
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class WebConfig { @Bean public FilterRegistrationBean<CORSFilter> corsFilter() { FilterRegistrationBean<CORSFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new CORSFilter()); registrationBean.addUrlPatterns("/*"); return registrationBean; } }
这个过滤器将对所有请求添加跨域响应头,允许来自任何源的请求,并指定了允许的 HTTP 方法和请求头。
三、使用 Spring 的WebMvcConfigurer
接口
1. 创建一个配置类并实现WebMvcConfigurer
接口:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://example.com") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("Content-Type", "Authorization") .allowCredentials(true) .maxAge(3600); } }
这个配置类通过重写
addCorsMappings
方法来配置跨域设置,允许来自http://example.com
的请求,并指定了允许的 HTTP 方法、请求头、是否允许携带凭证以及最大缓存时间。
16. 什么是SpringBoot? 有哪些优点?
一、Spring Boot 是什么
Spring Boot 是一个用于快速开发基于 Spring 框架的独立应用程序的开源框架。它简化了基于 Spring 的应用开发过程,通过自动配置和约定优于配置的理念,使得开发者可以更加专注于业务逻辑的实现,而无需花费大量时间进行繁琐的配置工作。
Spring Boot 可以创建独立的、可执行的 Java 应用程序,其中内置了 Servlet 容器(如 Tomcat、Jetty 等),可以直接运行而无需将应用部署到外部的应用服务器上。它还提供了丰富的 starter 依赖,方便开发者快速引入各种常用的技术和框架,如数据库连接、Web 开发、安全等。
二、Spring Boot 的优点
-
快速开发:
- 极大地减少了开发过程中的配置工作,通过自动配置功能,开发者只需关注业务逻辑,大大提高了开发效率。
- 提供了大量的 starter 依赖,使得引入各种技术变得非常简单,无需手动配置复杂的依赖关系。
-
独立可运行:
- 内置了 Servlet 容器,可以生成独立的可执行 JAR 包或 WAR 包,方便部署和运行。
- 无需依赖外部的应用服务器,降低了部署的复杂性。
-
微服务友好:
- 非常适合构建微服务架构,每个微服务可以作为一个独立的 Spring Boot 应用开发和部署。
- 提供了各种微服务相关的功能支持,如服务发现、配置中心等。
-
生产就绪特性:
- 提供了很多生产环境所需的特性,如健康检查、指标监控、外部化配置等,使应用能够快速适应生产环境。
-
易于测试:
- 支持单元测试和集成测试,可以轻松地对应用进行测试。
- 提供了一些测试工具和注解,方便进行测试用例的编写。
-
社区活跃:
- Spring Boot 拥有庞大的社区和丰富的文档资源,开发者可以很容易地找到问题的解决方案和学习资料。
- 不断更新和改进,以适应新的技术和需求。
17. SpringBoot 的 自动装配原理是什么?
一、@SpringBootApplication 注解
@SpringBootApplication
是一个复合注解,它包含了@SpringBootConfiguration
、@EnableAutoConfiguration
和@ComponentScan
三个重要的注解。
-
@SpringBootConfiguration
:- 标记这是一个 Spring Boot 的配置类,类似于传统的 Spring
@Configuration
注解,表示这个类可以定义 Bean 和配置信息。
- 标记这是一个 Spring Boot 的配置类,类似于传统的 Spring
-
@EnableAutoConfiguration
:- 开启自动配置功能,这是自动装配的核心注解。它会根据项目中引入的依赖和类路径中的内容,自动配置 Spring 应用上下文。
-
@ComponentScan
:- 扫描指定的包及其子包,查找被
@Component
、@Service
、@Repository
等注解标记的类,并将它们注册为 Spring Bean。
- 扫描指定的包及其子包,查找被
当满足特定条件时,这些自动配置类会被加载并进行自动配置。每个自动配置类通常包含以下内容:
@Configuration
注解:表明这是一个配置类,可以定义 Bean 和配置信息。
条件注解(如
@ConditionalOnClass
、@ConditionalOnProperty
等):用于确定是否应该应用该自动配置。例如,
@ConditionalOnClass(SomeClass.class)
表示只有当类路径中存在SomeClass
时,该自动配置才会生效。Bean 定义:
在自动配置类中定义各种 Bean,这些 Bean 可以是服务、数据源、配置对象等,以满足特定的功能需求。
19. SpringBoot 在启动的时候会做那几件事情?
Spring Boot 在启动时会执行以下主要步骤:
-
加载引导类(Bootstrap Class)
- Spring Boot 应用通常有一个引导类,这个类上有
@SpringBootApplication
注解。引导类负责启动整个应用程序。 - 引导类通常包含一个
main
方法,用于启动 SpringApplication。
- Spring Boot 应用通常有一个引导类,这个类上有
-
创建 SpringApplication 对象
SpringApplication
的构造函数会做一些初始化工作,包括确定应用的类型(是 Web 应用还是非 Web 应用)、设置应用的名称等。
-
加载资源和环境(Resources and Environment)
- Spring Boot 会加载应用的资源,如配置文件(application.properties 或 application.yml)。
- 同时,创建和初始化应用的环境(Environment)对象,这个环境包含了各种属性,如系统属性、环境变量、配置文件中的属性等。
-
初始化器(Initializers)和监听器(Listeners)
- Spring Boot 会调用一系列的初始化器和监听器。
- 初始化器可以在应用启动的早期阶段对应用上下文进行定制化操作。
- 监听器可以监听应用启动过程中的各种事件,并做出相应的反应。
-
推断应用类型
- 根据类路径中的依赖和配置,确定应用是一个 Web 应用还是非 Web 应用。
-
创建应用上下文(Application Context)
- 根据推断出的应用类型,创建相应的应用上下文,如
AnnotationConfigServletWebServerApplicationContext
(对于 Web 应用)或AnnotationConfigApplicationContext
(对于非 Web 应用)。
- 根据推断出的应用类型,创建相应的应用上下文,如
-
加载自动配置(Auto-configuration)
- Spring Boot 会扫描类路径,查找并加载自动配置类。
- 自动配置类会根据应用的依赖和环境条件,自动配置 Spring 应用上下文,例如配置数据源、Web 服务器、安全设置等。
-
刷新应用上下文(Refresh Application Context)
- 调用应用上下文的
refresh
方法,这个方法会完成以下重要任务:- 注册 Bean 定义。
- 初始化所有的单例 Bean。
- 触发各种事件,如
ContextRefreshedEvent
。
- 调用应用上下文的
-
启动嵌入式服务器(Embedded Server)(如果是 Web 应用)
- 如果应用是一个 Web 应用,Spring Boot 会启动一个嵌入式的 Web 服务器(如 Tomcat、Jetty 等)。
- 服务器会监听特定的端口,等待接收 HTTP 请求。
-
运行应用(Run the Application)
- 最后,Spring Boot 会启动应用,并开始处理请求。如果应用中有定义
CommandLineRunner
或ApplicationRunner
接口的 Bean,这些 Bean 的run
方法会在应用启动后被调用。
20. Spring 、SpringBoot 、SpringMVC 有什么区别?
Spring、Spring Boot 和 Spring MVC 有以下区别:
一、Spring
定位:
- Spring 是一个开源的 Java 企业级应用开发框架,为企业级应用开发提供了全面的解决方案。
功能特点:
- 提供了依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)等核心功能。
- 支持事务管理、数据访问、Web 开发等多个方面,但需要进行大量的配置工作。
开发方式:
- 开发人员需要手动配置各种 Bean、依赖关系和中间件组件,相对较为繁琐。
二、Spring Boot
定位:
- 是基于 Spring 框架的快速开发框架,旨在简化 Spring 应用的开发和部署过程。
功能特点:
- 内置了嵌入式服务器(如 Tomcat、Jetty),可以直接生成独立可运行的 JAR 或 WAR 文件,无需部署到外部服务器。
- 提供自动配置功能,根据项目依赖自动配置 Spring 应用上下文,减少了大量的配置工作。
- 提供了丰富的 starter 依赖,方便快速引入各种常用的技术和框架。
开发方式:
- 遵循约定优于配置的原则,开发人员只需关注业务逻辑,通过少量的配置或无需配置即可快速开发应用。
三、Spring MVC
定位:
- 是 Spring 框架中的一个模块,用于构建 Web 应用程序的 MVC(Model-View-Controller)架构。
功能特点:
- 实现了 MVC 架构模式,将应用程序分为模型(Model)、视图(View)和控制器(Controller)三个部分,提高了代码的可维护性和可扩展性。
- 提供了强大的请求处理、数据绑定、视图解析等功能,方便开发 Web 应用。
开发方式:
- 开发人员需要在 Spring 配置文件中配置 DispatcherServlet、视图解析器等组件,并编写控制器类来处理请求。
总结:
- Spring 是一个基础的企业级应用开发框架,提供了广泛的功能但配置相对复杂。
- Spring Boot 是在 Spring 基础上构建的快速开发框架,简化了配置和部署过程,适合快速开发独立的应用程序。
- Spring MVC 是 Spring 框架中的 Web 开发模块,专注于构建 Web 应用的 MVC 架构。
在实际开发中,可以结合使用 Spring、Spring Boot 和 Spring MVC,以充分发挥它们各自的优势,提高开发效率和应用的质量。