面试八股文--框架篇(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:打包并安装到本地仓库


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

相关推荐
uhakadotcom11 分钟前
nginx的JavaScript魔力:njs简介与实践
javascript·后端·面试
用户3157476081351 小时前
MCP的出现,是对Function Calling的“书同文、车同轨”吗?
人工智能·面试·mcp
Foyo Designer3 小时前
【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的消息队列:使用 RabbitMQ 实现异步处
java·spring boot·程序人生·spring·职场和发展·rabbitmq·java-rabbitmq
Java技术小馆4 小时前
如何排查Linux系统中的CPU使用率过高问题
java·后端·面试
六月的可乐4 小时前
【干货】前端实现文件保存总结
前端·javascript·面试
mCell4 小时前
每秒打印一个数字:从简单到晦涩的多种实现
前端·javascript·面试
SuperYing5 小时前
前端候选人突围指南:让面试官主动追着要简历的五大特质(个人总结版)
前端·面试
Moment5 小时前
前端性能指标 —— CLS
前端·javascript·面试
掘金安东尼6 小时前
上周前端发生哪些新鲜事儿? #407
前端·面试·github