八股之 Java 常用框架

news2024/11/13 11:16:24

一、Spring

1.IOC

1.将一个类声明为 Bean 的注解有哪些?

  • @Component:通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。
  • @Controller : 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。

2.@Autowired 和 @Resource 的区别是什么?

Autowired 属于 Spring 内置的注解,默认的注入方式为byType,会优先根据接口类型匹配并注入 Bean (接口的实现类)。

当一个接口存在多个实现类时,注入方式会变为 byName(根据名称进行匹配),寻找与变量名相同的类名,但更推荐通过 @Qualifier 注解来显式指定名称而不是依赖变量的名称

// SmsService 接口有两个实现类: SmsServiceImpl1和 SmsServiceImpl2
// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Autowired
private SmsService smsServiceImpl1;
// 正确注入  SmsServiceImpl1 对象对应的 bean
// smsServiceImpl1 就是我们上面所说的名称
@Autowired
@Qualifier(value = "smsServiceImpl1")
private SmsService smsService;

@Resource属于 JDK 提供的注解,默认注入方式为 byName。如果无法通过名称匹配到对应的 Bean 的话,注入方式会变为byType

@Resource 有两个比较重要且日常开发常用的属性:name(名称)、type(类型)。如果仅指定 name 属性则注入方式为byName,如果仅指定type属性则注入方式为byType,如果同时指定name 和type属性(不建议这么做)则注入方式为byType+byName

// 报错,byName 和 byType 都无法匹配到 bean
@Resource
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Resource
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean(比较推荐这种方式)
@Resource(name = "smsServiceImpl1")
private SmsService smsService;

总结:

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
  • Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
  • 当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。
  • @Autowired 支持在构造函数、方法、字段和参数上使用。@Resource 用于字段和方法上的注入,不支持在构造函数或参数上使用。

3.Bean 的作用域

  • singleton(默认) : IoC 容器中只有唯一的 bean 实例,是对单例设计模式的应用。
  • prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例。
  • request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
  • session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
  • application/global-session (仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
  • websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。
<bean id="..." class="..." scope="singleton"></bean>
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
    return new Person();
}

4.Bean 的生命周期

5.Bean 是线程安全的吗?

Spring 框架中的 Bean 是否线程安全,取决于其作用域和状态。

prototype 作用域下,每次获取都会创建一个新的 bean 实例,不存在资源竞争问题,所以不存在线程安全问题。

singleton 作用域下,IoC 容器中只有唯一的 bean 实例,可能会存在资源竞争问题(取决于 Bean 是否有状态)。如果这个 bean 是有状态的话,那就存在线程安全问题(有状态 Bean 是指包含可变的成员变量的对象)。

不过,大部分 Bean 实际都是无状态(没有定义可变的成员变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。

对于有状态单例 Bean 的线程安全问题,常见的有两种解决办法:

  1. 在 Bean 中尽量避免定义可变的成员变量。
  2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

2.AOP

1.Spring AOP 和 AspectJ AOP 有什么区别?

2.AspectJ 定义的通知类型有哪些?

  • Before(前置通知):目标对象的方法调用之前触发
  • After (后置通知):目标对象的方法调用之后触发
  • AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发
  • AfterThrowing(异常通知):目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。
  • Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法

3.多个切面的执行顺序如何控制?

1、通常使用@Order 注解直接定义切面顺序

// 值越小优先级越高
@Order(3)
@Component
@Aspect
public class LoggingAspect implements Ordered {

2、实现Ordered 接口重写 getOrder 方法。

@Component
@Aspect
public class LoggingAspect implements Ordered {
    // ....
    @Override
    public int getOrder() {
        // 返回值越小优先级越高
        return 1;
    }
}

3.循环依赖

循环依赖是指 Bean 对象循环引用,是两个或多个 Bean 之间相互持有对方的引用,例如 CircularDependencyA → CircularDependencyB → CircularDependencyA。

@Component
public class CircularDependencyA {
    @Autowired
    private CircularDependencyB circB;
}

@Component
public class CircularDependencyB {
    @Autowired
    private CircularDependencyA circA;
}

(1)如何解决

在全局配置文件中设置允许循环依赖存在:spring.main.allow-circular-references=true

Spring 框架通过使用三级缓存来解决这个问题,确保即使在循环依赖的情况下也能正确创建 Bean。Spring 中的三级缓存其实就是三个 Map,如下:

// 一级缓存
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// 二级缓存
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

// 三级缓存
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

简单来说,Spring 的三级缓存包括:

  1. 一级缓存(singletonObjects):存放最终形态的 Bean(已经实例化、属性填充、初始化),一般情况我们获取 Bean 都是从这里获取的,但是并不是所有的 Bean 都在单例池里面(如原型 Bean )
  2. 二级缓存(earlySingletonObjects):存放过渡 Bean(半成品,尚未属性填充),也就是三级缓存中 ObjectFactory 产生的对象,与三级缓存配合使用的,可以防止 AOP 的情况下,每次调用 ObjectFactory.getObject() 都是会产生新的代理对象
  3. 三级缓存(singletonFactories):存放ObjectFactoryObjectFactorygetObject()方法(最终调用的是getEarlyBeanReference()方法)可以生成原始(初始化) Bean 对象或者代理对象(如果 Bean 被 AOP 切面代理)。三级缓存只会对单例 Bean 生效

Spring 创建 Bean 的流程:

  1. 先去 一级缓存 singletonObjects 中获取,存在就返回;
  2. 如果不存在或者对象正在创建中,于是去 二级缓存 earlySingletonObjects 中获取;
  3. 如果还没有获取到,就去 三级缓存 singletonFactories 中获取,通过执行 ObjectFacotrygetObject() 就可以获取该对象,获取成功之后,从三级缓存移除,并将该对象加入到二级缓存中。

在三级缓存中存储的是 ObjectFacoty

public interface ObjectFactory<T> {
    T getObject() throws BeansException;
}

Spring 在创建 Bean 的时候,如果允许循环依赖的话,Spring 就会将刚刚实例化完成,但是属性还没有初始化完的 Bean 对象给提前暴露出去,这里通过 addSingletonFactory 方法,向三级缓存中添加一个 ObjectFactory 对象:

// AbstractAutowireCapableBeanFactory # doCreateBean #
public abstract class AbstractAutowireCapableBeanFactory ... {
	protected Object doCreateBean(...) {
        //...

        // 支撑循环依赖:将 ()->getEarlyBeanReference 作为一个 ObjectFactory 对象的 getObject() 方法加入到三级缓存中
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }
}

那么上边在说 Spring 创建 Bean 的流程时说了,如果一级缓存、二级缓存都取不到对象时,会去三级缓存中通过 ObjectFactorygetObject 方法获取对象。

class A {
    // 使用了 B
    private B b;
}
class B {
    // 使用了 A
    private A a;
}

以上面的循环依赖代码为例,整个解决循环依赖的流程如下:

  • 当 Spring 创建 A 之后,发现 A 依赖了 B ,又去创建 B,B 依赖了 A ,又去创建 A;
  • 在 B 创建 A 的时候,那么此时 A 就发生了循环依赖,由于 A 此时还没有初始化完成,因此在 一二级缓存 中肯定没有 A
  • 那么此时就去三级缓存中调用 getObject() 方法去获取 A 的 前期暴露的对象 ,也就是调用上边加入的 getEarlyBeanReference() 方法,生成一个 A 的 前期暴露对象
  • 然后就将这个 ObjectFactory 从三级缓存中移除,并且将前期暴露对象放入到二级缓存中,那么 B 就将这个前期暴露对象注入到依赖,来支持循环依赖(虽然还没初始化完成,但是可以拿到该对象在堆中的存储地址了)

只用两级缓存够吗? 在没有 AOP 的情况下,确实可以只使用一级和三级缓存来解决循环依赖问题。但是,当涉及到 AOP 时,二级缓存就显得非常重要了,因为它确保了即使在 Bean 的创建过程中有多次对早期引用的请求,也始终只返回同一个代理对象,从而避免了同一个 Bean 有多个代理对象的问题。

(2)缺点

增加内存开销:需要维护三级缓存,也就是三个 Map

降低性能:需要进行多次检查和转换

少部分情况不支持循环依,如非单例的 bean 和@Async注解的 bean

(3)@Lazy 注解如何解决循环依赖

没有被标记为懒加载的 Bean 会在 Spring IoC 容器启动的过程中被创建和初始化,反之则会在第一次被请求时创建。

A 的构造器上添加 @Lazy 注解之后(延迟 Bean B 的实例化),加载的流程如下:

  • 首先 Spring 会去创建 A 的 Bean,创建时需要注入 B 的属性;
  • 由于在 A 上标注了 @Lazy 注解,因此 Spring 会去创建一个 B 的代理对象,将这个代理对象注入到 A 中的 B 属性;
  • 之后开始执行 B 的实例化、初始化,在注入 B 中的 A 属性时,此时 A 已经创建完毕了,就可以将 A 给注入进去。

通过 @Lazy 就解决了循环依赖的注入, 关键点就在于对 A 中的属性 B 进行注入时,注入的是 B 的代理对象,因此不会循环依赖。

4.Spring 事务

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

  • 工厂模式 : Spring 使用工厂模式通过 BeanFactoryApplicationContext 创建 bean 对象。
  • 代理模式 : Spring AOP 功能的实现。
  • 单例模式 : Spring 中的 Bean 默认都是单例的。
  • 模板方法模式 : Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
  • 包装器模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  • 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
  • 适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

二、Spring MVC

1.说说自己对于 Spring MVC 了解?

MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。

2.Spring MVC 的核心组件

  • DispatcherServlet核心的中央处理器,负责接收请求、分发,并给予客户端响应。
  • HandlerMapping处理器映射器,根据 URL 去匹配查找能处理的 Handler ,并会将请求涉及到的拦截器和 Handler 一起封装。
  • HandlerAdapter处理器适配器,根据 HandlerMapping 找到的 Handler ,适配执行对应的 Handler
  • Handler请求处理器,处理实际请求的处理器。
  • ViewResolver视图解析器,根据 Handler 返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给 DispatcherServlet 响应客户端

3.SpringMVC 工作原理

  • 客户端(浏览器)发送请求, DispatcherServlet拦截请求。
  • DispatcherServlet 根据请求信息调用 HandlerMappingHandlerMapping 根据 URL 去匹配查找能处理的 Handler(也就是我们平常说的 Controller 控制器) ,并会将请求涉及到的拦截器和 Handler 一起封装。
  • DispatcherServlet 调用 HandlerAdapter适配器执行 Handler
  • Handler 完成对用户请求的处理后,会返回一个 ModelAndView 对象给DispatcherServletModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。Model 是返回的数据对象,View 是个逻辑上的 View
  • ViewResolver 会根据逻辑 View 查找实际的 View
  • DispaterServlet 把返回的 Model 传给 View(视图渲染)。
  • View 返回给请求者(浏览器)

4.

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

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

相关文章

【网络 day1】

服务器可以循环接收客户端的数据&#xff1b;当客户端退出后&#xff0c; 服务器阻塞等待下一个客户端的连接&#xff0c;而后继续通信&#xff1b;当有客户端连接时&#xff0c; 服务器端 打印客户端的IP 和 Port信息&#xff1b;将代码的 send 和 recv 改为 write 和 read&am…

2024年5款值得推荐的图表数据可视化工具推荐,不会Excel做表必备!

只推荐5个数据可视化图表制作网站&#xff0c;保证让你相见恨晚&#xff01; 模板类型全、数量丰富&#xff0c;支持在线编辑&#xff0c;还免费~~ 1、Dycharts 推荐指数&#xff1a;☆☆☆☆☆ 网址&#xff1a;dycharts.com 这是一个功能强大且免费的在线数据可视化制作工…

产品分析 | 便利蜂

​产品信息 产品名称&#xff1a;便利蜂 Slogan&#xff1a;小小的幸福 在你身边 版本号&#xff1a;V1.11.3 大小&#xff1a;23.6M 体验环境&#xff1a;Android6.0.1 品牌概述 便利蜂成立于2016年12月&#xff0c;算是起步较早的企业了&#xff0c;17年2月就开了第一家…

记录一次edu web端渗透测试实录

0x01前言 由于是直接接到的相关需求&#xff0c;所以是针对性的一次渗透测试&#xff0c;以下内容仅仅作为思路分享以及打法扩展 0x02 进后台小妙招 弱口令永远是永恒不变的0day漏洞&#xff0c;这也是我们挖漏洞时的敲门砖&#xff0c;以下给出的是一个很神奇的关于寻找后台…

看 逆行人生

电影和我的职业本身有相关性&#xff0c;而且我特别喜欢徐峥执导的电影&#xff0c;这次的题材也算是碰上自己的胃口。 周六&#xff0c;下了大半天的雨&#xff0c;早上驱车到公司加班&#xff0c;下午六点多到时候特别想去看电影&#xff0c;果断再驱车从公司赶回来&#xff…

excel计算时间差-显示每堂课时间

TEXT(H2 - INDEX($H$2:$H$1000, MATCH(B2, $B$2:$B$1000, 0)), "mm:ss")import pandas as pd# 假设你已经加载了数据 df pd.read_excel(你的文件路径.xlsx)# 将开始时间列转换为datetime类型 df[开始时间] pd.to_datetime(df[开始时间])# 计算每个课堂号组内的时间…

批发供应系统:提升效率与竞争力的关键

在当今复杂多变的商业环境中&#xff0c;批发供应系统作为连接生产商、分销商与零售商的重要纽带&#xff0c;其效率与智能化水平直接决定了供应链的运作效率与市场竞争力。随着信息技术的飞速发展&#xff0c;尤其是大数据、云计算、人工智能&#xff08;AI&#xff09;及物联…

Python基础—数据分析中的可视化技巧

数据分析中的可视化技巧是帮助我们将复杂的数据转化为直观、易于理解的图表和图像的过程。这些技巧不仅有助于发现数据中的模式和趋势&#xff0c;还能增强数据故事的讲述能力。以下是一些常用的数据可视化技巧&#xff0c;以及相应的Python代码示例&#xff08;使用matplotlib…

Diffusion Model相关论文整理(二)

目录 1、AnoDDPM: Anomaly Detection With Denoising Diffusion Probabilistic Models Using Simplex Noise [CVPR Workshop 2022]2、Unsupervised Visual Defect Detection with Score-Based Generative Model[2022]3、DiffusionAD: Denoising Diffusion for Anomaly Detectio…

接口自动化-代码实现

接口自动化基础 1、接口自动化测试 接口自动化&#xff1a;使用工具或代码代替人对接口进行测试的技术测试目的&#xff1a; 防止开发修改代码时引入新的问题测试时机&#xff1a; 开发进行系统测试转测前&#xff0c;可以先进行接口自动化脚本的编写开发进行系统测试转测后&…

Tensorflow实现深度学习案例7:咖啡豆识别

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一、前期工作 1. 导入数据 from tensorflow import keras from tensorflow.keras import layers,models import numpy as np import matplotlib.pyplot as plt import os,PIL,p…

地平线旭日X3开发板--图像获取时间戳问题

需求 需要获得图像接收完成后的帧时间戳。 sensor f37, MIPI 通信 问题 按我的了解&#xff0c;一般是在内核中产生MIPI数据接收完成中断并打印时间戳&#xff0c; 一般是CLOCK_MONOTONIC方式的时间 &#xff0c; X3无法获得MIPI数据接收完成的时间戳。 X3平台HB_VIN_GetC…

4 - Linux远程访问及控制

目录 一、SSH远程管理 1. SSH概述 2.SSH的优点 3.配置OpenSSH客户端 4.sshd服务支持的两种验证方式 5. 使用SSH客户端程序 5.1 ssh - 远程登录 5.2 scp - 远程复制 6.配置密钥对验证 二、TCP Wrappers访问控制 1.TCP Wrappers 概述 2. TCP Wrappers 机制的基本原则 …

MS SQL Server partition by 函数实战二 编排考场人员

目录 需求 输出效果 范例运行环境 表及视图样本设计 功能实现 生成考场数据 生成重复的SQL语句 封装为统计视图 编写存储过程实现统计 小结 需求 假设有若干已分配准考证号的考生&#xff0c;准考证号示例&#xff08;01010001&#xff09;共计8位&#xff0c;前4位…

ZeroEA阅读笔记

ZeroEA阅读笔记 摘要 实体对齐(EA)是知识图(KG)研究中的一项关键任务&#xff0c;旨在识别不同知识图谱中的等效实体&#xff0c;以支持知识图谱集成、文本到SQL和问答系统等下游任务。考虑到KG中丰富的语义信息&#xff0c;预训练语言模型(PLM)凭借其卓越的上下文感知编码功…

使用SSMS操作AdventureWorks 示例数据库

简介 AdventureWorks 示例数据库&#xff0c;官方文档&#xff1a;https://learn.microsoft.com/zh-cn/sql/samples/adventureworks-install-configure?viewsql-server-ver16&tabsssms 下载备份文件 OLTP 数据适用于大多数典型的联机事务处理工作负载。数据仓库 (DW) 数据…

网络设备监控工具 PIGOSS BSM 网络设备-Ruijie设备SNMP配置及监控

目录 1. 全局模式 2. 配置SNMP V2 3. 配置SNMP V3 4. 配置SNMP Trap 5. 保存配置 6. 查看配置结果 7. 锐捷设备监控 1. 全局模式 SNMP 的配置工作在网络设备的全局配置模式下完成&#xff0c;在进行SNMP 配置前&#xff0c;请先进入全局配置模式。 Ruijie>enable …

Excel“取消工作表保护”忘记密码并恢复原始密码

文章目录 1.前言2.破解步骤3. 最终效果4.参考文献 1.前言 有时候别人发来的Excel中有些表格不能编辑&#xff0c;提示如下&#xff0c;但是又不知道原始密码 2.破解步骤 1、打开您需要破解保护密码的Excel文件&#xff1b; 2、依次点击菜单栏上的视图—宏----录制宏&#xf…

Spring Boot内嵌Tomcat处理请求的链接数和线程数

Spring Boot内嵌Tomcat处理请求的连接数和线程数 处理请求的连接数和线程数配置 Spring Boot的配置项 #等待连接数 server.tomcat.accept-count100 #最大链连接数 server.tomcat.max-connections8192#最小备用线程数 server.tomcat.threads.min-spare10 #最大工作线程数 ser…

【git命令相关】git上传和删除文件步骤

&#xff08;一&#xff09;git登录 1. git bash窗口输入 git config --global user.name "你的Git账号" git config --global user. Email "你的Git邮箱"2. 生成密钥 ssh-keygen -t rsa -C "你的Git邮箱"在此命令执行的返回结果中找到key存放…