精选

以简历为中心对当前12家公司的面试进行分类总结

个人bg:25届双非本,无实习(天崩开局)

以下是目前为止的12家面试中被问到的问题,结合本人粗略判断问得最多的模块当属MYSQL+Redis+并发+项目

面试中如果有实习肯定问实习更多一点,没有实习确实很吃亏,可能更多会问校园经历以及项目相关,目前为止秋招进度几乎为0,笔试倒是做了不少,但真正给面的很少,外界条件肯定会影响到自己的学习进度,但这个时候是最不能松懈的,有笔试就继续做,有面就积极应对,当然没有消息的时候也只能打磨自己的各方面的能力。

算法,项目和八股以及好的简历缺一不可

  1. 熟悉 Java 基础知识(如集合类、异常处理等),能够运用 Lambda 表达式 + Stream API高效操作集合类。
  2. 熟悉并发编程,能够使用 CompletableFuture等JUC类、自定义线程池实现并发和操作异步化。
  3. 熟悉 MySQL 数据库及库表设计,熟悉索引、锁、事务、日志等,能够通过创建索引、分库分表等方式优化性能。
  4. 熟悉 SSM+Spring Boot 开发框架,能够使用 MyBatis Plus+Mybatis X 自动生成 CRUD 代码,能够独立开发基于 Spring Boot Starter 的 SDK
  5. 熟悉 Redis 常见数据结构及应用,实践过基于 Redis 的分布式限流、分布式Session登录、分布式锁,能够解决在高并发下 的缓存穿透,击穿,雪崩问题。
  6. 熟悉RabbitMQ消息队列,有过手动消息确认、消息持久化、交换机队列定义、消息生产消费的实践。
  7. 熟练使用 Linux 系统的相关操作命令,能使用命令监控系统负载和进程状态;能够通过宝塔或者Docker容器在云服务器上完成对项目的部署。
  8. 熟悉 Nacos 和 Dubbo RPC 框架,能够使用 Spring Cloud Gateway 实现 API 网关、访问控制,了解Spring Cloud常用组件, 如Eureka注册中心,Fegin 远程调用,Ribbon 负载均衡。
  9. 熟悉并实践过多种设计模式,比如工厂模式、装饰者模式、双检锁单例模式、代理模式等
  10. 熟悉分布式应用开发:比如 Dubbo RPC 框架、Etcd 注册中心、负载均衡、设计重试和容错机制保证服务稳定性等。
  11. 熟悉React框架开发,能使用Ant Design Pro框架、Umi OpenAPI代码生成、WebStorm IDE等开发工具快速开发前端项目。 (了解)
  12. 熟练使用 Git、IDEA、ChatGPT、Swagger、Postman等工具提高开发写作效率 (了解)

1. (14道)熟悉 Java 基础知识(如集合类、异常处理等),能够运用 Lambda 表达式 + Stream API高效操作集合类。

Java基础

1.1.1. StringBuffer、StringBuilder 的区别? StringBuffer如何实现线程安全的

1.1.2. Java文件流中,上传图片使用字节流还是字符流,上传视频呢

1.1.3. final关键字主要用来做什么?

final关键字主要用于表示“最终”的含义。在Java中,final可以用来修饰变量、方法和类。当final用来修饰变量时,表示该变量的值不能再被修改。当final用来修饰方法时,表示该方法不能被子类重写。当final用来修饰类时,表示该类不能被继承。

JaJava 8(也称为JDK 1.8)是Java编程语言的一个主要版本,于2014年3月由Oracle公司发布。这个版本带来了大量新特性,极大地改善了Java的编程体验,使代码更加简洁、高效。以下是Java 8的一些主要新特性:

1.1.4. 1. Lambda表达式

1.1.4.1. Lambda表达式是Java 8最重要的特性之一,它允许以更简洁的方式编写匿名函数。Lambda表达式本质上是一个匿名方法,可以将函数作为参数传递进方法或将代码视为数据。其构成部分包括使用逗号分隔的参数列表、箭头符号、函数体三部分。使用Lambda表达式可以写出更简洁、更灵活的代码。

1.1.4.2. 2. 函数式接口

1.1.4.3. 函数式接口是只包含一个抽象方法的接口。Java 8引入了@FunctionalInterface注解来显式声明函数式接口,虽然这个注解是可选的,但它可以帮助编译器检查接口是否符合函数式接口的定义。Lambda表达式通常与函数式接口一起使用。

1.1.4.4. 3. Stream API

1.1.4.5. Stream API提供了一种新的处理集合数据的方式。它可以让我们以声明式的方式对数据进行操作,如过滤、映射、排序等,大大简化了集合的处理。Stream API可以与Lambda表达式结合使用,提高编码效率和可读性。

1.1.4.6. 4. 方法引用

1.1.4.7. 方法引用是Lambda表达式的一种简写形式,可以直接引用现有的方法。方法引用的语法是ClassName::methodName,它使得代码更加简洁。

1.1.4.8. 5. 默认方法

1.1.4.9. Java 8允许在接口中定义默认方法,即带有实现的接口方法。这使得接口的演化更加灵活,而无需破坏现有的实现。默认方法使用default关键字声明。

1.1.4.10. 6. Optional类

1.1.4.11. Optional类是Java 8中引入的一个容器类,用于处理可能为null的值。它的主要目的是减少空指针异常(NullPointerException),使得代码更加健壮和可读。Optional类提供了一系列方法来安全地处理可能为null的情况。

1.1.4.12. 7. 新的日期和时间API

1.1.4.13. Java 8引入了新的日期和时间API,以替代旧的Date和Calendar类。新的API提供了更好的可读性和易用性,并且支持更多的操作。例如,LocalDateLocalTimeLocalDateTime等类分别用于处理日期、时间和日期时间。

1.1.4.14. 8. Base64

1.1.4.15. Java 8提供了Base64编码和解码的工具类,用于将二进制数据编码为ASCII字符串,或将ASCII字符串解码为二进制数据。这在处理网络传输、存储等场景时非常有用。

1.1.4.16. 9. 注解相关新特性

1.1.4.17. Java 8扩展了注解的上下文,现在几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,甚至方法的异常也能添加注解。此外,Java 8还引入了重复注解(@Repeatable),允许在同一位置声明多个相同的注解。

1.1.4.18. 10. 并行相关扩展

1.1.4.19. Java 8对并行处理进行了优化,使得数据的并行操作更加容易和高效。Stream API支持顺序流和并行流之间的切换,可以通过parallel()sequential()方法在它们之间进行切换。

1.1.4.20. 综上所述,Java 8的这些新特性极大地改善了Java的编程体验,使代码更加简洁、高效和易于维护。通过掌握这些特性,开发者可以更好地利用Java 8的功能来编写现代、高性能的应用程序。

1.1.5. Lambda表达式

在日常开发中的使用

Lambda表达式在Java 8及更高版本中得到了广泛应用。它们主要用于简化代码,特别是处理集合、过滤、映射等操作。例如,使用Lambda表达式可以轻松地过滤出满足条件的元素,或者对集合中的每个元素执行操作。Lambda表达式提供了一种简洁、优雅的方式来编写函数式代码。

优点

  1. 简洁性:Lambda表达式通过箭头符号(->)实现了函数定义的简洁化,避免了冗长的语法结构和重复代码。
  2. 类型自动推导:Lambda表达式不需要显式指定参数类型,编译器会根据上下文自动推断出参数类型,使得代码更加简单、易懂。
  3. 可读性:Lambda表达式能够更自然、简洁地反映出程序员的编程意图,提高了代码的可读性。
  4. 提升效率:Lambda表达式减少了重复的样板代码,使程序员能够更快速地完成任务,提高了开发效率。
  5. 支持函数式编程:Lambda表达式是Java进行函数式编程的基础,允许通过简洁和优雅的方式来表示函数行为。

1.1.6. JVM、JRE和JDK的关系

JVM(Java Virtual Machine) :Java虚拟机是运行Java字节码的虚拟计算机。任何平台只要安装了JVM,就可以运行Java程序。

JRE(Java Runtime Environment) :Java运行时环境,包含了JVM和Java程序运行所需的核心类库等。它是运行Java程序所必须的环境。

JDK(Java Development Kit) :Java开发工具包,是Java程序员的开发环境,包含了JRE和一系列用于开发、调试Java程序的工具(如javac编译器、java调试器等)。简而言之,JDK是JRE的超集,JRE是JVM的超集。

1.1.7. 什么是面向对象?

面向对象一般就是不需要考虑每一个对象的一个具体的行为,只需要关注这个对象有有哪些属性,把它封装起来。那样过程的话,它是属于这个属性,它需要做哪些操作,面向面向对象的话就只需要关注对象本身就可以了。

1.1.8. 面向对象的那个基本要素是什么?

面向对象的有封装、继承和多态。

封装的话就可以把把一些属性封装起来。只提供提只提供给提供给外部一个接口,set一个set一个公共的一个set或者get一个方法,可以把它有效的防止防止外部的一些。防止外部人的一些攻击。然后制成的话制成就是可以子类可以制成可以继承副类来实现一些功能上的一个重用。然后多态的话就可以体现在对一些类的重写以及重写

1.1.9. 讲一下一个类的实例化的过程是什么样的?

一个类的实例化它是先进行一个初始化,然后再进行一个联系法包括。包括分析检查以及。以及筛选,然后再进行一个。初始化,然后对它进行一个初始的复制,以及把把一些把一些引间接引用改成直接引用。

1.1.10. 类的初始化你肯定是首先是不是要被分配内存?是不是你那些属性就要去初始化了?接下来是干什么的?

在堆一般在堆内存里面初始化。然后分配了内存之后。属性进行初始化,把把这个属性的一些方法给它加载进来。有参构造和无参构造,调用他的构造函数,最终是返回这个类的引用。

Java集合

1.1.1. HashMap默认的初始化大小为多少,是怎么扩容的

1.1.2. 先说一下java这边你比较熟悉的一些集合。

1.1.3. 如何理解hash呢

哈希表的话它是一个kv类型的。它是在1.7之前,它是一个链表加上数组加链表的形式。但在1.8以后他他添加了一个红黑树,他只有他当他一个链表长度大于8,然后数组长度大于64的时候,它会转化成一个红黑数。如果它当它那个链表如果小于6的话,它又会从红黑数转化成一个链表的形式。它哈西提供了一些一些添加一些增删改查的一些操作。但是它是线程不安全的。如果线程安全的有两个hashtable,但它但这个现在都已经不怎么用了,基本上就被淘汰了。还有一个concurrentHashMap

这个是如果如果要用到哈希,如果要用到哈希的话,要而且还要保证线程安全的话,就可以用这个。然后它是它扩容的话,是它它是一个扩容因数是0.75。当它比如它初始化的话,它是十六,如果达到12的话,它会进行扩容。扩容的话每次是扩容两倍,1.8之后是变成两倍。因为它那个每次每每次变成两倍的话,它直接在它通过那个未运算的话,每次扩容如果翻两倍,它如果它进行一个位运算,如果是在低位的话,它还是直接在那个位置上不动。如果是高位的话,它进行一个与运算,变到前面,就就把就就这样子可以对可以避免一些那个哈西扣的算他对他进行哈希避免一些冲突,尽可能的一些避免冲突

1.1.4. 解决哈希冲突的方法有什么

不会,回答了一个扩容哈希冲突是指不同的输入值经过哈希函数计算后得到相同的哈希值,是一种常见的情况

复盘

  1. 链表法(Separate Chaining):这是一种常用的解决哈希冲突的方法。每个哈希桶维护一个链表,每当发生冲突时,将新的元素添加到链表的末尾。这样,在哈希桶中有相同哈希值的元素都存储在同一个链表中。
  2. 开放寻址法(Open Address):这种方法将所有的元素都存储在哈希表中,不使用额外的数据结构来解决冲突。当发生冲突时,依次查找其他空闲的槽位,直到找到一个空槽来存储元素。
    • 线性探测(Linear Probing):在发生冲突时,依次检查下一个槽位,直到找到一个空槽。
    • 二次探测(Quadratic Probing):在发生冲突时,通过一定的间隔(如平方数)来探测下一个槽位,直到找到一个空槽。
    • 双重哈希(Double Hashing):通过使用第二个哈希函数来计算下一个槽位的位置,以解决冲突。
  1. 再哈希(Rehashing):当哈希冲突达到一定程度时,可以扩大哈希表的大小,并重新计算所有元素的哈希值。这样可以减少冲突发生的概率。

选择哪种解决冲突的方法取决于具体情况,例如数据的特点、访问模式、内存和时间的限制等。不同的方法在性能、空间利用率和实现复杂性等方面都有不同的权衡。

2. (19道)熟悉并发编程,能够使用 CompletableFuture等JUC类、自定义线程池实现并发和操作异步化。

2.1. CountDownLatch

了解程度

CountDownLatch是Java并发工具类之一,用于协调多个线程之间的同步。其作用是让某一个线程等待多个线程的操作完成之后再执行。它基于AQS(AbstractQueuedSynchronizer)实现,计数器只能递减且不可重置。

适用场景

  1. 主线程等待多个子线程完成任务后再继续执行。
  2. 启动多个线程并发执行任务,等待所有线程执行完毕后进行结果汇总。
  3. 线程间依赖关系的处理,如一个线程需要等待其他线程完成某些操作后才能继续执行。

2.2. AQS(AbstractQueuedSynchronizer)

了解程度

AQS是一个用来构建锁和同步器的框架,它提供了一套线程阻塞等待以及被唤醒时锁分配的机制。通过内置的FIFO队列,AQS可以完成获取资源线程的排队工作。许多Java并发工具类,如ReentrantLock、Semaphore等,都是基于AQS实现的。

2.3. CAS(Compare-And-Swap)

了解程度

CAS是一种用于实现同步的原子操作,它包含三个操作数:内存位置的值(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置更新为新值。CAS是乐观锁的一种实现方式,它假设在多个线程并发访问共享资源时,发生冲突的可能性较小。

2.4. CAS与synchronized、volatile的区别

  1. synchronized
    • 保证可见性和原子性。
    • 线程加锁前,必须读取主内存的最新值到自己的工作内存。
    • 线程解锁前,必须把共享变量的值刷新回主内存。
    • 悲观锁机制,适用于写操作较多的场景。
  1. volatile
    • 保证可见性,但不保证原子性。
    • 通过内存屏障保证变量的修改对其他线程可见。
    • 轻量级,适用于读操作远多于写操作的场景。
  1. CAS
    • 保证原子操作,通过比较并交换实现。
    • 非阻塞的乐观锁机制,适用于写操作较少,冲突较少的场景。
    • 可能导致ABA问题,但可以通过版本号等方式解决。

2.5. CAS作为乐观锁存在的问题

ABA问题:CAS算法在比较并替换内存中的值时,如果在此期间该值被其他线程修改后又改回了原值,CAS操作会误认为该值没有被修改过,从而执行更新操作。这可能会导致数据一致性问题。解决ABA问题的一种常见方法是使用版本号或时间戳机制。

循环时间长开销大:如果CAS操作一直失败,那么自旋锁会一直进行循环尝试,这会导致CPU开销增大。在锁竞争激烈或持有锁的线程需要长时间占用锁执行同步块的情况下,CAS的自旋锁机制可能并不适合。

2.6. 你了解Synchronized吗,底层是如何实现可见性的?

2.7. 你里面还讲到了一个锁,什么叫做锁的自旋?

锁的咨询。CAS它如果没有获取到锁的话,它会一直在自旋等待。然后synchronized和reentrantlock

的那个锁,它是如果你没有获取到锁的话,它就会进行它就会进入阻塞状态。阻塞状态的话它会来回切换,IO会会增大一个。因为每次IO的话它每次重新从阻塞态到运行态的话,它会它都会从用户态到一个内核内核态的一个转换会造成一些资源的浪费以及占用CPU性能。如果通过自旋的话,它会在没有获取到锁,他会自旋自旋,直到获取到锁的话,他就会减少一个切换。

2.8. 什么叫做锁的可重入?

可重入synchronized和reentrantlock,它都是可重入锁。可重入锁就相当于是我这个所获取到之后,如果退出的话,下一次再想要获取的话,他不需要再重复进重复重复的去抢占这个锁。它这它它的实现是synchronized它是给一个给一个次数。如果你每获取到一次锁的话,他都会次数加1。如果他丢掉这个锁的话,它每次次数减一直到那次数到0的话,它才会不可重入。到0的时候他如果需要再占用再强再要用这个锁的话,就重新跟别的所进行一个竞争。或者是有一些所是公平所,他是要排队的。有一些是非非公平锁的话,他就需要在有所的时候进行一个竞争。

2.9. 线程池核心参数

线程池的核心参数主要包括:

  1. 核心线程数(corePoolSize) :线程池中保持的线程数,即使这些线程处于空闲状态,也不会被销毁。
  2. 最大线程数(maximumPoolSize) :线程池中允许的最大线程数。
  3. 非核心线程存活时间(keepAliveTime) :当线程池中的线程数超过核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
  4. 时间单位(unit) :非核心线程存活时间的时间单位,如秒、毫秒等。
  5. 工作队列(workQueue) :用于存放待执行任务的阻塞队列。

2.10. 创建线程的方法

创建线程主要有以下几种方法:

  1. 继承Thread:通过继承Thread类并重写其run方法来实现。
  2. 实现Runnable接口:通过实现Runnable接口并重写其run方法,然后将Runnable实例传递给Thread类。
  3. 实现Callable接口:通过实现Callable接口并重写其call方法(该方法可以抛出异常并返回执行结果),然后使用FutureTask来包装Callable对象,最后由Thread类执行该FutureTask对象。这种方式相比Runnable接口,可以获取执行结果并处理异常。
  4. 使用线程池(如ExecutorService :线程池可以管理一组线程,减少创建和销毁线程的开销,提高系统性能。

2.11. 线程池的拒绝策略

线程池的拒绝策略主要有以下几种:

  1. AbortPolicy:直接抛出异常,阻止系统正常工作。
  2. CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中运行被拒绝的任务。
  3. DiscardOldestPolicy:丢弃队列中最靠前的任务,并执行当前任务。
  4. DiscardPolicy:静默地丢弃无法处理的任务,不抛出异常。

2.12. 我想在任意的方法里面,我想娶到我某一个参数的话,我们应该要怎么做?鉴权这块你了解吗?比如说我现在一般健全的时候,其实我的我们的接口上下文里面是能拿到这个用户信息的,对不对?那你的用户信息一般会存在哪里呢?在我们直接写代码的业务里面,如果你想要去获取用户信息,你会怎么获取?

存到本地内存里面ThreadLocal

2.13. 可以对她进行一下介绍吗?你对ThreadLocal的理解

它是一个本地内存,相对于相对一个线线上的那种内存的话,他可能放在本地访问的可能访问的应对在本地的话可能更安。比较安全。

2.14. 多并发的实现方式

多并发的实现可以通过多种方式,包括但不限于以下几种:

  1. 多进程(Multiprocessing)
    • 概念:在操作系统中创建多个进程,每个进程都有自己独立的地址空间和资源。
    • 优点:独立性强,一个进程的崩溃不会影响其他进程。
    • 缺点:进程间通信开销较大,资源占用较多。
    • 实现方式:在Python中,可以使用multiprocessing模块来创建和管理进程。
  1. 多线程(Multithreading)
    • 概念:在单个进程中创建多个线程,所有线程共享该进程的地址空间和资源。
    • 优点:线程间通信方便(通过共享内存),资源占用少,启动速度快。
    • 缺点:由于共享资源,可能导致数据竞争和不一致性问题。
    • 实现方式:在Python中,可以使用threading模块来创建和管理线程。
  1. 协程(Coroutine)
    • 概念:协程是一种用户态的轻量级线程,其调度完全由用户控制。
    • 优点:极高的执行效率和极低的资源消耗,特别适合I/O密集型任务。
    • 缺点:需要用户自己管理调度,实现复杂。
    • 实现方式:在Python中,可以使用asyncio库来实现异步编程和协程。
  1. 异步I/O(Asynchronous I/O)
    • 概念:通过非阻塞I/O操作,实现任务的并发执行。
    • 优点:提高程序的响应性和吞吐量,特别适合处理大量并发请求。
    • 实现方式:在Python中,可以使用asyncio库结合aiohttp等异步库来实现异步Web服务。
  1. 分布式系统
    • 对于更大规模的并发需求,可以通过构建分布式系统来实现,利用多台机器的资源共同处理请求。

2.15. 你最近有在学什么知识吗?

最近的话在看并发一些相关的。并发的话我看的是那本java并发编程之美。在那一本书上进行一个学习,在里面我学习到了那synchronized的它是一个它是用在代码和类上的,它是会自会进行一个自动的进入到这段代码的时候,它会它就拥有了锁。然后这段代码代码运行完之后,它它会自动的释放锁。然后reentrantlock的话,它是需要手动的进行一个解锁的过程。同时的话新则它是一个它是一个非公平锁。然后reentrantlock的话,会根据一个底层的选择来选择他他要使用公平锁还是非公平锁。然后volatile它是一个它可以实现一个对所有的对一些变量,对所有的用户是可见的。然后的话他还会阻止一个代码的重排序。因为有一些代码会在多线程的情况下,JVM会根据那个语义来进行一个重新的一个重新的一个代码的顺序调整。但是它如果如果ABC代码,如果C要依赖AB代码的话,那只能在AB代码调换。C代码是不能在AB之上的。然后还有AQS,AQS的话它是很多锁的一个实现,很多扫的一个复利的一个框架。

2.16. AQS的核心是什么?

AQS核心就是那个。叫lock,它底层是基于基于实现lock接口。

AQS(AbstractQueuedSynchronizer)的核心在于实现了一个高效且灵活的线程同步框架,它主要用于构建锁和其他同步类。AQS的核心可以归纳为以下几个方面:

2.16.1. 1. 同步状态管理

  • 状态变量(State Variable) :AQS使用一个volatile int state变量来表示同步状态。这个状态变量用于记录锁的获取、释放等信息,是AQS实现同步控制的基础。
  • 状态操作方法:AQS提供了一系列方法来操作状态变量,如getState()setState(int newState)compareAndSetState(int expect, int update)等,这些方法通过CAS(Compare-And-Swap)操作保证了线程安全。

2.16.2. 2. 线程队列管理

  • CLH队列:AQS内部实现了一个基于CLH(Craig, Landin, and Hagersten)锁算法的虚拟双向队列(CLH队列)。这个队列用于管理等待获取资源的线程。在CLH队列中,每个节点(Node)代表一个线程,并包含线程的引用、状态、前驱节点和后继节点等信息。
  • 节点(Node) :AQS中的Node类是实现CLH队列的关键。它包含了线程引用、状态(如CANCELLED、SIGNAL、CONDITION等)、前驱节点和后继节点等字段。通过这些字段,AQS能够高效地管理线程队列,并实现线程的阻塞和唤醒。

2.16.3. 3. 锁获取与释放机制

  • 独占式锁:在独占模式下,AQS只允许一个线程访问共享资源。线程通过调用acquire(int arg)方法来尝试获取锁,如果获取成功则继续执行,否则将线程加入等待队列并阻塞。释放锁时,线程调用release(int arg)方法,并唤醒等待队列中的下一个线程。
  • 共享式锁:在共享模式下,AQS允许多个线程同时访问共享资源。线程通过调用acquireShared(int arg)方法来尝试获取锁,并根据资源的可用情况决定是否阻塞或继续执行。释放锁时,线程调用releaseShared(int arg)方法,并可能唤醒等待队列中的多个线程。

2.16.4. 4. 模板方法模式

  • 自定义同步器:AQS采用了模板方法模式,允许开发者通过继承AQS并重写特定的方法来创建自定义同步器。AQS提供了获取和释放锁的框架,而具体的实现逻辑则由子类提供。这种设计方式使得AQS非常灵活且易于扩展。

2.16.5. 5. 高效性与公平性

  • 高效性:AQS通过利用volatile关键字和CAS操作来确保线程安全和高效的同步控制。同时,CLH队列的虚拟性也避免了实际队列创建和销毁的开销,进一步提高了性能。
  • 公平性:虽然AQS本身并不直接提供公平锁的实现,但开发者可以通过重写AQS的方法来实现公平的锁获取策略。例如,在将线程加入等待队列时,可以根据线程请求的先后顺序来排序,以确保公平性。

综上所述,AQS的核心在于其同步状态管理、线程队列管理、锁获取与释放机制、模板方法模式以及高效性与公平性的实现。这些特性使得AQS成为Java并发编程中一个非常重要的基础组件。

2.17. 线程池了解。在线程池里面我们执行了一个任务对吧?那任务他抛了一个未捕获的异常,我们就没有进行对他进行一个执行线程的执行任务的县城和县城城分别都会发生什么事情?

执行这个线程的话,先要看你这个线程是创建的时候,它一个阻塞的一个你当时一个拒绝策略。如果如果你的拒绝策略是一个是有一个考color run policy的话,它是如果你。发如果发生异常的话,是这个拒绝是调用者这个线是调用者的这个线程来去执行这个被阻被被拒绝的这个任务。然后如果他是选用的about policy的话,就会直接抛出这个任务,被县城这拒绝的一个异常。如果是this kind policy的话,他就不会进行一个处理。还有一个discard old policy,他会拒绝,他会抛出最早的一个任务,然后执行该任务。

2.18. 你说的这个拒绝策略是在什么情况下会执行的?

这种情况是在核心线程核心线程数满,然后在工作那个工作队列也满的情况下,这时候会对一个最大线程数来进行一个增加。直到最大线程数也满的情况下,他会对对你这个先生是来通过你定当时定义的这个拒绝策略来进行一个拒绝。

2.19. 那这个任务他自己抛了一个未捕获的异常,那么执行这个任务的线程和这个线程池分别会发生什么事情?可能跟你说的拒绝策略应该不是同一个东西,对吧?

这个的话还真没,因为实际当中确实没遇到相关的一些bug,也没深入了解过。

当任务(例如,一个Runnable或Callable任务)在执行过程中抛出了一个未捕获的异常时,其处理方式和影响会依据你使用的线程池(如ThreadPoolExecutor)的具体配置和Java版本有所不同,但一般来说,可以遵循以下的基本行为模式:

2.19.1. 线程(Worker Thread)

  1. 任务执行:线程从线程池的工作队列中取出一个任务并执行它。
  2. 异常抛出:如果任务在执行过程中抛出了异常,并且这个异常没有被任务代码本身捕获,那么这个异常将会传播到任务执行的线程中。
  3. 异常处理:在大多数情况下,Java的线程池实现(如ThreadPoolExecutor)不会直接捕获这些异常。这意味着,如果任务内部没有处理这些异常,它们将会导致线程的中断(但实际上,在ThreadPoolExecutor中,异常本身并不直接导致线程中断,除非在异常处理代码中显式调用了Thread.interrupt())。但是,这通常不会停止线程的运行;线程会继续尝试从队列中获取并执行新的任务,除非它被外部请求中断或线程池关闭。

2.19.2. 线程池(如ThreadPoolExecutor

  1. 任务执行失败:当任务因异常而失败时,这个失败不会自动通知给线程池。线程池本身不会意识到某个任务因为异常而失败,除非任务执行者(即任务本身)通过某种机制(如回调函数、日志记录、将异常结果提交到某个共享的数据结构等)来通知线程池。
  2. 任务结果:对于Callable任务,异常会被封装成一个ExecutionException,这个异常会在调用Future.get()方法时抛出。如果任务抛出了RuntimeExceptionError,并且这些异常没有被捕获,那么这些异常同样会被封装在ExecutionException中。
  3. 线程池状态:线程池的状态(如活动线程数、完成的任务数等)不会因为这个异常而改变,除非异常导致线程池被显式地关闭或缩小(例如,通过调用shutdown()shutdownNow()方法)。

2.19.3. 解决方案

  1. 任务内部异常处理:确保任务内部对可能抛出的异常进行适当的处理,或者通过某种方式(如记录日志、发送通知等)来记录或报告这些异常。
  2. 使用Future.get() 捕获异常:对于Callable任务,使用Future.get()来检索任务结果,并准备好捕获和处理ExecutionException
  3. 线程池关闭和清理:在适当的时候关闭线程池,并确保所有已提交的任务都已经完成或被取消。

3. (26道)熟悉 MySQL 数据库及库表设计,熟悉索引、锁、事务、日志等,能够通过创建索引、分库分表等方式优化性能。

3.1. Mysql的默认的是InnoDb,可以说一下底层是什么树实现的?

3.2. select ID code name grade from students where grade=‘大一’,mysql执行过程中底层一共实现了查询几次(grade没有索引)

3.3. @Transactional在不考虑外界因素的情况下会不会回滚失效

3.3.1. 1、异常被捕获后没有抛出

3.3.2. 2、抛出非运行时异常

3.3.3. 3、方法内部直接调用

3.3.4. 4、新开启一个线程

3.3.5. 5、注解到private方法上

3.3.6. 6、数据库本身不支持

3.3.7. 7、事务传播属性设置错误

3.4. 介绍一下索引失效的一些场景

索引失效的一些场景包括:

  1. 当查询条件中包含对索引列的函数操作时,可能导致索引失效。

  2. 当查询条件中使用了逻辑运算符(如OR)时,可能导致索引失效。

  3. 当查询条件中使用了隐类型转换时,可能导致索引失效。

  4. 当查询条件中使用了通配符(如"%")开头,可能导致索引失效。

  5. 当索引列的顺序与查询条件中的顺序不一致时,可能导致索引失效。

3.5. 除了mysql学过其他数据库了吗

NoSQL指非关系型数据库 :主要代表:MongoDB,Redis。NoSQL( 存储方式可以是JSON文档、哈希表或者其他方式。)

3.6. 关系型数据sql和非关系型数据库nosql有什么区别

mysql一般是行列存储数值,nosql一般是k,v类型的(面试官提示还有文档类型的)

3.6.1. 复盘:

其实最主要的是前者满足ACID,后者满足BASE(面试时候没打出来)

扩展性对比:NoSql更容易扩展,数据之间无关系,redis自带的哨兵模式,主从复制,切片集群模式

3.7. 优化一个sql语句大概有一个什么过程呢

先通过慢查询进行分析,查询到哪里需要优化,看对应字段是添加一个单字段索引还是联合索引,另外提到了分表分库(面试的时候想不到太多)

3.7.1. 复盘:

分析查询语句:使用EXPLAIN命令分析SQL执行计划,找出慢查询的原因。比如是否使用了全表扫描,是否存在索引未被利用的情况等,并根据相应情况对索引进行适当修改。

创建或优化索引:根据查询条件创建合适的索引,特别是经常用于WHERE子句的字段,Order by排序的字段,Jion联表查询的字段,Group by的字段,并且如果查询的时候涉及到多个字段,考虑建立联合索引,使用联合索引要符合最左匹配原则,不然会导致索引失效。

避免索引失效:比如不要用左模糊匹配、函数计算、表达式计算等等。

查询优化: 避免使用select * ,只查询真正需要的列,使用覆盖索引,即索引包含所有查询的字段,联表查询尽量要以小表驱动大表,并且被驱动表的字段就你也要有索引,当然最好通过冗余字段的设计,避免联表查询。

分页优化:

优化数据库表: 比如不要用左模糊匹配、函数计算、表达式计算等等。

使用缓存技术: 引入缓存层,如redis,存储热点数据和频繁查询的结果,但要考虑缓存一致性的问题,对于读选择旁路缓存策略,对于写请求会选择先更新db,在删除缓存的策略。

3.8. 如果是要让你去设计一个数据库,你在数据库这个设计方面就需要考虑哪些问题?

先根据实际业务需求进行字段和表的统计,每个表的字段符合数据库的范式,同时对每个表尽可能少的减少冗余,对于一些字段也要进行分析,提前添加上索引,以及一些主键设置和唯一索引,同时比如字符串类型的也要提前设置对应的大小,避免内存浪费。

3.8.1. 复盘

什么是数据库?存数据的

数据库里有什么?数据表(理解为 excel 表格)

java 操作数据库?程序代替人工

3.8.1.1. 什么是设计数据库表?

有哪些表(模型)?表中有哪些字段?字段的类型?数据库字段添加索引?表与表之间的关联?

举例:性别是否需要加索引?

3.9. 什么是覆盖索引?

刚刚发现答错了,答成索引下推的内容了

覆盖索引:其实应该是是查询的字段在联合索引里面,通过非聚簇索引查找的时候子树内容包含需要查的内容(本身叶子节点存放的是主键,如果不包含对应字段,需要找到主键回表查询,覆盖索引避免了回表)

比如 select age from user where age=20; 在此处age是有索引的,此时就会形成覆盖索引

索引下推: select * from user where zipcode=xxx, birthdate=xxx;此时(zipcode, birthdate)是联合索引如果没有索引下推该语句会先查找到符合zip的内容然后对每一条符合的主键进行回表查询,但你索引下推之后只需要在符合zip的内容下查找符合bir的主键然后进行回表查询;

3.10. 什么是索引下推?

索引下推: select * from user where zipcode=xxx, birthdate=xxx;此时(zipcode, birthdate)是联合索引如果没有索引下推该语句会先查找到符合zip的内容然后对每一条符合的主键进行回表查询,但你索引下推之后只需要在符合zip的内容下查找符合bir的主键然后进行回表查询;

3.11. mysql的InnoDB和MyISAM有什么区别呢?

  • 事务支持:InnoDB支持事务处理(ACID兼容),具有提交、回滚和崩溃恢复能力。而MyISAM不支持事务处理。
  • 存储结构:InnoDB的表数据文件本身就是索引文件,表数据文件按照B+Tree组织的一个索引结构,叶节点包含了完整的数据记录。而MyISAM的索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。
  • 锁机制:InnoDB支持行级锁和外键,适合高并发的更新较多的场景。MyISAM使用的是表级锁,并发性能相对较差。
  • 崩溃恢复:InnoDB有崩溃恢复能力,在数据库异常崩溃后能够自动恢复数据。MyISAM在数据库异常崩溃后可能会出现数据丢失的情况。
  • 全文索引:MyISAM支持全文索引,而InnoDB在MySQL 5.6及之后的版本才支持全文索引。

3.12. InnoDB为什么选用B+树作为索引

InnoDB选用B+树作为索引结构,主要基于以下几个原因:

  • 磁盘I/O优化:B+树通过减少磁盘I/O操作次数来提高数据检索效率。数据库系统巧妙利用了磁盘预读原理,将节点大小设为等于一个页(通常是4KB或16KB),使得每个节点只需一次I/O就能完全载入。
  • 局部性原理:由于B+树的节点中存放的是键值及指向子节点的指针,因此可以利用局部性原理,提高缓存命中率。
  • 平衡树结构:B+树是一种自平衡树,能够保持树的高度相对较低,即使在数据量很大的情况下也能保持较高的查询效率。
  • 范围查询优化:B+树的所有记录节点都是按照键值顺序存放的,这有利于进行范围查询。

3.13. 1000万行的数据B+树高度

对于1000万行的数据,B+树的高度会依赖于页的大小(如16KB)以及索引键的大小。一般来说,高度不会很高,因为B+树通过增加扇区个数(即节点中的子节点指针数)来保持树的平衡。在极端情况下,即使数据量达到数亿条,树的高度也可能只有几层。

3.14. 三行最多能存储多少内容

“三行”在数据库上下文中并不是一个标准的概念,通常我们讨论的是页(Page)或记录(Row)的存储容量。对于InnoDB来说,每个页默认大小是16KB,而每条记录占用的空间取决于记录中字段的数量、类型和长度。因此,无法直接回答“三行最多能存储多少内容”,因为这取决于具体的数据结构和字段定义。

3.15. MySQL的一条语句的查询流程

MySQL的一条语句的查询流程大致如下:

  1. 连接器:客户端与MySQL建立连接,连接器负责处理这些连接请求,验证用户身份和权限。
  2. SQL接口:客户端发送SQL语句给服务器,服务器通过SQL接口接收这些SQL命令。
  3. 查询缓存(已废弃) :在MySQL 8.0及以后的版本中,查询缓存已被移除。
  4. 解析器:对SQL语句进行词法分析和语法分析,确定其语法是否正确,并将其转化为一个内部数据结构。
  5. 优化器:评估各种执行计划,并选择最优的执行计划。
  6. 执行器:按照执行计划中的步骤,调用存储引擎的接口从数据表中获取数据,并进行排序、聚合、过滤等操作。

3.16. MySQL的执行过程

MySQL的执行过程与查询流程类似,但更侧重于事务和数据持久化方面。执行过程中,InnoDB引擎会开启事务,记录undo log(回滚日志)和redo log(重做日志),以确保数据的完整性和持久性。同时,MySQL还会记录binlog(二进制日志),用于数据复制和恢复。

3.17. 插入意向锁和意向锁

  • 意向锁:是一种表级锁,用于表示事务接下来可能会对表中的某些行加锁。意向锁分为意向共享锁(IS)和意向排他锁(IX)。它们的主要作用是与其他表级锁(如S锁和X锁)兼容,以支持行级锁。
  • 插入意向锁:是一种特殊的意向锁,用于在插入新行时锁定表中的间隙,防止其他事务在这些间隙中插入重复的行。

3.18. mysql的集中隔离级别,分别有什么作用?

读已提交就可可重复读以及串行化这四种读未提读未提交的话读未提交的话相当于是你你未提交,你比如线程A和B你线程A还未对这个数进行提交的情况下,你B已经B已经可以看到该A提交。A未提交这个数据就会造就会造成贩毒以及藏毒一级不可重复读,不可重复读的问题。

读未提交,读未提交的话就可以解决脏读的问题。然后可重复读的话,你在这种情况下可以防止。可重复读的话,它可以防止脏毒以及不可重复。脏读,但是他也可以阻止一些阻止大部分的贩毒的情况。但是你要想对这种情况都阻止的话,就必须要用可串行化。但是可串行化的话,他他会他是对整个过程加速就比较耗费时间。所以说mysql的默认情况下就默认支持的是可重复读。

3.19. bin log的作用和同步流程

  • 作用:bin log(二进制日志)记录了MySQL数据库中所有更改数据的SQL语句(不包括SELECT和SHOW这类操作),主要用于数据复制和数据恢复。
  • 同步流程:在MySQL的主从复制架构中,主库将binlog发送给从库,从库接收到binlog后应用这些日志中的SQL语句来更新自己的数据,从而实现数据的同步。

3.20. redo log、undo log和bin log的区别

  • redo log:用于记录事务操作中的修改,确保在数据库系统发生故障时能够恢复未提交的事务。redo log是物理日志,记录的是数据页的物理修改。
  • undo ****log:用于记录事务操作前的数据状态,用于事务回滚或MVCC(多版本并发控制)。undo log是逻辑日志,记录的是数据行的逻辑修改。
  • bin log:记录了所有更改数据的SQL语句,主要用于数据复制和数据恢复。bin log是逻辑日志,记录的是数据操作语句。

3.21. bin log的两阶段提交

bin log的两阶段提交是MySQL保证数据一致性的重要机制。在第一阶段,事务的修改被写入到redo log中,并设置redo log为prepare状态。在第二阶段,MySQL将事务的修改写入到bin log中,并设置redo log为commit状态。如果在这个过程中系统崩溃,MySQL可以根据redo log和bin log来恢复数据的一致性。

3.22. 三个范式

数据库设计的三个范式是为了减少数据冗余和提高数据完整性而提出的规范:

  • 第一范式(1NF) :要求数据库表的每一列都是不可分割的基本数据项,每一列都是原子性数据,不能是集合、数组等非原子性数据项。
  • 第二范式(2NF) :在第一范式的基础上,要求数据库表中的非主属性完全依赖于主键。即消除部分依赖。
  • 第三范式(3NF) :在第二范式的基础上,要求数据库表中的非主属性既不部分依赖于主键,也不传递依赖于主键。即消除传递依赖。

3.23. 数据库优化手段

数据库优化的手段多种多样,包括但不限于以下几个方面:

  • 索引优化:合理创建索引可以显著提高查询效率。
  • 查询优化:通过优化SQL语句,减少不必要的全表扫描和复杂的连接操作。
  • 配置优化:调整MySQL的配置参数,如缓冲区大小、连接数等,以适应不同的应用场景。
  • 硬件升级:增加内存、使用更快的存储设备等硬件升级手段也能提高数据库性能。
  • 架构优化:采用读写分离、分库分表等架构优化手段来应对高并发的数据访问需求。
  • 缓存技术:使用缓存技术来减少对数据库的直接访问,提高响应速度。
  • 定期维护:定期执行数据库维护任务,如更新统计信息、重建索引等,以保持数据库的最佳性能。

3.24. 你还写到了叫做一个mysql,对吧?能讲一下mysql里面的最左匹配吗?

最左匹配的话它是一个索引的联合,它是一个联合索引的一个原则。他一般来说是要一般来说联合索引要符合最多匹配原则。所以说如果你就比如ABC联合,所以当你是AB的话,它是可以走最左索引。但是如果是BC的话,因为是A没有走索引,所以说BC的话就会导致索引失效。

3.24.1. 什么是复合索引?

复合索引是指索引建立在两个或两个以上的列上的索引。比如,有一个表users,里面包含first_namelast_nameemail三个字段,你可以在这三个字段上创建一个复合索引,比如INDEX idx_name_email (first_name, last_name, email)

3.24.2. 最左匹配原则

最左匹配原则指的是,MySQL在利用复合索引进行查询时,会按照索引中列的顺序从左到右依次进行匹配。也就是说,它首先会查找索引中的第一列,然后是第二列,依此类推。如果查询条件跳过了索引中的某些列,那么这些列之后的索引部分将不会被使用到,索引就会失去部分或全部的效率。

3.24.3. 示例

假设我们有一个复合索引INDEX idx_name_email (first_name, last_name, email),以下是一些查询示例以及它们是否能利用到最左匹配原则:

  1. 能利用索引
    • SELECT * FROM users WHERE first_name = 'John';
    • SELECT * FROM users WHERE first_name = 'John' AND last_name = 'Doe';
    • SELECT * FROM users WHERE first_name = 'John' AND last_name = 'Doe' AND email = 'john.doe@example.com';

这些查询都能从左到右依次利用索引中的列,因此都能有效地利用索引。

  1. 不能有效利用索引
    • SELECT * FROM users WHERE last_name = 'Doe';
    • SELECT * FROM users WHERE email = 'john.doe@example.com';

这些查询跳过了索引中的第一列(first_name),因此无法利用到复合索引idx_name_email

  1. 部分利用索引
    • SELECT * FROM users WHERE first_name = 'John' AND email = 'john.doe@example.com';

这个查询虽然跳过了last_name列,但仍然能利用到索引中的first_name列。但是,由于跳过了last_name,所以索引的email部分将不会被利用到。

3.24.4. 结论

最左匹配原则是优化MySQL查询性能的一个重要考虑因素,特别是在设计复合索引时。了解并合理利用这一原则,可以显著提高查询效率。同时,也需要注意查询条件的顺序,以确保它们能够最有效地利用索引。

3.25. 了解最左前缀的底层原理吗?

没有深入了解

3.26. redis和mysql如何保持数据一致性?

数据库缓存的话,它如果读写的话,如果堵的话,他我们一般是采用旁路缓存。如果你先去来先来读缓存,如果缓存没有读到的话,就会通过读数据库。读到数据库之后把数据库的缓把数据库的数据再更新到缓存里面。如果是写数据的话,一般是先删先更新数据库,然后更新数据库之后把缓存删掉。如果下次再请求数据,如果下次再请求再一般写的话,就先更新数据库再删除缓存。这两种情况就尽可能高地保证数据库和relais的保证他们数据的一致性。

4. (9道)熟悉 SSM+Spring Boot 开发框架,能够使用 MyBatis Plus+Mybatis X 自动生成 CRUD 代码,能够独立开发基于 Spring Boot Starter 的 SDK

4.1. mybatis中#{}与${}的区别是什么

4.2. Mybatis-plus它主要是做什么呢?

4.3. 为什么是选择了Mybatis-plus,而不是直接用Mybatis?

4.4. 调用一个接口它是怎么样把这个接口去映射到你写的那个xml的那个sql?

4.5. 就比如说统计两分钟内某一个sql调用次数,你会有一个什么样的一个想法来做呢?

4.6. Spring SpringBoot和SpringMVC三者的区别是什么

4.7. SpringBoot启动流程

SpringBoot的启动流程大致如下:

  1. 创建SpringApplication对象:通过运行静态的run方法创建一个SpringApplication对象,并在构造函数中完成一些初始化配置。
  2. 运行SpringApplication:通过调用run方法启动SpringBoot应用。
  3. 准备环境:创建并准备环境对象Environment,用于读取环境配置,如application.ymlapplication.properties文件。
  4. 创建ApplicationContext:根据应用类型(如Servlet应用)创建相应的ApplicationContext对象,这是Spring的IoC容器。
  5. 刷新上下文:通过调用refresh方法刷新上下文,完成bean的加载、注册、解析、实例化等一系列操作。
  6. 启动完成:通知监听器应用启动完成,并调用ApplicationRunnerCommandLineRunner接口中定义的run方法执行启动后的初始化操作。

4.8. 然后你刚才有讲到一个请求对吧?我已经进到了后端,那进到java后端的假设后面是一个spring MVC的应用,它又是怎么如何处理这个请求?

Spring MVC的话一般说正常的spring项目的话,它是基于MVC架构,它会先进入到他一他获取到请求之后,先进入到controler层。他会根据controler层的一些请业务逻辑以及请求进入到service层。对,service层在通过通过到层数据库的一些映射,然后把一些实体类的信息传递给后端。最后再通过model层把把这些数据进行一个返回映射。然后这些通过抗皱层的一些rest API的一个协议,通过一些一般通过json数据传输给前端。

在使用 Spring MVC 的应用程序中,后端服务器通过处理来自客户端的请求来响应HTTP请求。以下是大体的处理流程:

1 客户端发送一个HTTP请求到Spring MVC应用程序的对应URL。
2. Spring MVC框架中的DispatcherServlet接收到请求,并将其分发给相应的控制器(Controller)。
3. 控制器根据请求的URL和其他参数处理请求,并调用相应的业务逻辑处理。
4. 业务辑处理完成后,控制器将处理结果封装为一个模型(Model)对象,并将其传递给视图(View)

  1. 视图负责将模型对象渲染为HTML页面或其他格式的响应,并将响应发送回客户端。
  2. 客户端浏览器接到响应,根据响应的内容进行渲染显示。

Spring MVC通过将请求的URL映射到相应的控制器方法来实现请求的路。通常使用注解(如@RequestMapping)或配置文件来定义URL与控制器方法的映射系。

控制器方法可以使用解来接收请求的参数,如@RequestParam、@PathVariable等。这些注解得开发人员能够轻松地获取请求中的数据,并将其传递给处理逻辑。

在处理请求时,控制器可以使用业务逻辑组件(例如服务层、数据访问层)来执行实际的业务操作,以满足请求的需求。

最后,控制器将处理结果封装为模型对象,将其传递给视图进行渲染。视图通常使用模板引擎(如Thymeleaf、Freemarker)或解析器将模型对象渲染为最终的响应。

需要注意的是,Spring MVC框架提供了很多灵活的配置选项和功能,根据具体需求进行定制和扩展。以上仅是一个概括的处理流程,具体的实现可能会根据具体的应用和开发方式有所不同。

4.9. 过滤器和拦截器的区别

过滤器和拦截器的区别主要体现在以下几个方面:

  1. 实现机制:过滤器是基于函数回调的,而拦截器是基于Java反射机制的。
  2. 依赖关系:过滤器依赖于Servlet容器,而拦截器不依赖于Servlet容器。
  3. 作用范围:过滤器几乎可以对所有的请求起作用,而拦截器只能对action请求起作用。
  4. 访问权限:拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  5. 调用次数:在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
  6. 与IoC容器的关系:拦截器可以获取IoC容器中的各个bean,而过滤器不能。这使得拦截器在调用业务逻辑时更加灵活和方便。

5. (14道)熟悉 Redis 常见数据结构及应用,实践过基于 Redis 的分布式限流、分布式Session登录、分布式锁,能够解决在高并发下 的缓存穿透,击穿,雪崩问题。

5.1. Redis的用途

Redis是一款高性能、内存中键值存储数据库,专为存储可快速访问的数据结构而设计。其主要用途包括:

  1. 缓存:作为数据缓存层,提高应用程序的性能和响应速度。
  2. 会话管理:存储用户会话信息,如登录状态、购物车内容等,简化会话管理并提升用户体验。
  3. 消息传递:实现异步消息通信,支持发布/订阅模式,适用于事件驱动架构和分布式系统。
  4. 计数器:存储和递增计数器值,用于跟踪网站访问量、用户交互等指标。
  5. 时间序列数据库:存储以时间戳为索引的数据,用于分析和可视化时间相关数据。
  6. 分布式锁和限流:用于协调并发访问共享资源、限制特定应用程序功能的使用等。

5.2. 能给我介绍一下Redis分布式锁是怎么体现的呢?有什么流程

关于Redis分布式锁的体现:

  1. 使用SETNX命令(SET if Not eXists)在Redis中设置一个锁的key,如果该key不存在,则说明获取到了锁。

  2. 设置锁的过期时间,防止锁忘记释放导致死锁。可以使用PIRE命令为锁key设置一个合理的过期时间。

  3. 在执行完任务后,使用DEL命令删除锁key,释放锁

5.3. 发布一批优惠券,如何来进行设计能够保证不会发生超卖的问题?

这种情况下,这种确实每个人只能用,先要考虑他是每个人是否能多次抢。如果每个人只能抢一次的话,就要对就每个用户你要对每一次进行抢锁的时候,你要先对这个线对用户线程加一个锁。最后当他他他先会判断这个锁,先判断这个券他有没有还有没有剩余。如果有剩余的话,先看这个用户有没有用户线程有没有获取到这个锁。如果获取到锁的情况下,他才能来抢到这个券。如果他没有这个现成的话,他只能只能等待或者就是被。

5.4. 可以基于哪种锁来进行设计?

设计锁的话,我感觉这里可以设计个基于ReentrantLock,它可以有它有那个抢占式的锁。然后你每个用户你可以每不同的用户同时过来的话,你看哪一个他有他会抢到这个锁,就不用比那种公平锁的话,它需要每个用户先来先服务。在这种情况下不是很合适的

5.5. 你觉得这种券可以放到redis里面吗?说一下原因

Redis我感觉有点不太合适,因为redis是基于缓存的。你。你缓存的话,它缓存跟如果把这些券的把这些券的数量存到数据,存到通过mysql同步,放到redis里面进行缓存。这个时候有可能会造成缓存不能及时的清理掉。(面试官补充到存到redis里面就算不设置过期时间,也只是一个key存在,并不会影响性能,所以其实是可以存入redis里面的)

我进行了一些分散的阐述:

对正常来说这种来说通常是因为有两种方式。一种是通过总数每次递减,每次得到一个减1,也可以是初始是零,然后每次加一加加法的话,你可以可以得到可以得到一个总数。然后减就是每一次加你可以知道它一个调用的次数,而不用再单独再设置一个剩余次数。

5.6. 如果此时新增了5000张券,这种情况下基于哪种设计更合适呢?

这种就加的方式合适吗?因为你原来是5000个。你如果要减的话,减到已经减到零了,你要再加5。再你如果此时再发放5000了,你要还难道还从0到负-5000吗?这时候你要通过加的话,你如果是5000,你此时只要比较,如果这个加加到1万的时候停了就行了。我感觉如果这个时候加的话更好一点。

5.7. Redis常见数据结构

Redis常见的数据结构包括:

  1. 字符串(String) :最基本的键值对存储类型。
  2. 列表(List) :按照插入顺序排序的字符串列表。
  3. 集合(Set) :不重复的无序字符串集合。
  4. 有序集合(Sorted Set) :不重复的无序字符串集合,但每个成员都会关联一个double类型的分数,Redis正是通过分数来为集合中的成员进行从小到大的排序。
  5. 哈希(Hash) :键值对集合,是一个string类型的field和value的映射表,hash特别适合用于存储对象。
  6. 位图(Bitmaps) :位图不是一种实际的数据类型,而是一种特殊的字符串对象,它使用二进制位来进行存储,从而节省空间。
  7. 超日志(HyperLogLog) :用于进行基数统计的算法,在Redis中提供了对应的实现。
  8. 地理空间索引(Geo) :用于存储地理位置信息,并支持基于位置的查询。

5.8. ZSet底层实现

Redis中的有序集合(Sorted Set)是通过跳跃表(Skip List)和哈希表(Hash Table)来实现的。跳跃表用于实现有序集合的排序功能,而哈希表则用于存储成员和分数的对应关系。这种组合方式既保证了数据的有序性,又提高了数据的查询效率。

5.9. 实现附近用户功能

实现类似微信附近用户的功能,通常需要使用地理位置信息,并结合Redis或数据库进行范围查询。以下是一种可能的实现方式:

  1. 收集用户地理位置信息:用户在注册或登录时,可以收集其地理位置信息(如经纬度)。
  2. 存储地理位置信息:将用户的地理位置信息存储到Redis的有序集合(Sorted Set)中,以用户的ID作为成员,以地理位置信息(如经纬度)计算得到的某种值(如geohash)作为分数。
  3. 范围查询:当用户需要查找附近的用户时,可以根据当前用户的地理位置信息计算出一个范围(如半径为X公里的圆形区域),然后使用Redis的有序集合范围查询功能,查找分数在这个范围内的所有用户。
  4. 优化性能:为了提高查询效率,可以使用Redis的geospatial功能,它提供了基于地理位置的查询接口,可以更方便地实现类似的功能。

在 Redis 中实现一个可重入锁(Reentrant Lock)需要一些额外的逻辑来确保同一个客户端(或线程,在分布式环境中通常是客户端)能够多次获取同一个锁,而不会造成死锁。在传统的 Java 并发库中,ReentrantLock 允许锁的拥有者重新进入锁,而不会阻塞。但在 Redis 这样的分布式环境中,由于锁是跨多个进程的,所以我们需要模拟这种行为。

5.10. 你说的redis的分布式限流,你是用什么做的?

我第二个项目是通过radiation的一个RateLimeter,它是底层是基于令牌桶算法实现的。一般来说限流算法还有固定窗口以及滑动窗口,还有第一那个令牌桶,还有那个低桶那个词滴桶法,基本就那那。

我这个就limit那个RateLimeter底层是基于令牌桶算法的,每次请求每一个请求方法都会都会来给你颁发一个令牌。如果你拥有这个令牌的话,你就可以正常检修。如果没有这个令牌的话,你要不就是等,要不就是一直阻塞等待,要不就是这个请求被拒绝。

5.11. 底层令牌令牌桶底层是底层了解过它的。

按道理来说radisson里面应该是一个lua脚本的。

5.12. 他是怎么样去做到你说的这个实现一个令牌桶?

底层的话他就给一个固定的令牌桶数量,每次请求会将这个令牌桶的数量加1。如果他如果到达这个令牌总的数量的时候,令牌总就不会再进行对他对请求进行一个颁发。

5.13. 下面是一个使用 Redis 实现可重入锁的基本思路:

5.13.1. 1. 使用 Redis 哈希(Hashes)记录锁的状态

由于 Redis 本身不直接支持可重入锁,我们可以使用 Redis 的哈希数据类型来存储锁的状态,包括锁的持有者、锁的计数(即重入次数)等信息。

5.13.2. 2. 锁的实现步骤

5.13.2.1. a. 初始化锁

在 Redis 中,对于每个锁,我们可以使用一个哈希键来存储相关信息,例如:

  • lock:key:owner:存储锁的持有者标识(如客户端ID或唯一标识符)。
  • lock:key:count:存储锁的重入次数。

5.13.2.2. b. 尝试获取锁

  1. 检查锁是否已存在:使用 HGET 命令检查 lock:key:owner 是否存在。
  2. 如果锁不存在
    • 使用 HSETNX 命令尝试设置 lock:key:owner 为当前客户端的ID,并设置 lock:key:count 为 1。如果 HSETNX 成功,表示锁被成功获取。
    • 设置锁的过期时间(使用 EXPIRESETEX),以防止锁永远不会被释放。
  1. 如果锁已存在
    • 检查 lock:key:owner 是否与当前客户端的ID相同。
    • 如果相同,则使用 HINCRBY 命令增加 lock:key:count 的值,表示锁的重入次数增加。
    • 如果不同,则当前客户端无法获取锁。

5.13.2.3. c. 释放锁

  1. 检查锁的持有者:首先确认 lock:key:owner 是否与当前客户端的ID相同。
  2. 减少重入计数:如果相同,使用 HDECRBY 命令减少 lock:key:count 的值。
  3. 如果重入计数为 0:删除整个哈希键(lock:key:ownerlock:key:count),释放锁。

5.13.3. 3. 注意事项

  • 锁的过期时间:必须设置过期时间以避免死锁,但这也可能导致客户端在持有锁期间由于过期时间被意外释放锁。
  • 客户端故障:如果客户端在持有锁期间崩溃,锁可能会被永久持有。可以通过设置 Redis 的持久化策略和监控机制来减轻这个问题。
  • 性能考虑:在高并发场景下,Redis 的性能可能会成为瓶颈。可以通过优化 Redis 的配置、使用 Redis 集群或使用其他分布式锁服务来改进性能。

5.13.4. 4. 使用 Lua 脚本

由于 Redis 支持 Lua 脚本的原子执行,可以使用 Lua 脚本来确保上述步骤的原子性,从而避免在分布式环境中可能出现的竞态条件。

通过这种方式,我们可以在 Redis 中实现一个基本的可重入锁机制,尽管它可能不如在单进程环境中使用本地锁那样高效或简单。

5.14. 然后您这里提到了说分布式限流,你能具体介绍一下吗?是怎么实现分布式限流的?

分布式限流一般限流是我们这里是通过redis的reatimit以及lun脚本来实现的一个分布式限流。它的底层是一个令牌桶算法。令牌桶算法的话,他每一次请求他会来,他他会给你分配一个令牌。然后你如果拥有这个令牌的话,你就会可以保证这个请求是有权限的。如果没有这个令牌的话,你可能就需要在这里等待,或者等有令牌的时候再释放,也有可能会被拒绝。

6. (7道)熟悉RabbitMQ消息队列,有过手动消息确认、消息持久化、交换机队列定义、消息生产消费的实践。

6.1. MQ(消息队列)的用途

MQ(Message Queue)是一种用于在不同应用程序或系统之间异步传输消息的中间件。其主要用途包括:

  1. 流量消峰:当服务器面临大量请求时,通过MQ进行流量缓冲和分批处理,避免服务器被压垮。
  2. 异步解耦:实现上游系统和下游系统的异步调用,降低系统间的耦合度,提高系统的可扩展性和可维护性。
  3. 数据收集:在分布式系统中,通过MQ进行数据采集和聚合,如业务日志、监控数据、用户行为等。
  4. 消息通信:支持不同系统或应用之间的消息通信,实现松耦合的系统架构设计。

6.2. MQ核心部分

MQ(消息队列)的核心部分主要包括:

  1. 消息生产者(Producer) :负责生产(发送)消息到消息队列中。
  2. 消息队列(Broker) :负责存储和转发消息。它可以是单机部署,也可以是集群部署,以提供高可用性和扩展性。
  3. 消息消费者(Consumer) :负责从消息队列中拉取(或推送)消息并进行处理。

6.3. MQ保证消息可靠性

MQ保证消息可靠性主要依赖于以下几种机制:

  1. 持久化机制:将消息持久化到磁盘上,以防止消息队列服务崩溃导致的数据丢失。
  2. 确认机制:消费者处理完消息后,向消息队列发送确认信息,以确保消息被正确处理。如果消费者在处理消息过程中崩溃或失败,消息队列可以将该消息重新发送给其他消费者。
  3. 事务性消息:支持事务性消息,确保消息的生产和消费在同一个事务中完成,以保证数据的一致性。

6.4. 那你消息机制了解吗?

消息推送一般有webSocket还有Sse

6.5. 他是怎么推?原理是了解过吗?

他是一般是通过NIO或者IO操作。一般来说是比如一对一的那种请求的话,它是给一个通相当于把消费者跟生产者那种关系生产一个消息,然后通过消息中间键转发。然后如果有消息的话,他消费者会从这个消息这个池子里面获取到一条消息。如果那种有广播那种广播的话,如果有一条消息就会把这个消息传给每一个人。

6.6. 回调用过吗?

回调我们第二个项目的话,它是通过MQ异步调用的话,然后他如果因为你要分析一个数据的话,它是需要时间的。然后你上传你的需求之后,他会先告诉你这数据正在分析中,然后等然后通过MQ进行一个异步的操作。如果他分析成功之后,它会给你个回调函数,然后告诉你这个分析结果成功了。分析结果成功之后,用户得到这个消息就可以查看你的那个图表了。

6.7. 那接口是怎么用的呢?

它回调的话,它有一个一异步回调一个Callable它是可以可以可以有一个返回指的。

7. (10道)熟练使用 Linux 系统的相关操作命令,能使用命令监控系统负载和进程状态;能够通过宝塔或者Docker容器在云服务器上完成对项目的部署。

7.1. 是否熟悉Linux命令,如何查看Java的进程信息

7.2. 我看你的简历里面写了一个用ps -ef | grep java 什么情况下会用到这个命令?

这行指令一般就比如有一些端口端口号占用,可以根据这个命令来查看有哪些端口有占用情况,然后对端口进行一些杀清除,这个端口进行一个清除。(面试官说这里查的是PID,跟这个命令不对应)

7.3. 你对于linux或者说有了解吗?

因为我们上线就对一些项目进行上线的时候,是要有的是在linux上进行上线的,所以说有一些基本的命令是了解的。

7.4. 您现在已经打好了一个jar包了,然后这时候您需要说把这个教包传到服务器上面,把它给运行起来。然后这个过程当中您都需会用到哪些命令?

一般我们通过上传工具把它先上传到本上,把这个价包上传到linux服务端

7.5. 用什么实现上传?

xftp

7.6. 现在就在另外一台服务器上面,您需要把这个文件把它传到另外一台linux服务器上面,这时候你会怎么操作?

这个时候可以用WEGT那个。远程下载的那个包那个命令。

7.7. 但是假设说我存在服务器A的home目录下面有一个web点卷是吧?现在我什么服务都没有,我能在B服务器上面也能拿到这个web点赞。Wget只能下载HTTP的资源吧。

这个好像还没真还真没了解过。

7.8. 443端口号被占用,如何找到对应的端口号,并把该端口杀掉?

一般在linux上的话,有一个NET nice start那个命令,可以查看那个443的端口以及它的占用情况。然后找到对应的端口端口号的那个PID的话,可以通过就有一个PSPS杠EF管道氟加EP根据那个PID找到对应的嗯哪一个进程在监听,然后对这个进程把这个进程用kil命令杀掉。

7.9. 如果443端口号是导师使用的端口号,不能杀掉,如何最快的解决端口冲突问题?

了解的不是很多

7.10. 刚才提到docker,docker里面的端口映射有了解过吗?或者目录映射。可以动态的更改吗?

一般来说它它每一个拉取的一个镜像,它都有一个doctor里面,它会给你单独他分了一个分了一个目录以及那个包。然后你要想把你本地的一个linux本地的那个包进行映射的话,需要要执行一个执行。你需要在启动这个镜像的时候,要输入一个对应的一个映射的一个命令,然后把彼此对应起来。

8. (3道)熟悉 Nacos 和 Dubbo RPC 框架,能够使用 Spring Cloud Gateway 实现 API 网关、访问控制,了解Spring Cloud常用组件, 如Eureka注册中心,Fegin 远程调用,Ribbon 负载均衡。

8.1. 你最近实现了这个一个接口平台项目,可以讲一下SpringBoot和Dobbu是什么关系,有什么区别?

关于Spring Boot和Dubbo的关系和区别:Spring Boot是一个快速构建基于Spring框架的应用程序的工具,可以简化Spring应用的开发过程。Dubbo是一个高性能的分布式服务框架,用于协调不同服务之间的通信和调用。Spring Boot可以和Dubbo进行整合,使得Dubbo框架可以更方便地在Spring Boot应用中使用。两者的关系就像是Spring Boot是一个构建应用的工具,而Dubbo是一个用来实现分布式服务的框架。

8.2. 网关的核心概念

网关是网络通信中的一个关键组件,它负责在不同网络或系统之间进行协议转换和数据交换。以下是网关的核心概念:

  1. 路由
    • 网关的核心功能之一,负责根据一定的规则(如URL、请求头等)将请求转发到目标服务器或系统。
    • 路由通常由ID、目标URL、一组断言(Predicate)和过滤器(Filter)组成。
  1. 断言(Predicate)
    • 用于匹配HTTP请求中的所有内容(如请求头、请求参数等)。
    • 如果请求与断言相匹配,则进行路由转发。
  1. 过滤器(Filter)
    • 在请求被路由转发前或之后对请求进行修改处理。
    • 过滤器可以用于参数校验、权限校验、流量监控、日志输出等多种场景。

8.2.1. 路由转发和请求断言

  • 路由转发:网关根据路由规则将请求转发到目标服务器或系统。这通常涉及到URL的匹配、请求头的修改等操作。
  • 请求断言:在路由转发之前,网关会对请求进行一系列的检查(即断言),以确保请求满足一定的条件(如用户已登录、请求参数有效等)。如果断言为真(即请求满足条件),则进行路由转发;如果断言为假(即请求不满足条件),则可能返回错误信息或进行其他处理。

这些概念共同构成了网关的核心功能,使得网关能够在不同网络或系统之间安全、高效地传输数据。

8.2.2. 什么是RPC框架?可以讲一下吗?RPC它的核心功能是有哪几部分呢?

Dubbo是一个由阿里巴巴开源的高性能、轻量级的Java RPC(远程过程调用)框架,它致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA(面向服务的架构)服务治理方案。Dubbo在分布式系统中扮演着重要的角色,特别是在服务拆分、服务治理、服务注册与发现、负载均衡等方面具有显著优势。以下是对Dubbo的详细介绍:

8.3. 一、Dubbo的核心特点

  1. 高性能:Dubbo采用了Netty等高性能通信框架,支持高并发、低延迟的通信。同时,它提供了多种负载均衡策略,能够智能感知下游节点的健康状况,显著减少调用延迟,提高系统吞吐量。
  2. 透明化的RPC服务调用:Dubbo使得远程方法调用就像调用本地方法一样简单,开发者无需关心远程调用的底层细节,只需简单配置即可实现服务的输入输出功能。
  3. 服务注册与发现:Dubbo内置了服务注册中心,支持多种注册中心服务,如Zookeeper、Nacos等。服务提供者启动时向注册中心注册服务,消费者订阅所需服务并获取提供者地址,实现服务的自动发现和管理。
  4. 集群容错:Dubbo提供了丰富的集群容错机制,包括失败自动切换、快速失败等策略,能够有效提高系统的稳定性和可用性。
  5. 高度可扩展:Dubbo遵循微内核+插件的设计原则,所有核心能力如Protocol、Transport、Serialization等都被设计为扩展点,支持第三方实现。

8.3.1. 二、Dubbo的主要组成部分

  1. Provider(服务提供者) :暴露服务的服务提供方,启动时向注册中心注册自己提供的服务。
  2. Consumer(服务消费者) :调用远程服务的服务消费方,启动时向注册中心订阅自己所需的服务。
  3. Registry(服务注册中心) :服务注册与发现的中心目录服务,负责服务地址的注册与查找。
  4. Monitor(监控中心) :统计服务的调用次数和调用时间的日志服务,用于监控服务的运行状态和性能指标。
  5. Container(服务运行容器) :负责启动、加载和运行服务提供者。

8.3.2. 三、Dubbo的应用场景

  1. 微服务架构:Dubbo框架提供了服务治理、集群容错、负载均衡等功能,适用于构建大规模微服务架构。
  2. RPC远程调用:Dubbo框架基于RPC协议进行远程调用,适用于构建分布式系统中不同服务之间的通信。
  3. 分布式服务治理:Dubbo框架提供了服务注册、发现、动态路由等功能,适用于管理分布式系统中的服务。
  4. 高性能通信:Dubbo框架采用了Netty等高性能通信框架,支持高并发、低延迟的通信,适用于对通信性能要求较高的场景。
  5. 服务监控:Dubbo框架提供了丰富的监控功能,可以监控服务的运行状态、性能指标等,适用于需要对服务进行实时监控和管理的场景。

8.3.3. 四、Dubbo的优缺点

优点

  • 高性能、轻量级,适合分布式系统。
  • 透明化的RPC服务调用,开发简单。
  • 丰富的服务治理功能,提高系统稳定性和可用性。
  • 高度可扩展,支持多种注册中心和协议。

缺点

  • 主要针对Java语言,对其他语言支持不够完善。
  • 扩展性有限,某些特殊场景下的需求可能无法满足。
  • 监控和管理功能相对简单,对于大规模服务实例的管理可能不够强大。

总之,Dubbo作为一个优秀的分布式RPC框架,在分布式系统中具有广泛的应用前景。它以其高性能、轻量级、灵活性和可靠性等特点,成为了分布式服务调用的重要工具之一。

9. (4道)熟悉并实践过多种设计模式,比如工厂模式、装饰者模式、双检锁单例模式、代理模式等

9.1. 介绍一下策略者模式

策略者模式是一种行型设计模式,它以一种灵活的方式在多个算法中进行选择。策略者模的核心思想是将算法独立于客户端使用,并将不同算法封装成不同的策略类,使得这些算法可以互替换,而不影响客户端的使用。

在策略者模式中,通常会含以下几个角色:

  • 策略接口(Strategy Interface):定义了策略类的公共方法,用于声明不同策略类的抽象行为。
  • 具体策略类(Concrete Strategy):实现了策略接口,包含了具体的算法逻辑。
  • 环境类(Context):维护一个对策略接口的引用,用于执行具体的策略算法。客户端通过环境类与策略类进行交互。

策略者模式的优点有:

  • 提高了代码的灵活性和可扩展性客户端可以根据需要选择不同的策略,而不需要修改原有的代码。
  • 降低了具体略类与客户端之间的耦合:策略类可以独立维护和改变,对客户端来说是透明的。

策略者模式适场景包括:

  • 当一个系统需要动态地在多个算法中选择一种时。
  • 当一个类有多个行为,而不希望使用大量的条件语句来判断时。
  • 当一些相关的仅在行为上略有不同时,可以使用策略者模式来避免重复的代码。

需要注意的是,策略者模式并不适用于所有情况,如果策略类数量较少且不经常改变,或者算法逻辑非常简单,可以使用简单的条件判断来解决问题。

9.2. 介绍一下工厂模式

工厂模式(Factory Pattern)是种创建型设计模式,它提供了一种封装对象创建过程的方式,隐藏了具体实例的创建细节。工厂模式通过定义一个创建对象的接口,但将具体的实例化操作交给子类来完成,从而实现了对象的创建和使用的解耦。

在工厂模式中,通常会包含以下几个角色:

  • 抽象产品(Product):定义了产品的公共接口,是接口或抽象类。
  • 具体产品(Concrete Product):实现了抽象产品接口,是具体的产品对象。
  • 抽象工厂(Factory):定义了创建产品的接口,可以是接口或抽象类。通常会包含一个或多个创建产品的方法。
  • 具体工厂(Concrete Factory):实现了抽象工厂的方法,负责创建具体产品对象。

工厂模式有多种变体,包括简单工厂模式、工厂方法模式和抽象工厂模式。

  • 简单工厂模式(Simple Factory Pattern):也称为静态工厂模式,是通过一个工厂类来实现对象的创建。客户端通过向工厂类传递指定的参数,工厂类根据参数的不同来创建不同的产品对象。
  • 工厂模式(Factory Method Pattern):定义了一个创建产品的接口,但具体的产品创建由子类来实现。每个具体的产品由对应的具体工厂来创建,客户端可以通过不同的具体工厂来创建不同的产品对象。
  • 抽象工厂模式(Abstract Factory Pattern):提供了一种通过组合多工厂类来创建一组相关或相互依赖的对象的方式。抽象工厂定义了一组创建对象的接口,每个具体的工厂负责创建一组具体的产品对象。

工厂模式的优点有:

  • 封装了创建对象的细节,客户端不需要关心具体的实例化过程。
  • 提高了代码的可扩展性和可维护,符合开闭原则。
  • 可以通过工厂类来控制对象的创建过程,方管理和修改创建逻辑。

工厂模式适用于以下情况:

  • 当一个类不知道它需要的对象的具体类型时,可以使用工厂模式动态的创建对象。
  • 当一个类希望由子类来指定创建对象的具体类型时,可以使用工厂方法模式。
  • 当一个类需要创建一组相关或相互依赖的对象时,可以使用抽象工厂模式。

需要注意,工厂模式并不是适用于所有情况,如果只有一个具体产品类,或者产品创建过程非常简单可以不使用工厂模式。

9.3. 他们分别涉及到了什么设计模式?

过滤器和拦截器分别涉及到了不同的设计模式,具体来说:

9.3.1. 过滤器模式(Filter Pattern)

过滤器模式是一种行为型设计模式,它允许用户使用不同的标准(过滤条件)对一组对象进行过滤操作,得到满足特定条件的对象子集。这种模式通过定义一系列可重用的过滤器,实现了对数据集合的动态过滤,且过滤逻辑可以方便地添加、修改或组合。

主要角色包括

  • Filter(过滤器接口) :定义过滤操作的统一接口,通常包含一个filter()方法。
  • ConcreteFilter(具体过滤器) :实现Filter接口,每个具体过滤器对应一种具体的过滤条件。
  • Target(目标集合) :待过滤的数据集合,可以是列表、数组或其他可迭代的数据结构。
  • Client(客户端) :负责创建具体过滤器,并将它们应用到目标集合上。

优点

  • 将对象的过滤、校验逻辑抽离出来,降低系统的复杂度。
  • 提高了代码的复用性和可维护性。

缺点

  • 如果过滤器数量较多或处理的数据量很大,可能会导致性能下降。

9.3.2. 拦截器模式(Interceptor Pattern)

拦截器模式是一种在请求被处理之前或之后自动执行代码的设计模式,它允许开发者在方法调用之前或之后插入自定义行为,而无需修改原有的方法实现。这种设计模式在多种编程语言和框架中广泛使用,特别是在Web开发和企业级应用架构中。

主要角色和原理

  • Interceptor(拦截器接口) :定义了在业务逻辑执行前后插入自定义行为的组件的接口。
  • InterceptorImpl(拦截器实现) :实现了拦截器接口的类,具体定义了拦截逻辑。
  • Target(目标对象) :被拦截的对象,通常是业务处理逻辑。
  • TargetInvocation(调度器/拦截器链) :负责管理和调度拦截器的组件,按照一定的顺序将请求传递给拦截器链中的每个拦截器,并控制请求的最终处理。

优点

  • 透明性:拦截器对于请求处理流程中的其他组件是透明的,即它们不需要知道拦截器的存在。
  • 灵活性:可以轻松地添加、删除或修改拦截器,而不需要修改被拦截的代码。
  • 重用性:拦截器可以被多个组件或请求重用,减少了代码冗余。
  • 关注点分离:拦截器允许将横切关注点(如日志记录、事务管理、安全检查等)从业务逻辑中分离出来,提高了代码的模块化和可维护性。

总结

过滤器模式主要用于数据的过滤处理,通过定义一系列可重用的过滤器实现动态数据过滤;而拦截器模式则更多用于在请求处理前后插入自定义行为,实现横切关注点的分离和复用。两者虽然都是处理流程中的“中间件”,但应用场景和目的有所不同。

9.4. 那你先说一下你这边比较熟悉的设计模式,什么样的熟悉的设计模式?

一般来说有单例模式,单例模式的话它有懒汉式饿汉式,以及懒汉式饿汉市还有一种。但是的情况下,一般单单列是一般它只进行一次初始化,后面就不用再进行初始化了。

就是有策略模式,策略模式的话他你有一些代码当中,如果有很如果有就那种那种一些冗余的那种代码。比如很多if的情况下,它可以通过策略者模式来进行一种优化。它相当于是你可以对他进对他通常他有一个策略接口,然后他然后有几个实现具体实现这个策略接口的一个实现类,然后再给一个统一的一个请求这个策略的一个中间的一个环境。然后你可以自定义的选择,选择用哪种策略。这种策略这种设计模式的优点的话,它可以更加的让代码更加灵活,同时也有很强的扩展性。如果你有你想扩展一个别的策略的话,你只需要继承这个接口就行了。

然后的话还有工厂模式。工厂模式的话它相当于提供了一个工厂,可以封装的创建一个工创建对象。您正常来说,你每个产品都要有一个对应的一个生产这个产品的工厂。这个时候用工厂模式的话,就把产品也产品筹划抽象了一下,把工厂也抽象。然后如果你想要实现这个产品的话,你就对这个抽象的产品进行一个聚成工厂。你要是有很多个工厂的话,你想要实现哪种工厂,你就对这个抽象工厂进行一个实现。这种工厂的话你就用户只需要用户只需要关心那个。相当于是你用户不用关心他他这个产品是来自哪个工厂,你只需要知道你已经你得到了这个产品。同时的话也是可以提高代码的可扩展性和可维护性。

10. (2道)操作系统

10.1. 理解的LRU大概它是一种怎么样的一种算法?它一般会用在什么样的场景下最近最少使用?

LRU(Least Recently Used)算法是一种内存管理算法,它根据数据的最近使用情况来决定哪些数据是最不常用的,进而将这些不常用的数据从缓存中淘汰出去。LRU算法的基本原则是,当有新的数据访问时,如果缓存中已经存在该数据,则将它移到最近使用列表的末尾;如果缓存中不存在该数据,则将其添加到最近使用列表的末尾,并在缓存中总容量不足时淘汰最近使用列表头部的数据。

LRU算法一般用在缓存系统或页面换算法中,最近最少使用的数据通常很可能不会再被使用,因此优先淘汰这些数据可以提高性能。

10.2. LRU你使用的Map,但似乎没有办法实现更新最近访问的,如何去实现这个新旧数据的这样一个排序呢?应该选择那个数据结构?

实现LRU算法的数据结构可以选择双向链表和哈希表结合使用。双向链表可以维护数据的访问顺序,而哈希表用于快速查找特定数据是否存在,并且可以通过哈希表的移除操作来保持缓存大小的控制。

11. (7道)计算机网络

11.1. TCP和UDP有什么区别

TCP是它是报文传输,三次握手,四次挥手可靠传输,

UDP是那个那个帧传输。数据不安全,会造成数据丢失

11.1.1. 复盘:

连接:TCP 是面向连接的传输层协议,传输数据前先要建立连接;UDP 是不需要连接,即刻传输 数据。 服务对象:TCP 是一对一的两点服务,即一条连接只有两个端点。UDP 支持一对一、一对多、多 对多的交互通信

可靠性:TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按序到达。UDP 是尽最大 努力交付,不保证可靠交付数据。但是我们可以基于 UDP 传输协议实现一个可靠的传输协议,比 如 QUIC 协议 拥塞控制、流量控制:TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。UDP 则没有, 即使网络非常拥堵了,也不会影响 UDP 的发送速率。

首部开销:TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节, 如果使用了「选项」字段则会变长的。UDP 首部只有 8 个字节,并且是固定不变的,开销较小。

传输方式:TCP 是流式传输,没有边界,但保证顺序和可靠。UDP 是一个包一个包的发送,是有 边界的,但可能会丢包和乱序。

11.2. 各自的使用场景有什么

TCP是点对点通信的,UDP可以一对一,一对多,多对多等。在HTTP1.0(不支持持久连接和管道化。)和HTTP1.1(支持同一个连接传输多个请求和响应。)都使用的是TCP进行传输,在HTTP2.0(还引入了头部压缩、服务器推送)换成UDP,利用QUIC协议进行传输(面试的时候答错了,实际是2.0是在1.1的基础上添加了多路复用,在3.0(目的是减少延迟和提高性能,支持更快的连接建立和更好的拥塞控制。)才基于UDP协议

11.2.1. 复盘:

TCP的使用场景:

  • 文件传输:TCP提供可靠的、有序的数据传输,适用于大文件传输,如下载、上传文件。
  • 邮件传输:TCP证数据的可靠性,确保电子邮件的完整性和正确性。
  • 网页浏览:TCP适用于HTTP协议,保证网页内容的准确传输,数据的可靠性要求较高。
  • 数据库访问:TCP提供可靠的数据传输,适用于数据库的查询、更新、事务等操作。
  • 远程登录:TCP提供稳定的连接,适用于远程访问服务器,如SSH协议。

UDP的使用场景:

  • 实时通信:UDP适用于实时性要求高的应用,如音频、视频通信,实时游戏等。UDP的低延迟和简单性对于实时性要求较高的应用非常适用。
  • DNS查询:UDP通常用于DNS查询,因为DNS查询需要快速,在不确定目标主机是否存活的情况下使用UDP比较合适。
  • 日志传输:UDP适用于日志传输场景,因为日志往往只需要传输,不需要可靠性和有序性。
  • 广播和多播:UDP支持广播和多播,适用于在局域网内广播消息或者发送给多个主机的场景,如视频直播。

11.3. 什么是子网掩码?

不会 随便答的说ip太少,通过子网掩码让更多人使用,

11.3.1. 复盘

子网掩码(Subnet Mask)一个用于划分 IP 地址的网络部分和主机部分的二进制数值。它通过与 IP 地址逻辑运算,来确定一个 IP 地址所在的网络。

子网掩码用于将一个 IP 地址分成网络地址和主机地址两部分。在 IPv4 地址中,子网掩码通常是 32 位的二进制数值。它的作用是将相应位置的 IP 地址位数标为网络部分和主机部分。

子网掩码中的网络部分用连续的1表示,而主机部分用连续0表示。这样就可以根据子网掩码的对位数判断哪些位是网络地址,哪些位是主机地址。

以一个例子说明,假设一个 IP 地址为 192.168.1.100,子网掩码为 255.255.255.0。将它们转换为二进制式后:

IP 地址: 11000000.10101000.00000001.01100100

子网掩码: 11111111.11111.11111111.00000000

根据子网掩码的对应位数,我们可以得出该 IP 地址的网络部分为 110000.10101000.00000001,即 192.168.1。而主机部分为 01100100,即 100。

子网掩码的用途是帮助计算机判断一个 IP 地址是否在同一个网络中。当两个 IP 地址和它们的子网掩码逻辑“与”运算后得到的结果相同,就说明它们在同一个网络中。这样,计算机可以根据子网掩码来决定将数据包发送到局域网内的哪个设备上从而实现网络通信。

子网掩码在网络规划和配置中扮演重要角色,它能够有效划分 IP 地,帮助实现有效的网络通信与管理。

11.4. 听说过防火墙吗?介绍一下

部署项目的时候都需要把端口号放开,不然访问不到,为了网络的安全,避免直接把ip暴露到公网下,造成一些数据丢失以及一些安全性能(面试官补充去保护未经允许的用户限制他的访问)

11.4.1. 复盘:

防火墙(Firewall)是一种网络安全设备或软件,用于监控和控制网络流量,保护计算机和网络免受未经授权的访问、恶意攻击和数据泄漏等威胁。

防火墙的要功能包括:

  1. 包过滤:防火墙可以根据预先定义的规则,检查数据包的源地址、目标地址、端口号等信息,决定是否允许或阻止数据包通过。
  2. 状态检测:防火墙可以追踪连接的状态,通过检查连接的状态信息,对连接进行控制和筛选。
  3. 身份验证:防火墙可以要求用户进行身份验证,确保只有获得授权的用户才能访问网络资源。
  4. VPN隧道:防火墙可以构建虚拟私有网络(VPN)隧道,通过加密和隧道技术,在公共网络上建立安全的连接,保护数据的机密性和完整性。
  5. 代理服务:防火墙可以充当代理服务器,代替内部客户端与外部服务器进行通信,隔离内部网络与外部网络,提高安全性。

防火墙可以设置不同的规则和策略,根据应用需求和安全级别,进行灵活的网络访问控制。它可以对入站和出站的数据进行过滤和监控,保护内部网络免受网络攻击、恶意软件和未经授权的访问。

防火墙可以是硬件设备,如网络安全设备、路由器,也可以是软件程序,如操作系统自带防火墙或第三方防火墙软件。在企业和组织的网络环境中,通会配置多层防御策略,包括边界防火墙、内部防火墙、主机防火墙等,以加强网络安全保护。

希望以上对防火墙的介绍能给你提供一些了解。如果还有其他问题,请随时提问。

11.5. 听说过ddos攻击吗?讲一下

可以使用第三方DDOS服务来防止。同时提高项目的逻辑

11.5.1. 复盘:

分布式拒绝服务(DDoS)攻击是通过大规模互联网流量淹没目标服务器或其周边基础设施,以破坏 目标服务器、服务或网络正常流量的恶意行为。

DDoS 攻击是通过连接互联网的计算机网络进行的。这些网络由计算机和其他设备(例如 IoT 设备) 组成,它们感染了恶意软件,从而被攻击者远程控制。这些个体设备称为机器人(或僵尸),一组 机器人则称为僵尸网络。 一旦建立了僵尸网络,攻击者就可通过向每个机器人发送远程指令来发动攻击。当僵尸网络将受害 者的服务器或网络作为目标时,每个机器人会将请求发送到目标的 IP 地址,这可能导致服务器或网 络不堪重负,从而造成对正常流量的拒绝服务。由于每个机器人都是合法的互联网设备,因而可能 很难区分攻击流量与正常流量。

常见的DDoS攻击包括以下几类:

网络层攻击:比较典型的攻击类型是UDP反射攻击,例如:NTP Flood攻击,这类攻击主要利用大流量拥塞被攻击者的网络带宽,导致被攻击者的业务无法正常响应客户访问。

传输层攻击:比较典型的攻击类型包括SYN Flood攻击、连接数攻击等,这类攻击通过占用服务器 的连接池资源从而达到拒绝服务的目的。

会话层攻击:比较典型的攻击类型是SSL连接攻击,这类攻击占用服务器的SSL会话资源从而达到 拒绝服务的目的

应用层攻击:比较典型的攻击类型包括DNS flood攻击、HTTP flood攻击、游戏假人攻击等,这类 攻击占用服务器的应用处理资源极大的消耗服务器处理性能从而达到拒绝服务的目的。

为了防范DDoS攻击,可以采取以下措施:

增强网络基础设施:提升网络带宽、增加服务器的处理能力和承载能力,通过增强基础设施的能 力来抵御攻击。 使用防火墙和入侵检测系统: 配置防火墙规则,限制不必要的网络流量,阻止来自可疑IP地址的 流量。入侵检测系统可以帮助及时发现并响应DDoS攻击。

流量清洗和负载均衡: 使用专业的DDoS防护服务提供商,通过流量清洗技术过滤掉恶意流量,将 合法流量转发给目标服务器。负载均衡可以将流量均匀地分发到多台服务器上,减轻单一服务器 的压力。 配置访问控制策略:限制特定IP地址或IP段的访问,设置访问频率限制,防止过多请求集中在单个 IP上。

11.6. HTTP和HTTPS的区别

HTTP(Hypertext Transfer Protocol)和HTTPS(Hypertext Transfer Protocol Secure)是互联网中用于数据传输的两种协议,它们在安全性方面存在显著差异:

  1. 安全性
    • HTTP:以明文方式发送内容,不提供任何方式的数据加密,因此安全性较差。
    • HTTPS:是HTTP的安全版本,通过SSL/TLS协议对数据进行加密,确保数据的机密性和完整性,同时使用数字证书来验证服务器的身份,防止中间人攻击。
  1. 端口
    • HTTP:默认使用端口80。
    • HTTPS:默认使用端口443。
  1. 应用场景
    • HTTP:适用于不需要高度安全保护的普通网站。
    • HTTPS:适用于需要保护用户数据安全的网站和应用,如电子商务网站、网上银行、社交网络等。

11.7. 在计算机网络里面,你能讲一下HTTPS的S是什么意思吗?

它是基于有一个TLS它这个安全协议,它基于这个TLS这个协议可以,对Http有一个安全的一个效果。

在计算机网络中,HTTPS 是超文本传输协议(HTTP)的安全,其中的 "S" 指代 Secure(安全)。HTTPS 通过使用加密协议来提供更安全的通信通道,以保护用户在网络上传输的数据的隐私和完整性。

当您在使用普通的 HTTP 进行通信时,数据是以纯文本形式传输的,没有任何加密,这意味着网络上的恶意用户可以截获和窃听传输的数据。这对于涉及敏感信息(如登录凭据、信用卡号码等)的网站来说是一种安全威胁。

为了解决这个问题,HTTPS 使用了一种称为 SSL(安全套接层)或 TLS(传输层安全)的协议来加密和保护数据传输。通过使用数字证书和加密算法,HTTPS 可以确保通的机密性、完整性和身份认证。

具体而言,HTTPS 使用了公共密钥加密(Public Key和对称密钥加密(Symmetric Key Encryption)的结合方式。公共密钥加密用于建立安全连接和进行密钥交换,而对称密钥加密用于实际的数据传输。

当您在浏览器中打开一个使用 HTTPS 的网站时,浏览器会与服务器进行握手,建立一个加密的连接。之后,所有通过该连接传输的数据都会经过加密,只有在服务器端才能被解密。

通过使用 HTTPS,网站可以为用户提供更加安全和可信赖的通信环境,确保用户的个人信息和敏感数据的保密性和安全性。

12. (6道)JVM

12.1. JVM垃圾回收机制

JVM的垃圾回收机制主要包括以下几种:

  1. 标记-清除(Mark-Sweep) :首先标记出所有需要回收的对象,然后统一回收被标记的对象。但这种方式会产生内存碎片。
  2. 复制(Copying) :将可用内存划分为大小相等的两块,每次只使用其中一块。当这块内存用完了,就将还存活的对象复制到另一块上面,然后再把已使用的内存空间一次清理掉。这种方式简单高效,但会浪费一半内存。
  3. 标记-整理(Mark-Compact) :先标记出所有存活的对象,然后让所有存活的对象都向一端移动,紧接着直接清理掉端边界以外的内存。这种方式避免了内存碎片的产生。
  4. 分代收集(Generational Collecting) :根据对象存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。例如,新生代中每次垃圾回收都有大量对象死去,只有少量存活,因此可以选用复制算法;而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清除”或者“标记-整理”算法来进行回收。

12.2. 有了解过加java里面有哪几种引用对象的类型吗?哪几种对象?

类型,弱引用类型,虚引用类型,软引用类型。

强引用话一般就很如果垃圾回收的话,很难被回收。弱引用还有后面的三个,如果垃圾回收的话,一定会被回收的

12.3. java里面是怎么确定我这个对象可以被回收的呢?

java里面垃圾回收的话,它他一般来说他对堆内存里面垃圾回收策略的话,他有个分在堆里面分为新生代和老年代。如果新生代里面有分为一个EDEN区,还有一个survivor层,两个survivor层有个S1一区还是S2区?因为eden,他是一个新加的进去的。所以说他如果进行垃圾回收的话,先从这里进行垃圾回收。

在这里垃圾回收,如果第一轮如果没有被回收的话,它会进入到S1或者S2区。如果等他在S1S2区有一个限度,一般来说默认是十六。如果到16的话还没有被回收的话,此时就会进入老年代。然后比如一些String以及一些实例化,一般就在老年代里面这种也会被回收。但是一般一般是在后面才会回收,很难被回收的。

12.4. 假设我这个A对象被其他对象持有的情况下,他会被回收吗?

不会被回收

12.5. 那那垃圾处理器它是怎么确定这个对象有没有被引用呢?

有没有被引用它有两种方法,一种是可达性分析,还有一种是给他设置一个值,就每每一次被调用的话会对他加一。然后如果如果销毁一次的话,就点一直到它没有再被引用的时候,他就可以对它进行一个回收。然后可达性分析的话,相当于是从根节点创建一个类似树一样的,从根节点到依次遍历到最最底端。如果他没有如果没有一个,如果他是能到达的话,说明他这个可达性的话就会对他进行一个回收。如果如果垃圾回收的话,就会对它进行一个回收。

12.6. 浏览器内我们输入www.baidu.com然后敲击回车,在敲击回车之后到页面渲染完成,这整个过程都经历了什么事情?

服务端如果敲击了这个回车的话,他会先。一般的话,他会先对你这个请求的这个URL进行一个解析,然后看你这个请求方法以及传输的协议,会把这个。会检查这个UIL里面有没有出现一些非法的一些非法的字符。然后对这个因为浏览器有缓存,如果你这个网站已经缓存过的话,它会先到缓存里看看是否有这个请求缓存。如果有的话,就直接把这个缓存返回过去。如果没有的话,网站会通过一个DNS,他会对你这个请求进行一个DNS的解析。解析他会找到本地的一个域名,对本地域名通过DNS解析,一步一步找到对应的那个端口IP地址。然后获取到IP址地址之后,通过一个MAC协议找到对应的一个本机的一个主机MAC协议。最后。通过这个协议找到对应的网关地址,然后就建立一个TCP的连建立TCP连接。连接之后,如果他是TCPI他如果他是ATTP的话,他就如果TCP连接的话,它会进行一个三次三次握手,四次挥手的一个过程。如果它是基于ATTPS的话,因为它是TTATTPS是一个比较安全的一个协议,他他一共有四次握手。当它建立连建立成完建立完建立完连接之后,它会有一个方法,比如get或post的方法来进行一个统一的请求。请求之后从后端获取到资源之后,再进行一个返回,把这个资源通过一个前端的一个映射器展示给前端用户来进行一个查看。

在浏览器内输入www.baidu.com并敲击回车后,到页面渲染完成,这整个过程经历了多个阶段,主要包括DNS解析、TCP连接、HTTP请求与响应、页面渲染等步骤。以下是详细的过程:

  1. 输入URL并回车
    • 用户在浏览器地址栏输入www.baidu.com并按下回车键。
  1. 浏览器解析URL
    • 浏览器首先会检查输入的URL是否完整,如果缺少http://https://这样的协议头,浏览器通常会默认使用http://
    • 然后,浏览器会识别出www.baidu.com是域名部分,而路径部分被默认为根目录/
  1. DNS解析
    • 浏览器通过DNS(域名系统)将www.baidu.com这个域名解析为对应的IP地址。DNS解析通常是由递归的DNS查询过程完成的,这个过程中会查询本地DNS服务器、根DNS服务器、顶级域DNS服务器等,直到找到对应的IP地址。
  1. 建立TCP连接
    • 浏览器通过TCP/IP协议与解析出的IP地址(即百度的服务器)建立连接。这涉及到TCP的三次握手过程,确保连接的可靠性和正确性。
  1. 发送HTTP请求
    • 连接建立后,浏览器会向服务器发送HTTP请求,请求类型为GET,请求的资源是/,即百度网站的首页。
    • HTTP请求中包含了诸多信息,如请求头(Request Headers),其中包含了浏览器类型、请求的资源路径、语言偏好等信息。
  1. 服务器处理请求
    • 服务器接收到HTTP请求后,会进行一系列的处理,如解析请求、查询数据库、生成响应内容等。
    • 对于www.baidu.com的GET请求,服务器会返回百度网站的首页内容,包括HTML文档、CSS样式表、JavaScript文件、图片等资源。
  1. 服务器响应
    • 服务器将处理结果以HTTP响应的形式返回给浏览器。响应中包含了状态码(如200 OK表示请求成功)、响应头(如Content-Type指定了返回内容的类型)以及响应体(即请求的资源内容)。
  1. 浏览器接收响应
    • 浏览器接收到HTTP响应后,会解析响应内容,并根据响应类型进行相应的处理。
    • 对于HTML文档,浏览器会解析文档结构,并构建DOM(文档对象模型)树。
  1. 页面渲染
    • 在DOM树构建完成后,浏览器会开始渲染页面。
    • 渲染过程中,浏览器会解析CSS样式表,并将其应用到DOM元素上,形成渲染树(Render Tree)。
    • 接着,浏览器会计算每个元素的布局(Layout),即确定每个元素在页面上的确切位置和大小。
    • 最后,浏览器会根据渲染树和布局信息,将页面内容绘制到屏幕上。
  1. 资源加载与优化
    • 在页面渲染过程中,浏览器还会并行加载HTML文档中引用的其他资源,如CSS文件、JavaScript文件、图片等。
    • 这些资源的加载可能是同步的,也可能是异步的,具体取决于资源的加载策略和浏览器的实现。
    • 为了提高页面加载速度,现代浏览器采用了多种优化技术,如资源预加载、缓存机制、异步加载等。

这个过程是复杂而迅速的,通常只需要几秒钟就能完成,但背后涉及到了网络协议、前端技术、后端技术以及大量的优化策略。

13. (42道)API接口项目

13.1. 项目的人员分工以及项目需求的分工是如何划分的?

13.2. 介绍一下这个项目及这个项目中比如说分哪些模块,然后你是做了哪个模块。

13.3. 在这个做的过程中,感觉有没有什么比较头疼的问题?

讲了鉴权功能

13.4. 是个比较通用的,还是之前遇到过什么?做那个什么优化。

比较通用的一个功能

13.5. 那你还搞了个网关,为什么当时为什么想搞这玩意儿?

为了鉴权以及统一处理请求并进行负载均衡(然后发散讲了一些)

13.6. 为什么要做转发?

因为项目是不同模块的划分,为了实现统一的鉴权,做一个网关实现路由转发来是完成

13.7. 聊到外层的模块和你的客户端的模块,对吧?那你能大概说一说你用到哪些技术吗?

13.8. 它最后是怎么样去连接数据库的吗?到底是用了哪个工底层的工具来连接数据库的呢?

13.9. 你可以稍微讲一下你的业务,你可以稍微讲一下你负责的业务?

13.10. 你这边有登录注册,修改密码这些,那就是你支持一个账号在多个地点登录?

13.11. 同时登录以后,有个人有一个账号对密码做了修改,那其他的账号会不会被踢掉呢?

13.12. 也聊到你这边有上线下线接口,这个你是怎么实现的?

13.13. 这个上线下线接口有什么用呢?下线之后不能使用是如何做到的?

13.14. 你现在上线和下线接口的时候,就比如说刚刚你不是你客户端可以在多个地方登录。那这个时候就比如说A登录了也B也登录了,对吧?然后假设A对一个接口进行上线,然后B同时对这个接口进行下线,那你怎么样保证他们的操作是有序的?

13.15. 整个这个项目的过程中,就是你觉得对你来说挑战比较大的一个事情是什么?

比如在设计实现 API 签名认证算法时,发现鉴权结果和预期不同 —— ak、sk 明明完全一致,但就是无法通过鉴权。然后你通过 debug 的方式,定位到了关键问题是由于中文编码、或者字段大小写不一致导致了签名不同。最后你通过修改中文编码等方式确保客户端和服务端生成的签名一致进行解决。

13.16. AK和SK是如何来实现用户的鉴权的呢

13.17. 你的第一个项目,你有去风控过他们的发帖子的内容吗?有去监控过他们的帖子发帖内容吗?

实现对帖子内容进行风控是一个相对复杂的问题,需要综合考虑多个方面,包括文本分析、规则引擎、机器学习等技术手段。下面是一种常见的实现思路:

  1. 敏感词过滤:建立一个敏感词库,包含一些不允许出现的关键词或短语。对新发表的帖子内容进行敏感词过滤,如果检测到敏感词,则拒绝发布或进行相应处理。
  2. 文本分类与文本匹配:利用机器学习或自然语言处理技术,对帖子内容进行分类,如骚扰广告、色情等。可以采用传统的分类算法或深度学习模型来训练分类器,并将新的帖子输入分类器中进行分类预测。
  3. 文本相似度匹配:对于重复发布或高度相似的帖子,可以通过计算文本相似度或采用哈希算法来发现重复内容,减少重复帖子的出现。
  4. 用户行为分析:基于用户的历史行为数据(如发帖频率、点赞、评论等),建立用户行为模型。通过分析用户行为模式,可以检测出一些异常行为,如恶意刷屏、灌水等,进而实施相应的风控措施。
  5. 人工审核与用户举报:引入人工审核机制,在发帖后对帖子内容进行人工审核。同时,也鼓励用户积极举报违规内容,通过用户反馈来进行风控处理。
  6. 不断更新与优化:不断收集数据并进行分析,优化现有的风控策略和算法,以应对新的风险。

需要注意的是,风控系统的设计与实现是一个综合性的问题,需要根据具体的业务需求、用户行为和平台特点进行定制化开发。同时,也需要遵守相关的法律法规与隐私保护政策,确保用户的合法权益和数据安全。

13.18. 你做这个项目之前,你有去了解过市场上其他平台的这种项目吗?还是说你自己独立设计的?

13.19. 你在里面负责什么内容?你觉得你负责的模块里面最难的是哪一部分?

13.20. 你这个项目的Dubbo用在了哪里?

13.21. 你为什么要把一个业务砍都砍出这么多模块出来?是用什么来去根据什么来划分这些模块的?

13.22. 你说你可以直接集成这个客户端SDK,那我API网关怎么统计你对这个客户端的调用情况呢?

13.23. 如果客户端安装自己的SDK的话,你客户端SDK更新了以后,你怎么怎么做一个适配或者说发布

13.24. 可能解决不了适配问题。比如说我有一个接口,我原来只要传三个参数,我老的业务只支持三个参数。那后面业务发生变动了,我需要传四个参数,那四个都是必传的那我新版的SDK发布了,我怎么让老的用户去使用我的新的SDK,或者说我怎么去把这个老APP适配掉?

13.25. 你当时写这个平台的时候,是为什么要写这个平台?你有去网上搜过这种在线接口平台的相关项目吗?

13.26. 那你现在专业接口平台第一版设计的时候,你都设计了哪些接口?

13.27. 这个项目写完以后,你自己最大的收获是最大收获?

13.28. 如果用过的SKAK泄露了怎么办?他用一个正常的AK使劲访问你,你有下线的操作吗?

13.29. 你那你对这个接口的请求频率什么之类的有做限制吗?如何实现的?

13.30. 项目的代码都是你自己写的吗?负责了哪些模块?

13.30.1. API虚拟认证算法是个什么?可以大概讲一下如何实现的吗?

13.31. 当然,除了MD5加密,市面上还有多种加密方式,这些加密方式根据应用场景和安全需求的不同而有所区别。以下是一些常见的加密方式:

13.31.1. 其他加密方式

  1. 对称加密算法
    • AES(Advanced Encryption Standard) :目前广泛使用的对称加密算法,提供高安全性。
    • DES(Data Encryption Standard) :较老的对称加密算法,虽然安全性不如AES,但在一些旧系统中仍然使用。
    • RC4:一种流加密算法,速度较快,但安全性存在争议,不推荐在新系统中使用。
  1. 非对称加密算法
    • RSA:最常用的非对称加密算法之一,用于加密小量数据、数字签名等场景。
    • DSA(Digital Signature Algorithm) :主要用于数字签名,确保数据的完整性和发送者的身份。
    • ECC(Elliptic Curve Cryptography) :基于椭圆曲线数学的加密算法,提供与RSA相同的安全性,但密钥长度更短,计算效率更高。
  1. 散列函数
    • SHA(Secure Hash Algorithm) :包括SHA-1、SHA-256、SHA-3等,广泛用于数字签名、文件校验等场景。
    • Bcrypt:一种专为密码存储设计的散列函数,通过增加计算复杂度和盐值来提高破解难度。
  1. Base64
    • 严格来说,Base64不是一种加密算法,而是一种编码方式,用于将二进制数据转换为ASCII字符串形式,以便于在网络中传输。

13.32. 可以简单介绍一下第一个项目的应用场景?

这主要是对于开一个软件开发的一个开发者来进行使用的。当然你用户的话,你也可以在线对一个对一些接口一些在线的一个调用。

主要对开发者来说的话,他可以对一些在这个平台上线的一些接口对进行一些。比如你有些功能需要一些接口,需要一些三方接口来实现。你可以在这个平台上来进行一些寻找。它会比如有一些你需要前端需要调用一个当日的每日的天气。在这个平台上你可以根据提供一个文档,在项目在自己的项目中进行一个接入。同时的话他也提供了一个SDK的一个工具包。本地的一个SDK你可以用开发者可以下载到本地,对这个项目进行一个整合到自己的项目中,大致是这样一个作用。

13.33. 你这个项目相当于是整合了第三方的接口然后进行SDK的一个开发吗?

也可以三方来接入自己,也可以上线一些自己的原创的一些接口。相当于是一个平就是一个也可以理解为你那种对所有的接口进行一个聚合,包括三方的以及自己的一些接口。

13.34. 本项目中你用到了Dubbo,请问在项目中起到了什么作用呢?

这个项目因为是分模块的,它在引入double它一个远程调用,对不同模块之间的一些接口进行一个远程的调用。可以个人开发者的话不用关心不同模块之间的一些远程的调用的传输协议,把它当成像本地方法一样实现不同模块间的调用。

13.35. 像你这种分布式的项目,你怎么部署的?比如说我有五个子模块,它们有相互依赖的关系的话

13.36. 那你先说一下在这个项目上面有没有让你觉得有挑战的地方?

因为这个项目我觉得学到更多的可能在AK和SK设计的那些那那一块。

你正常来说你我这个接口正常来说每个人调用的话,我不可能免费给你调用。一般来说是需要收费的。然后涉及到收费的话,你要就要采就要去就要防止一些用恶意用户来进行一个访问。这个时候我对每一个在我这个平台上注册的用户,我先注册,注册的时候已经给他生成一个默认,生成一个随机,生成一个AK和SK然后存到你的数据库里面。然后你如果要来访问我的数据库的时候,你要来访请求我这个接口的话,我会把请你把你的AK和一些请求头以及时间戳,或者加一些随机数,通过前通过这个请求头来进行一个加密算法。然后我们当时选的是MD5加密的。

加密完之后,如果因为我们是通过一个网关请求,请求都会统一进入到网关层。在网关层的话,它会通过你用户的ID然后查询到你这个数据库里面的AK通过AK然后再根据获得请求,请求头里面获取到那个随机数,以及你的请求的一个数据以及随机数,然后再进行一个MD5加密。

MD5加密后的一个数据,如果相等的时候,你我这个API接口这个提供者才能信任你这个调对我这个接口调用的对他产生了信任,这时候才能进行调用,否则的话他就不允许他调用。这时候可以防止有一些用户,有一些恶意用户,比如获取到你这个伪造一个请求,然后来恶意的攻击我这个API。

你这个AK跟SK跟oauto的认证是同一套体系吗?

类似。因为我们当时参考的是腾讯云以及一些阿里云。他当时你如果想要使他第三方平台一些OSOSS那种对象存储的话,他会给你提供一个AK和SK。我们当时是通过这来思考的那我在登录的时候,

13.37. 你们主要是在上面发布了哪些接口呢?

发布结果的话,我们有一些比如在线调试调在线桥每日的天气,以及根据一些就比如给一个相关的一个字段,然后返回你一个想要的一个图片吧。还有一些我们在别的一些我们当时写的别的项目,我们觉得可能后期会用到,然后就把这些封装到项上线到项目当中,然后可以对他进行后期一个项目开发进行一个复用。

13.38. 就是你这边统计接口的调用次数是怎么统计的?

因为我们当时想的是有3种,因为正常来说你前我你前端如果要访问我这个项目的话,有一种情况是你前端可以直接访问我这个模拟的这个接口。然后还有一种是通过后端,你前端先到后端,然后再通过后端来访问这个模拟接口。这种情况的话可以用一些NGINX这种来进行一个负载均衡。

但是我们考虑到NGX可能编程的话更复杂一些。我们这时候用的是SpringBoot gataway, 然后你前端先通先访问接口的话,都会通过先会请求到API网关层。网关层在网关中统一对一个次数进行一个计算。你到这个接口的时候,你先对你要请求哪一个接口,然后对这个进行计算之后,通过网关层来通过网关层来对你这个路由统一进行转发。转发到你对应的有一个接口,有一个模拟接口的一个模块。通过这个模拟接口的模块就可以进行真实的一个对接口的请求,直接就在网关层进行数据统进行这个次数的统计。

13.39. 涉及了API的签名认证的一个算法,给用户分配分分配了独立的那个AK用于健全,对吧?对,那那我想问一下你这个里面的话有没有防篡改相关的假设?

一般我们这个API签名认证算法的话,正常流程是你你你在注册的时候有生成这个AK和SK。你如果请求API的话,你会把这个AKAK1请求后等参数传过去。一般AK和SK是不可以被第三方获得的。你只传的时候只会传一个AK然后以及请求头以及时间戳还加了一个随机数,然后通过网关层来进行一个统一的拦截,然后进行健全。健全之后根据这个把根据请这个请求头这个加密的里面的获取到AK然后通过这个AK来查询它数据库里面真实的一个AK和SK,然后再进行一个MD5加密,然后两个对比之后才能如果相同的话,才能对这个请求者进行一个信任。如果中间人对他进行一个篡改的话,用用户如果觉得他这个用户如果觉得他这个请求的有一些异常的话,他他会申请对这个AK和SK进行一个重新生成。

对于数据的篡改并没有进行开发

13.40. 您在设计这个签名认证算法的时候,有没有参考过一些业界的一些认证。

比如说类似于一下阿里云或者腾讯云。

因为阿里云跟腾讯云,如果因为当时我们如果存储图片的话,当时是刚开始考虑的是腾讯云,阿里云的对象存储。他是给你提供一个你想要使用的话,他给你提供一个AK和SK。你可以在本地进行一个进行一个配置,然后再在yml文件里面进行一个配置。配置完之后,你就可以对图片进行上传以及下载了。当时是可当时是根据他这方面来进行一个实现的。

13.41. 您说解决多个子系统代码重复的问题,您抽象出了一些公共模块。那您具体抽象了哪些公共模块?然后抽象的一个原则是什么样子的?中间有没有用到什么样的一些设计模式?

因为我们这个公共模块层,它其实是包含了一些,就比如说各个模块有可能很多模块都需要使用到的一些实体类,还有一些公共场公共每个模块都要涉及到一些,就比如有一些方法类,或者就有一些封装的一些youtube那种封装的一些包,这些是在公共模块的。因为公共模块里面涉及的东西不是太多。当时分开的模块是主要是为了能够在因为我们当时的公共模块的话,如果要引用的话,是把它通过maven进行打包,然后在需要的模块里面进行引用就可以使用了当因为也模公共模块里面涉及到的东西也不是很多,也没有依据那个设计模式来划分。

13.42. 通过RPC框架实现子系统间的高性能接口调用,然后的话您的接口调用大概有多少的QPS?

14. (19道)智能BI项目

14.1. 下面这个BI平台的BI是指什么?那传统的BI是什么呢?你有用过我传统的BI吗?你有了解过市面上的一些其他的BI工具吗?本项目你负责了哪些模块

14.2. 如果上传的文件内容比较大的话,你怎么做分片处理的?你的Ai对接的哪些?

14.3. 你们有限制一个用户的访问量吗?比如说有限制这个用户的访问量之类的?是根据次数来计算的吗?

14.4. 也没有部署过项目,部署到哪里啦,讲一下项目部署的方法?

14.5. 第二个项目有什么功能可以简单介绍一下吗?

就是你比如传统的那种BI系统的话,我们当时写的时候调研过他是你必须有你正常来说先需要把一些数据进行一个一个上传,然后通过数据分析师来对这个数据分析之后,通过你选一个什么样的图表类型,然后再进行人工的一个数据分析师进行人工的一个分析,然后再得到一个分析的数据。然后我们这个就是相当于当时AI正式火的时候,我们就通过一个用户不用关心你这个,只要是一个普通的,不用专门去研究数据分析的。你一个普通的用户如果想要分析数据的话,只需要把你这个用户的一个相当于比如excel的一个文件上传上去,然后选择你想要生成一个图标,以及你对这些数据想要获得一个某个方面的。比如某一天的增长,某一天的用户的一个注册的用户的一个信息的增长率的一些数据,然后就可以上传上去。然后通过AI在后台,它会自动一个对这个用户的一个表格的一个分析,然后返回给你用户。用户的话可以在可视化的一个分析,然后看到你这个数据的一个诉求。

14.6. 可以讲一下你是如何来实现数据分析的这个功能,指定化的让AI进行分析呢?

就比如我后头台正常来说你要调试BI。然后我们这个就是比如你这个图表的一个数据,以及一个你的诉求,还有你这个图表的一个选择的图表类型。这三个数据会通过后台的一个分析,然后就相当于一个可以说原始一点就是类似jsp那样的一个一个挖孔。然后把这些数据通过pom预设的一个模板,传输给AI通过AI每次遇到调调校一下,通过多次的调校,然后让他分析,让他根据根据你那个模板来进行一个返回。我们通常会对他你我们这个模板一般来说的话用一个,比如你先给你一个身份信息。比如现在假定你是一个数据分析工程师,然后请根据我给你的这些数据,返回一个后返回一个基于一下前端的一下那个组件库的一个Jason说根据这个echars返回一个结果,然后前端的话根据返回的json来生成一个图表,就这样子。

14.7. 项目中提到用redis实现了限流,请问是如何实现的呢?

我这个是去通过redis的Redisson 的 RateLimeter。它是底层是基于令牌桶算法来进行一个限流。它就是你一个请求,如果想要对这个接口进行访问,他会从这个令牌桶里面给你分配一个令牌。你只有拥有这个令牌的话,你才能进行访问。然后当令牌里面当当这个令牌桶里面令牌没有的话,你只能等待或者被这个请求被拒绝,来保证防止一些同一时间段有有很多很多请求对系统造成一些影响。

14.8. 限流算法种类

限流算法主要有以下几种:

  1. 固定窗口算法:简单计数,在固定时间窗口内限制请求数量。但存在临界问题,即窗口边界处可能突发流量。
  2. 滑动窗口算法:通过维护多个时间窗口来解决固定窗口的临界问题,使得限流更加平滑。
  3. 令牌桶算法:以恒定的速率往桶中放入令牌,请求来时从桶中取令牌,如果桶中没有令牌则拒绝服务。这种方式可以应对突发流量。
  4. 漏桶算法:以恒定的速率处理请求,多余的请求直接丢弃或缓存。这种方式可以平滑流量,但无法应对突发流量。

14.9. 令牌桶算法操作及优点

令牌桶算法操作

  1. 令牌桶算法以一个恒定的速率往桶中添加令牌。
  2. 每个请求到达时,尝试从桶中取出一个令牌,若取到则允许请求通过,否则拒绝服务。

令牌桶算法优点

  1. 灵活性高:可以应对突发流量,因为桶中可以预先存储一定量的令牌。
  2. 控制能力强:通过调整生成令牌的速率和桶的大小,可以精确控制请求的通过率和突发流量的大小。

14.10. 令牌桶算法面对突发流量

如果你将令牌桶的容量设置为100,但在某个时段突然来了200多个请求,那么:

  1. 前100个请求会正常通过,因为它们可以从桶中取到令牌。
  2. 后100个请求会因为桶中令牌不足而被拒绝服务或进行等待,直到桶中有足够的令牌为止。

14.11. 可以讲一下数据库的分库分表的应用场景以及分库分表的时候需要注意的地方?

一般你如果你这个项目一一些数据比较小的话,你完全用不到分布分表,就可以对一些性能进行优化。如果要用到分布分表的话,可能就是你你这个系统的用户或者一些数据比较大,需要对他进行一些分分库分表。分库的话就相当于是把它把它设置,把它对对它进行一个分布式的一个数据库的一个部署。分表的话就相当于是对同一个表进行一个一个轮询,相当于轮比如你填你前端对他进行请求,一个数据库请求的话,会根据一个轮询,你对它不同的数据插入到不同的表中,对同一个分表是针对同一个表进行不同的一个划分。然后再库分表的情况下,可需要注意的是你要对你这个系统根据系统的根据你这个设计系统的一个架构,实现不同的一些方案。(这里答得不是很好,面试官让我后面再仔细看一下)

14.12. 如果针对一个订单表,每天会产生几千笔订单,一段时间内甚至系统会达到亿级别的,这种情况下如果c端和b端都想查看订单的数据,基于不同的权限如何来进行订单表的分库分表呢?

这种订单表的话,你就你针对用户端,用户端他只需要你你用户端的话只需要关心你自己的订单的信息。你这个时候你可以根据每个用户对他进行单独一个分表,就每一个用户拥有一个他自己的订单表。然后的话你用户有订单比较大,然后对一个管理员后台管理的话,他需要知道自己每个月的一个下单的数量。这个时候他他应该是。需要进行分表的。

14.13. 你讲到的这种情况只适合c端来看自己的 订单号,但管理员想看后台本月的订单情况,没有办法实现,这种情况下思考一下应该如何设计库表呢?

确实是没有想到这么多。

14.14. 能说一下你在那个BI的平台里面,你的线程池是怎么配?

我当时是用了一个,就相当于是一个核心线路,核心线程数等于最大限制数。你相当于是把这个我先就他俩相等的话,到时候就当核心线程数和最大线程数相等的话,就无法再增加线程了。这时候你因为你用户对一些数据进行分析的话。超过。他如果超过核心线程数的话,因为已经没有到位到线程的,他这个时候只能采用拒绝策略,或者如果还有请求的话,可以对他直接返回。你已经请求的次数过多,直接给他返回过去OK

14.15. 能具体的说一下,当时在部署这个项目的时候,服务器里面的配置跟你当前那个性能说你的实际里面配置的是什么样的一个情况。就比如说你的你比如你是4CPU?你的线程池里面你那个线程数配的是多少?然后你用的是什么样的一个队列,然后在你的那个实际的项目里面,你是用了什么样的一个拒绝策略?

我们在在这个项目中,我们用当时是部署了服务器的一个当时这个4核4G的一个服务器。当时我们线程线程数是设置的是一个设置的是一个六。就是如果你你达到一个核心线程数,同时因为它核心线数等于最大线程数,如果你超过这个限度的话,他会采用一个拒绝的策略。我们当时选的双端队列来进行一个对这个拒绝的策略,对这个拒绝的一个线程进行一个处理,相当于是如果如果你这个先这队列已经满的话,你就像可以返回一个数据,提示用户当前当前请求过载,请稍后再再进行。

14.16. 你的意思是说当我的队列满了之后,我就通过主线程去发送一个提示消息是吗?

对,让用户知道你可以等等流量等等这个请求的频率低的时候,你再进行一个分析。

14.17. 那你们的队列是怎么设置大小?

队列的话,我们当时设置的是一个双端设置的一个是是一个双双端队列大小的话。

14.18. 您的机器的配置是什么样子?

14.19. AI后台对接的是什么呢,如何进行使用的?

15. (两道)手撕算法

15.1. 哈希表找一个字符串一个找一个找一个定义好的一个字符串,找他第一个不重复的字符应该是怎么去写?复杂度是多少

Map存入每一个字符,判断value是否为一,为一直接返回就好,很简单的一道题

15.2. 知道递归的话,讲一下1--100的相加的递归如何实现

16. (46道)其他类别的(HR了解情况等)

16.1. 有实习吗?因为什么原因没有去实习

16.2. 简历上两个项目都是实验室写的吗?还写过其他别的项目吗?

16.3. 项目上线中有遇到偶发的bug吗?如何解决的?

16.4. 项目开发的目的是为了什么,有没有具体的业务场景,可以大概讲一下吗?

16.5. 你对前端的了解如何呢?熟练度怎么样?

16.6. 你在试验室主要负责什么呢?完成过什么项目呢?项目有多少个页面?

16.7. 远程使用若依框架开发一个需求,完成前后端的联调

统计的是这个用户表里面每小时的新增用户注册数量,前端用echar来进行页面的展示。

16.8. 自我介绍以及个人情况

16.9. 为什么想要来我们公司

16.10. 因为什么没有暑假实习?

16.11. hr开始介绍公司的业务以及主要的工作

16.12. 讲了一下技术和业务之间的关系

16.13. 本公司实习会给我带来哪方面的提高?

16.14. 目前是大四了吗?已经没有课了吗?

16.15. 你讲一下就是你在学校里面,你的后端的知识是通过什么方式来学习的。

我们大一的时候刚开学一个星期,他因为我们计算机学院它院内有很多那种相当于是为了学习相关的知识的一些社团。然后当时招新有很多社团在里面,选择了其中一个面试之后进去了。他会刚开始是先从java技术开始学学完之后可以学一些技术的一些前端,就比如HTML,CSS的样式,然后慢慢每每一个阶段做一个考核。然后到大一大一下的时候,基本上就我让你选择前后分流了,分流之后一般是给你一些方向,从serve light那些开始学。然后学完之后需要spin不spring,然后spin写一个项目之后,当时让把这个项目重构成一个springBoot。然后到后面的话,一般都是有一些是从B站上一些课程,还有一些是加入了一些一些就类似付费的那种来进行进行一个学习。

16.16. 那平时有看技术相关的书吗?

宿舍还有一本深入了解并发编程之美,java并发编程之美。还有有一个是关于我在微信读书上面有有好多当时存在一些技术文技术书籍,有一些是mysql的调优,还有一些图解mysql还有图解计组原理一些相关的书。

16.17. 那你感觉看书跟你在一些论坛或者是这种B站上面学东西,它的差别是什么?

刚开始你大一大二的时候不是很了解,那时候感觉看看书的话容易看不下去。那个时候刚开始看视频的话,就跟着视频敲敲写写,那时候感觉增长挺快的。但后面发现那些B站上一些视频,大部分只是教你去简单的用一下。但是输入的话你其实还要去阅读官方文档播放,其实有时候你看着也挺吃力的。而有一些他比如那些支付的相关的书籍的话,它它相对来说质量就稍微更高一点。

16.18. 那你对自己的职业规划是什么样的?

目前职业的规划就是走java后端方向。然后后期的话都说都说总不能肯定不能一直敲代码,到后面才慢慢进行一些职业方向的一些考虑。

16.19. 就是我问几个场景,比如说在你的工作过程中,然后与别人发生冲突的时候你会怎么办?

发生冲突的话,那这种情况就先看看是是双方谁的问题。如果有一些问题是实在是没有一些冲突是没办法进行调解的话,那你可以选择主动去你去向对方你寻求一个沟通。两者两个人坐下来好好聊一聊,把把有些事事情聊通。然后反正我觉得在工作上两个人的沟两个人的一些矛盾,大部分可以通过坐下来沟通来。一般来说没有太多的那种。

16.20. 那我再问一下,如果遇到有人跟你无理取闹你怎么办?

无理取闹。我感觉我个人的脾气的话其实还算好。如果是真的我无理取闹的话,我如果不影响我的话,我选择是不是很不是太关注。影响到你的影影响到我的话,那得看到哪种程度。如果说只是。道德层面的话,那我只能那那。法律层面的话,那寻求法律援助。

16.21. 你来之前对我们公司有什么了解吗?

对我我觉得你们公司我看到了解了一些,它是基于sas平台以及营销互联网上的一些活动会比如那些发发一些券的那种活动的

16.22. 讲一下你了解全栈吗?

因为我们在在开发过程中,有时候前端前后端的同学会相互的进行一个协作交流。全站的话就是从前端开发到后端开发全过程都要参与的一个。

全栈(Full Stack)开发是软件开发中的一个术语,指的是一个开发者能够处理应用程序开发过程中的所有层面,包括前端(也称为客户端)开发、后端(也称为服务器端)开发、数据库管理、系统架构以及可能还包括用户界面设计、用户体验设计、测试、部署和维护等。全栈开发者需要具备跨多个技术栈工作的能力,能够使用多种编程语言、框架和工具来完成项目。

16.22.1. 前端开发

前端开发主要涉及用户界面的设计和实现,包括使用HTML、CSS和JavaScript等技术来构建网页和Web应用程序。全栈开发者需要了解如何创建响应式和交互式的设计,提升用户体验。

16.22.2. 后端开发

后端开发是处理服务器端的逻辑和数据库管理的部分。这包括使用服务器端语言(如Node.js、Python、Ruby、Java等)和框架(如Express.js、Django、Flask、Spring等)来构建API(应用程序接口),处理用户请求,执行数据库操作等。

16.22.3. 数据库管理

全栈开发者需要了解数据库管理系统(如MySQL、PostgreSQL、MongoDB等),包括如何设计数据库架构、编写SQL查询、优化数据库性能等。

16.22.4. 系统架构

全栈开发者还需要有系统级别的思考,能够理解并设计整个系统的架构,确保系统的可扩展性、可维护性和安全性。

16.22.5. 用户体验和用户界面设计

虽然不是所有全栈开发者都直接参与设计工作,但了解用户需求和设计原则对于开发高质量的应用程序至关重要。

16.22.6. 测试、部署和维护

全栈开发者还需要了解如何编写测试用例、进行自动化测试、将应用程序部署到生产环境,并监控和维护系统的正常运行。

16.22.7. 优点和挑战

优点

  • 更高的灵活性:能够处理项目中的任何问题,减少团队间的沟通成本。
  • 更快的开发速度:全栈开发者可以在不同层面间快速切换,加速开发过程。
  • 更全面的理解:对整个系统有深入的理解,有助于做出更合理的设计决策。

挑战

  • 技术广度:需要掌握多种技术和工具,学习成本较高。
  • 技术深度:在某些特定领域可能不如专业开发者深入。
  • 工作负荷:全栈开发者可能会承担更多的工作量和责任。

总之,全栈开发是一种要求广泛技能和深厚理解的开发方式,适合那些希望全面掌握软件开发过程并愿意不断学习和挑战的开发者。

16.23. 讲一下你觉得全栈开发有什么好处?

开发的话,在我看来他会,因为你正常来说是前端跟后端分开开发的。如果作为一个全栈开发的话,它有一种能把把控全局,前端后端的业务都比较的清晰了解。可以,比如你从前端开从后端开始开发,开发完之后相关的需求你直接就可以从后端的视角来来用前端来进行一个开发,更更流畅。

全栈开发在软件开发领域带来了诸多好处,这些好处不仅体现在个人技能提升上,也体现在项目效率、团队协作以及技术创新等多个方面。以下是我认为全栈开发的一些主要好处:

  1. 提高项目效率:全栈开发者能够独立完成从前端到后端的开发工作,减少了团队内部不同角色之间的依赖和沟通成本。当项目中出现问题时,全栈开发者能够更快地定位并解决,因为他们对整个系统有深入的理解。这种能力可以显著缩短开发周期,提高项目交付速度。
  2. 增强团队灵活性:在小型项目或初创公司中,全栈开发者能够迅速适应不同的工作需求,填补团队中的任何技术空缺。这种灵活性使得团队能够更快地响应市场变化,调整产品方向,甚至在某些情况下,全栈开发者可以单独承担整个项目的开发工作。
  3. 促进技术创新:全栈开发者对技术的广泛了解和深入理解使他们更容易发现新的技术趋势和解决方案。他们能够将前端和后端的技术创新结合起来,创造出更加高效、用户友好的应用程序。此外,全栈开发者还能够在项目中引入新的技术栈或工具,推动团队的技术进步。
  4. 提升个人技能:全栈开发要求开发者掌握多种技术和工具,这促使他们不断学习、实践和探索。通过不断挑战自己,全栈开发者能够不断提升自己的技能水平,成为更加全面的技术人才。这种技能提升不仅有助于他们在当前项目中发挥更大的作用,也为他们未来的职业发展打下坚实的基础。
  5. 更好的用户体验:全栈开发者对前端和后端都有深入的了解,这使得他们能够更好地理解用户需求,并设计出更加符合用户期望的应用程序。他们能够从整体上考虑用户体验,确保前端界面的美观性和易用性与后端逻辑的高效性和稳定性相匹配。这种综合考虑的能力有助于提升应用程序的整体质量,增强用户满意度。
  6. 降低项目成本:在某些情况下,雇佣全栈开发者可以降低项目成本。虽然全栈开发者的薪资可能高于单一领域的开发者,但由于他们能够独立完成更多的工作,减少了团队规模,从而降低了总体的人力成本。此外,全栈开发者的灵活性也意味着在项目需求变化时,不需要额外招聘或培训新的开发者。

综上所述,全栈开发在提高项目效率、增强团队灵活性、促进技术创新、提升个人技能、改善用户体验以及降低项目成本等方面都具有显著的好处。然而,也需要注意的是,全栈开发并不是适用于所有情况的解决方案,它需要根据项目的具体需求和团队的实际情况来灵活选择。

16.24. 想了解一下你是如何学习这些信息的?

这些信息就是涉及到计算机网络知识,有有一些是课程上学习到的,然后有一些的话是看和B站以及一些相关的技术文档上看到的学习。

16.25. 假设你遇到了这样一个问题,你会如何去解决它呢?就是你的上级跟你去讲,你要去学习这方面的知识,你会怎么样。

如果学这方面的知识,我一般来说先通过通过AI通过AI对这个进行分析,然后查然后对他们一些反馈来进行一个进行一个官方文档的一些查看,或者进行一些相关的百度搜索。

16.26. 用maven进行多模块的依赖管理跟打包。他会分哪几个阶段?这个有了解吗?

clean->package->insatll

16.27. package是在什么位置?install的包是在什么位置?

Package的话它就在你java项目目录的package里面,它可以在缓存里面。install就相当于下到本地了。

16.28. 本地的默认仓库的话默认是在哪一个目录?

默认的C盘的一个.mvn,但是一般的话你刚开始学学这个刚开始配置的话,一那个安装包,下面会你自己生会自己新建一个REP的一个依赖的一个窗口,在那个文件里统一会在里面存着。

16.29. 父子传参可以用什么方式?

前端相关的没有了解那么深

16.30. 问我实习多久,什么时候可以入职,学校课程安排

16.31. 想了解一下这两个项目的话是它的来源是什么呢?

一个是工作室的项目,一个是个人的学习项目

16.32. 咱们之前是没有过实习的这个经验的吗?因为什么

16.33. 最开始介绍的实习要求以及转正相关的是可以考虑的吧?

可以接受

16.34. 你身边的后端的朋友的情况以及实习的薪资?

朋友基本在北上杭武 4-5k左右

16.35. 你觉得自己性格是什么样子的?

16.36. 你平时有自己的这个学习的方式方法和途径吗?

16.37. 怎么咱们是什么时候开始看机会的?

八月中旬开始准备投递秋招,六月份左右开始准备投暑假实习

16.38. 八月中旬机会到现在,咱们有遇到的吗?

有遇到因为一些原因拒了

16.39. 看到您学校是河南这边的,家是哪里的,为什么想要去杭州发展?

16.40. 项目的来源或者目的

实验室项目

16.41. 正常来说开始秋招了怎么还在投实习岗

都在准备

(秋招有oc,谁会浪费时间来面实习啊)

16.42. 看你之前参加过比赛,可以讲一下吗?简历的软著可以讲一下吗?

16.43. 你们这个工作室大概什么样的规模?

16.44. 有考核机制?是谁来负责考核?怎么个考核形式?

16.45. 你是作为后端负责人,你是负责相关的?

16.46. 我看你在这他写的抗压能力强,这个实际上是有什么经历吗?

(后面讲了第四季度可能比较忙业务量大,可能有加班的情况)

17. (22道)反问

17.1. 反问:咱们公司主要是做主要的一些业务是干什么的?现在团队负责哪块?

17.2. Java投递的go,后续如何安排

如果愿意转go可以来转go,也可以选择java,但我的部门目前没有java开发

17.3. 该部门是使用的什么技术呢,主要负责做什么的?

整个一个它的硬件一个生命周期的管理。包括期间apple包括一个仓库的管理,物流的管理等等相关的一些数据,还有一些库存安全库存的预警之类的,大概是这么一个东西。

17.4. 我想问一下,咱如果我入职的话,你觉得我会在你公司更多的会学到哪一些的东西?就更多的成长的方面在哪个方向大概。

17.5. 公司的后端的一个技术栈有哪些

17.6. 请问一共几轮面试呢?

17.7. 我想问一下,如果我入职本公司的话,你觉得我会从本公司获得最大的收获是哪方面的?

这块其实我们现在公司里面,其实实现的就是做的事情蛮多的。就是有你对我们自己有一个低代码的一个平台,低代码平台的一个团队。这个团队里面,他会因为我看你的项目上设计里面,其实是比较倾向于做一些技术的一些研究的对吧?就是很多逻辑里面,所以其实你可能对业务这块可能不太感觉比较喜欢玩技术。那玩技术这边我们有一些低代码平台的一个设计的,然后同时我们有一个小团队在做,也在做AIGC相关的一个内容。所以如果说你入职之后,这两方面我觉得你是能够得到一些实际的一个产品应用的。

17.8. 想问一下公司,因为我看搁网上看到咱公司是有一个低代码平台的话。然后咱公司除了低代码平台,还有别的一些技术,就是常用的一些后端相关的一些技术

低代码平台它主要管两种。我们现在有两层,一个是pass,pass的话就是帮我们去玩一些部署,就是整个部署底层都给你代理掉。类似于我不知道有没有用过阿里云的那个线服务,部署的时候有一个GPS,我不知道你们有没有听过。这是一层底层的一个pass。

然后低代码平台它是什么呢?它是说我们在做一些简单的业务处理的时候,我们是不需要写代码,我们可以做一些简单的服务编排,页面设计上也可以直接去搭一些页面出来。那本身它还开放了一个区别,就是其实它是可以拥抱整个java生态的。就是你在java里面你是可以任意使用你自己想要的一些技术站,这个是不限制你的。并且我们现在90%的写的一些业务逻辑,都是基于这个java原生生态的一些技术上去做的。当然在现在的团队里面,我们会有一些技术规范。就是说如果你想引用一下一个新的一个技术框架的时候,其实需要经过一些详细的评估的。

17.9. 面试官介绍公司的相关的业务

17.10. 面试官主动讲了公司的工作强度还是有点大的

然后我们这一个工作强度还是有点大的。

一般情况下我们能保证双休,周六周日双休。有一些一月份是比较忙的,比如说一月份比较忙,二月份有可能比较忙,然后是5 6月份比较忙,还有就是十一、12月份比较忙。这几个月的话,有可能我们会某一个月,你像5 6月份的话,六月份就是每天要到九点,周六周日要有一天上班的。

17.11. 主动介绍公司的一些福利方面以及薪资构成

17.12. 你我看你刚刚提到了公司后端是封装了一些一一些组件。那正常来说对于一个实习生的话,是不是因为组建的话肯定是封装的特别好的那种,是不是学不到太多的?

组建也不会封的那么全面,因为我们的业务是不是标准化的业务,我们做的是定制业务,我们标准化业务已经稳定了,做成了商城,商城就是自定义工具。我们这边的话是封装其实是分一些简单的这种基础组件。比如说年份,你输出一个年份,比如说某一个那个算法,你分一个某一个算法,就是类似这种的这个业务流程,业务过程还是需要你去做的那那那个那个也分不了,因为我们的定制化比较多。比如说今年中国银行来了,我要做一个,比如说打飞机,我们去做了。然后等到那个工行来的时候,他要做打飞。但他的打飞机跟这个打的完全是不一样的,所以说不能标准化,只能在基础的那个组件上去做封装。

17.13. 我我我想了解一下杭州现在那个租房价格应该。

是1000块钱左右。我们实际实习工资的话应该是4000,后端应该是4000。然后我们三餐都有的,基本上也除了房租也花不了什么钱。就杭州,杭州一天一千。你要住的便宜一点的话,1000块钱、800块钱都有,八九百都有的。稍微好一点,那你一个人住1500,要好的好一点,就是带厨房,带什么的,独立卫生间什么的这种。二十几平大就要1500左右。正常你一个人做要求不太高的话,1000块钱左右。

17.14. 作为我本人的话,如果入入职公司的话,你觉得在你这边看来我会有什么哪方面的一些收获

首先你现在的身份是一个大学生。们需要去解决的一个问题的,就是按照我们需要解决这个问题,就是后面怎么样去做。所以对于我们来说最核心的一个问题,就是如何把一个实习生培养成一个我们需要的一个优秀的一个职场人。是你的身份需要一个转变的这就是对于一个人来说,它是非常大的一个变化了。当然在这个过程中,你看对于大学生或者实习生来说,他肯定很多经验是不足的那我们也会有一些相关的一些培训辅导,然后一些实战的一些东西去帮助他成为我们这样的人。那你能收获到的那不仅仅只是说技术,还有职场的一些事情,做事的方式,协作方面东西,它是一个非常综合的东西。

17.15. 大概讲一下咱公司的一些技术站,可以吗?

我们的技术站是这样,它的技术线比较多,然后对技术栈也是比较多的那我们这些在我们其中一个,一个是电商平台,它里面其实就是一些简单的spring boot,然后是全家桶,就是jpa,然后像相关的mysql,redis,rock dubbo等等这些东西。像比如说像string cloud或者说dubbo,在这个项目里面是没有用到的,但在其他项目会有用到像这样的框架。

17.16. 还有一个问题就是后续的大概流程还有什么?

如果觉得我们觉得是候选人是比较合适的话,那后面还会有相关的一些电话面试或者是现场面试。因为你这边是在河南,对吧?对,那如果有的话,那到时候就是一个电话面试。

17.17. 了解一下咱公司的一些相关的业务。

我们公司的话主要是数据安全领域的,然后的话我们研发部的话主要是数据安全产品的一个研发。然后我们的数据安全产品主要分三个大的一个类型。第一个类型是基于流量镜像解析的一个数据风险发现的一个API风险产品。第二个是基于扫描主动扫描来发现风险的扫描产品。然后第三类的话就是平台型的产品。它主要是一些数据安全的一些运营之类的一些东西,还有一些数据地图相关的。

17.18. 可以问一下公司里面的一个实习的待遇吗?

17.19. 面试的轮次

17.20. 后面还有几轮面试?

如果评估合适的话,还会有一轮CTO的终面

17.21. 公司主要是做什么?相关技术栈主要是什么?

17.22. 想了解咱公司有转正吗?

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
林寻
下载 APP