面试八股文--框架篇(SSM)

一、Spring框架

1、什么是spring

Spring框架是一个开源的Java平台应用程序框架,由Rod Johnson于2003年首次发布。它提供了一种全面的编程和配置模型,用于构建现代化的基于Java的企业应用程序。Spring框架的核心特性包括依赖注入(DI)、面向切面编程(AOP)、事务管理、数据访问、消息传递、远程调用等。

2、Spring IoC

**IoC(Inversion of Control:控制反转)**是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spring 特有,在其他语言中也有应用。

Q:Spring框架中的单例bean是线程安全的吗?

不是,Spring框架的默认值是singleton单例的。一般在spring的bean中注入都是无状态对象,没有线程安全问题,如果在bean中定义了可修改的成员变量,是要考虑线程安全问题的。可以考虑使用多例(prototype)或者加锁来实现。

java 复制代码
// 单例模式
public class Singleton {
    private static Singleton instance = null;

    private Singleton() {
        System.out.println("Singleton created");
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2);
    }
}

3、AOP(Aspect-Oriented Programming:面向切面编程)

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

4、Spring MVC

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

当然,这是传统的Spring MVC框架,前后端分离时,后端通常不再返回具体的视图,而是返回纯数据 (通常是 JSON 格式),由前端负责渲染和展示。因此Controller会直接返回JSON数据交由前端处理,这是通过**@RestController**实现的

4、Spring框架的常见注解

  • Spring:@Component、@Controller、@Service、@Repository、@Autowired、@Bean、@Aspect、@Before、@After
  • SpringMVC:@RequestMapping、@RequestBody、@RequesParam、@ResponseBody
  • SpringBoot:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan

5、SpringBoot自动配置

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

· @SpringBootConfiguration

· @EnableAutoConfiguration

· @ComponentScan

其中@EnableAutoConfiguration是实现自动化配置的核心注解,该注解通过@import注解导入对应的配置选择器。在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。

java 复制代码
@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@Slf4j
@EnableCaching
@EnableScheduling
public class SkyApplication {
    public static void main(String[] args) {
        SpringApplication.run(SkyApplication.class, args);
        log.info("server started");
    }
}

6、常见的请求类型

5 种常见的请求类型:

  • GET :请求从服务器获取特定资源。举个例子:GET /users(获取所有学生)
  • POST :在服务器上创建一个新的资源。举个例子:POST /users(创建学生)
  • PUT :更新服务器上的资源(客户端提供更新后的整个资源)。举个例子:PUT /users/12(更新编号为 12 的学生)
  • DELETE :从服务器删除特定的资源。举个例子:DELETE /users/12(删除编号为 12 的学生)
  • PATCH:更新服务器上的资源(客户端提供更改的属性,可以看做作是部分更新)

二、Redis

1、Redis的介绍

(1)Redis

Redis是一个开源的(open source)、内存中的数据结构存储系统,它支持多种数据结构,如字符串、哈希表、列表、集合、有符号整数和浮点数等,并提供了多种操作数据结构的命令。Redis基于内存的key-value结构数据库

(2)Redis数据类型

  • 字符串 string :SET key value,GET key

  • 哈希 hash:HSET key filed value,HGET key filed

  • 列表 list:LPUSH key value, RPOP key

  • 集合 set:SADD key mebmer, SMEMBERS key

  • 有序集合 sorted set:ZADD key score member

2、Redis的作用--缓存

使用Redis作为访问和数据库(DB)之间的纽带,遇到查询,先查Redis缓存,查到了直接返回,没查到再去数据库,这样能提高访问效率,减小数据库压力。但可能会有以下问题:

(1)击穿:指的是大量无效的查询一直进行访问,Redis中查不到,要持续访问DB,给DB带来负担,甚至导致崩溃(恶意访问,攻击)

解决方法:- 无效查询就在Redis中存储空字符串,可以不用访问DB(但可能存储大量空字符串)

  • 采用布隆过滤器(常见操作)布隆过滤器使用bitmap存储,可以直接过滤掉无效访问。(但也有误判率)

(2)穿透:指的是一个热点的key过期了,但有大量查询热点key的需求到来,导致访问DB频繁,导致DB崩溃

解决方法:- 采用锁:即一个进程到来后,发现Redis中没有该缓存,直接获得锁,然后去数据库中查询,其他进程来了之后,由于没有获得锁,只能等待。查询成功后存入Redis,可以直接返回(高一致性,但可用性低)

  • 采用逻辑过期:热点key不让其真正过期,而使用一个逻辑过期字段,这样一个进程进行查询后,直接返回旧值,然后获得一个锁,建立一个新的进程去数据库进行查找,其他进程来了之后,由于没有锁,因此也无法访问数据库,直接返回旧值,直到该查询更新(保证了高可用性,但一致性低)

(3)雪崩:很多key同时过期,而当大量查询来的时候,会给数据库造成压力,导致DB崩溃。

解决方法:给不同的key设置不同的过期时间,例如1-5min随机random

(4)双写一致性:提问(Redis作为缓存,mysql的数据如何和redis进行同步呢?)

解决方法:延迟双删(删除缓存--修改数据库--(延时)--删除缓存 -->依旧有脏数据风险

要保证一致性:加锁! 为了提高性能:采用共享锁(可以读不能写)和读写锁(读写都不行,也叫排他锁)

提高可用性,只能保证最终一致性:- 异步通知(MQ、canal(基于mysql))

(5)持久化(Redis作为缓存数据的持久化是怎么做的?)

Redis提供了两种策略:RDB和AOF

  • RDB(Redis Database Backup files)是一个快照文件,用于将redis内存中的数据存储到磁盘中,当redis实例宕机恢复数据的时候,可以从RDB快照中直接恢复
  • AOF(Append Only files)的含义是追加文件,当Redis中有操作写命名时,AOF会记录下这些命令,当redis实例宕机恢复数据的时候,可以重新执行一遍命令来恢复数据
  • RDB更快,但可能丢失数据,AOF慢,但丢数据风险小很多,一般一起用

(6)数据过期策略

Redis的数据过期策略:

  • 惰性删除:设置过期时间,当访问key的时候,查看是否过期,过期则删除,反之返回
  • 定期删除:每隔一段时间就对一些key进行检查,删除里面的过期key。两种模式:SLOW是定时任务,默认10hz,每次不超过25ms,FAST频率不固定
  • 一般惰性删除+定期删除两种配合使用

(7)数据淘汰策略(内存不足怎么办)

redis中提供了多种数据淘汰策略,默认是noeviction,即不删除任何数据,当内存不足的时候直接报错。但我们也可以采取其他方式,其中有两个重要概念,一个是LRU(最近最少使用),当前时间减去最近一次使用时间,越大则删除优先级越高,一般是对热点数据的保存。另一个是LFU(最少频率使用),是一段时间内的访问频率,频率越低删除优先级越高。

策略:allkeys-lru淘汰策略,这样留下来的都是热点key

3、Redis的作用--分布式锁

Redis的分布式锁主要利用Redis的setnx命令,其底层是lua脚本实现的(保证原子性)

redisson实现的分布式锁--可重入,在Redission的分布式锁中提供了一个WatchDog,一个线程获取锁成功后,WatchDog会给持有锁的线程续期。

redission实现的分布式锁--主从一致性:RedLock(红锁):不能在一个redis实例上创建锁

三、Mybatis

1、Mybatis介绍

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的工作。

2、常见问题

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

  • #{} 是预编译处理,防止 SQL 注入,sql查询时会替换为?
XML 复制代码
<select id="countByMap" resultType="java.lang.Integer">
  select count(id) from user
  <where>
  <if test="begin != null">
      and create_time &gt;= #{begin}
  </if>
  <if test="end != null">
      and create_time &lt;= #{end}
  </if>
  </where>
</select>
  • ${} 是字符串替换,有 SQL 注入风险
sql 复制代码
select * from users order by ${orderCols}
  • 一般参数传递使用 #{},动态表名/列名使用 ${}

Q2:MyBatis 的动态 SQL 有哪些标签?

  • <if><choose>/<when>/<otherwise>

  • <trim><where><set>

  • <foreach>:常用于 IN 查询

  • <bind>:创建变量

Q3:如何实现分页查询?

  • 物理分页:使用 PageHelper 插件
java 复制代码
PageHelper.startPage(pageNum,pageSize);
  • 逻辑分页:RowBounds(不推荐)

  • 手动编写 LIMIT 语句

Q4:MyBatis 的 xml 映射文件中,不同的 xml 映射文件,id 是否可以重复?

不同的 xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置 namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践而已。

原因就是 namespace+id 是作为Map<String, MappedStatement>的 key 使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。

四、Maven

1、maven介绍

Maven 是一个强大的项目管理和构建工具,主要用于 Java 项目。它提供了一套标准化的项目结构、依赖管理和构建生命周期

核心特点:

  • 依赖管理:自动下载和管理项目所需的库文件(JAR)

  • 标准化项目结构:约定优于配置

  • 构建生命周期:定义明确的构建阶段(compile, test, package等)

  • 插件体系:丰富的插件支持各种构建需求

  • 多模块支持:便于管理大型项目的多个子模块

2、常见问题

Q1:Maven 的坐标(GAV)是什么?

  • groupId:组织或项目的唯一标识(如:com.company.project)

  • artifactId:项目的唯一模块标识

  • version:项目的版本号

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

Q2:依赖冲突如何解决?

  • 最短路径优先

  • 声明优先(先声明的依赖优先)

  • 使用<exclusions>排除特定依赖

  • 使用mvn dependency:tree分析依赖树

Q3:Maven 的生命周期有哪些阶段?

  • package 和 install 的区别?

    • package:打包到项目的target目录

    • install:打包并安装到本地仓库


都看到这里了,给个小心心♥呗~

相关推荐
Lee川11 小时前
优雅进化的JavaScript:从ES6+新特性看现代前端开发范式
javascript·面试
Lee川14 小时前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i16 小时前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有17 小时前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有17 小时前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫18 小时前
Looper.loop() 循环机制
面试
AAA梅狸猫18 小时前
Handler基本概念
面试
Wect18 小时前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼19 小时前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试
掘金安东尼19 小时前
Next.js 企业级落地
前端·javascript·面试