目录
在使用 HashMap 的时候,用 String 做 key 有什么好处?
HashMap、LinkedHashMap、TreeMap的区别?
Stringbuffer 和 Stringbuilder 的区别是什么?
ArrayList和LinkedList的区别和优缺点,以及使用场景
说一说 Synchronized 和 Volatile 的区别是什么?
Spring 中 BeanFactory 和 ApplicationContext 有什么区别?
在Spring的特性,除利用AOP面向切面做日志编程,你还用过哪些特性
Springboot 中怎么区分 Jpa 和 Mybties 使用场景?
Spring 框架中的 Bean 是线程安全的么?如果线程不安全,那么如何处理?
你都用过SpringCloud的哪些组件,它们的原理是什么?
经典面试题:数据库单标1千万,未来1年还会增长多500万,性能比较慢,说下你的优化思路
如何理解rabbitMQ消息可靠性、重复消费、延迟队列、消息堆积
如何进行JVM调优?JVM参数有哪些?怎么查看一个JAVA进程的JVM参数?谈谈你了解的JVM参数。如果一个java程序每次运行一段时间后,就变得非常卡顿,你准备如何对他进行优化?
系统上的文件导入、导出如何设计的?(如何做百万级的导入、导出)
JAVA初级
请简述你对 MVC 模式的理解
Mvc全程model view controller模型视图控制器 将业务数据模型 视图页面分开来控制,而且才用mvc三层架构可以降低模块之间的耦合性,提高代码的复用性。缺点是简单系统太过于追求mvc模式的话,会增加系统业务
Sprint Bean的生命周期
Spring Bean的生命周期可以分为以下几步:
1.通过Spring框架的beanFactory工厂利用反射机制创建bean对象;
2.根据set方法或者有参构造方法给bean对象的属性进行依赖注入;
3.判断当前bean对象是否实现相关的aware接口,诸如beanNameAware、beanFactoryAware接口,如果有的话执行对应的方法;
4.执行bean对象的后置处理器postprocessbeforinitialztion
5.执行初始化方法initMethod
6.执行bean对象的后置处理器postprocessafterinitialztion
7.判断当前bean对象是否为单例,是则放到spring对象容器中,多例直接返回bean对象;
8.使用bean对象;
9.关闭容器,调用destroy方法销毁对象。
简要概括:
1.实例化 Instantiation
2.属性赋值 Populate
3.初始化 Initialization
4.销毁 Destruction
Spring 自动装配 bean 有哪些方式?
自动装配有三种方式:
byName
byType
constructor
byName
byName 通过匹配 bean 的 id是否跟 setter 对应,对应则自动装配。
byType
byType 通过匹配 bean 中所需要的依赖类型在容器上下文中自动寻找装配。
byName 和 byType区别
使用 byName 需要保证 bean 的 id 唯一,且这个 bean 需要自动注入的属性和set方法与 bean 的 id 要一致。
使用 byType 需要保证 bean 的 class 唯一,且这个 bean 需要自动注入的属性和类型要一致。
说一下类的加载过程?
jvm主要组成部分:类加载器,执行引擎,运行时数据区,本地库接口
Java源代码经javac编译为字节码文件,类加载器加载字节码文件到内存,放入到运行时数据区方法区。再由执行引擎将字节码转为系统指令,并通过本地库接口交给cpu调用。
总的来说有三部分:
一、加载
将类的class文件读入到内存,并为之创建class文件(这个过程是由类加载器完成的)
二、链接(链接又分为三部分)
1、验证
2、准备(为静态变量分配空间,并赋初始值)
3、解析
三、初始化
赋真实值
在使用 HashMap 的时候,用 String 做 key 有什么好处?
HashMap内部实现是通过key的hashcode来确定value的存储位置,因为字符串是不可变的,所以当创建字符串时,它的hashcode被缓存下来,不需要再次计算,所以相比于其他对象更快
HashMap、LinkedHashMap、TreeMap的区别?
1、HashMap是根据键的hashcode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,取得的数据完全是随机的
2、LinkedHashMap保存了记录的插入顺序,在使用Iterator进行遍历的时候,先得到的肯定是先插入的数据,可以在构造时带参数,按照应用次数来进行排序
3、TreeMap实现SortMap接口,能够把它保存的记录根据键排序。默认的是升序排序,也可以指定排序的比较器,进行遍历的时候得到的是排序过的记录。
this 与 super 之间有什么区别?
在Java中,this和super的区别主要是:所表示的实例不同、调用的构造不同、访问的成员不同以及使用方式不同。
1、所表示的实例不同
this代表本类的当前实例,即可以通过this访问本类中的成员(this可以单独使用)
super用于访问从父类继承的、可见的成员,所以super不能表示父类实例,不能单独使用
2、调用的构造不同
this用于调用本类内部的其它重载的构造方法
super用于调用父类的构造方法
3、访问的成员不同
通过this. 可以访问本类中以及父类中继承的、可见的成员(方法 和属性(字段))
通过super.可以访问从父类中继承的、可见的成员( 方法、字段(属性) )
4、使用方式不同
this关键字可以单独使用,比如直接输出this或当作返回值
this关键字在本类中可以省略
super关键字不可以单独使用,必须通过super(参数)或super.形式使用
从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
乐观锁和悲观锁的实现是怎么样的?
悲观锁一般都是通过加锁的方式来解决,而乐观锁的底层实现是CAS,也就是比较并替换,定义一个期望值,其他线程每次进行操作时,先和期望值进行比较,如果相同就修改原来的数据,如果不同,直接返回操作失败。
java中的乐观锁的实现最典型的就是原子类的操作
== 与 equals的区别
==:
如果==比较的是基本数据类型,那就是比较他们的值是否相等。
如果==比较是的引用数据类型,就是比较他们的地址是否相等。
equals():
比较两个对象是否相等。如果没有重写equals,作用和==类似。如果重写了equals,一般重写都是比较内容了
拿String来说:
String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。
Final 在 java 中有什么作用?
final关键字修饰类,表示被修饰的类不能被继承,参考String类。final关键字修饰方法,表示继承这个方法的类不能重写(override)被修饰方法,参考Object里面的wait方法。final修饰的变量,如果变量参数是八种原生数据类型,那么当前值不可以修改;如果是对象,则当前对象(对象的地址)不可修改,但是对象里面的变量不受影响,可以修改。
Stringbuffer 和 Stringbuilder 的区别是什么?
Stringbuffer线程安全,Stringbuilder线程不安全,Stringbuilder效率更快,因为它不需要加锁,不具备多线程安全
相对来说Stringbuffer就效率慢一些
ArrayList和LinkedList的区别和优缺点,以及使用场景
1、ArrayList是实现了基于动态数组的数据结构,LinkedList是基于链表结构。
2、对于随机访问的get和set方法,ArrayList要优于LinkedList,因为LinkedList要移动指针。
3、对于新增和删除操作add和remove,LinkedList比较占优势,因为ArrayList要移动数据。
优缺点:
1、对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是 统一的,分配一个内部Entry对象。
2、在ArrayList集合中添加或者删除一个元素时,当前的列表移动元素后面所有的元素都会被移动。而LinkedList集合中添加或者删除一个元素的开销是固定的。
3、LinkedList集合不支持 高效的随机随机访问(RandomAccess),因为可能产生二次项的行为。
4、ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
使用场景:
ArrayList使用在查询比较多,但是插入和删除比较少的情况,而LinkedList用在查询比较少而插入删除比较多的情况
说一说 Synchronized 和 Volatile 的区别是什么?
synchronized 可以作用于变量、方法、对象;volatile 只能作用于变量。
synchronized 可以保证线程间的有序性(个人猜测是无法保证线程内的有序性,即线程内的代码可能被 CPU 指令重排序)、原子性和可见性;volatile 只保证了可见性和有序性,禁止指令重排序,无法保证原子性。
synchronized 线程阻塞,volatile 线程不阻塞。
volatile 本质是告诉jvm当前变量在寄存器中的值是不安全的需要从内存中读取;sychronized 则是锁定当前变量,只有当前线程可以访问到,该变量其他线程被阻塞。
volatile 标记的变量不会被编译器优化;synchronized 标记的变量可以被编译器优化。
Java 中的 notify 和 notifyAll 有什么区别?
线程调用对象的wait方法那么线程会处在该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当线程调用对象notify,只会唤醒一个线程由等待池进入锁池中。当调用notifyAll方法,所有线程会有等待池进入锁池中等待竞争,这要看优先级了,竞争到对象锁的线程继续执行,直到执行完synchronized模块,才会释放掉该对象锁,被其他线程继续竞争
一个有@Transaction注解的方法中有锁,需要注意什么
在程序异常回滚后注意对锁的释放,以免死锁
Spring 是如何解决循环依赖?
三级缓存,简单来说,A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B,B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A,B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A放到一级缓存中。
并行和并发有什么区别?
并行:在同一时间段,多个请求访问不同资源,同时执行,互不影响,并行强调的是同一时间执行。
并发:在同一时间,多个请求同时访问同一个资源,并发强调是访问同一资源
Spring中 AOP 的实现原理是什么?
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
JAVA中级
Spring 静态代理的优缺点分别是什么?
优点是在不修改目标对象的前提下,可以通过代理对象对目标对象功能扩展缺点就是增加了代码维护的复杂度。
Spring中 AOP 的实现原理是什么?
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
Spring 中 BeanFactory 和 ApplicationContext 有什么区别?
BeanFactory属于Spring容器相关体系的根结点接口。 ApplicationContext接口继承了BeanFactory接口。
BeanFactory只有两个功能 1创建实例 2 获取实例。 并且懒加载实例。
ApplicationContext则增加国际化,AOP拦截器,消息发送响应机制,访问资源(url及文件)等。
在Spring的特性,除利用AOP面向切面做日志编程,你还用过哪些特性
IOC、AOP一起做自定义注解,自定义注解实力化
Spring Bean执行过程
Spring的特性,约束大于配置
如何解决循环依赖?
1、重构代码。通过修改代码结构来消除循环依赖关系,使类之间的依赖关系更加清晰和合理。
2、依赖注入框架。使用如Spring这样的依赖注入框架可以帮助自动处理依赖关系,避免循环依赖问题。
3、使用@Lazy注解。通过在构造方法的属性上使用@Lazy注解,利用其延时注入的特性来解决循环依赖。
4、字段注入或setter方法注入。将依赖关系转换为字段注入或setter方法注入,从而避免循环依赖。
5、模块化。将代码拆分成独立的模块,每个模块负责单一功能,以降低模块间的耦合度。
6、设计模式。利用设计模式,如观察者模式或中介者模式,帮助组织代码,避免循环依赖的产生。
7、编译器或工具辅助。使用某些编译器或工具检测循环依赖问题,并及时发现和解决问题。
在处理循环依赖时,应首先审查系统设计是否合理,因为很多时候循环依赖是由于系统设计不当造成的。如果是设计问题导致的循环依赖,首先应考虑进行代码重构,彻底消除循环依赖。
Springboot 中怎么区分 Jpa 和 Mybties 使用场景?
很简单,如果业务复杂多表关联查询多,就面向 sql 编程,如果业务简单只设计三张表以内就用 jpa
说一说 Spring 事务底层原理是什么 ?
Spring 事务处理模块是通过 AOP 功能来实现声明式事务处理的,具体操作(比如事务实行的配置和读取,事务对象的抽象),用 TransactionProxyFactoryBean 接口来使用 AOP 功能,生成 proxy 代理对象,通过 TransactionInterceptor 完成对代理方法的拦截,将事务处理的功能编织到拦截的方法中。读取 IOC 容器事务配置属性,转化为 Spring 事务处理需要的内部数据结构(TransactionAttributeSourceAdvisor),转化为 TransactionAttribute 表示的数据对象
Spring 框架中用到了哪些设计模式?请举例说明
无非是考察设计模式的应用,以下所有设计模式在源码中应用,请查收。
工厂方法模式:AbstractBeanFactory 。
抽象工厂模式:在 Spring 中,BeanFactory
单例模式:Spring中创建单例。
建造者模式:解析xml文件 | 构造者模式:Builder构造器,.builder方法
原型模式:在创建ioc容器后,通过getBean()获取bean对象时,往里追可以发现在核心方法处spring对bean的scope属性进行了判断,配置了prototype时。
适配器模式:spring AOP中的MethodBeforeAdviceAdapter类。
装饰模式:TransactionAwareCacheDecorator 类
代理模式:spring中代理有两种,Jdk代理方式和CGLIB。
外观模式:Tomcat 中,catalina.jar 中的 RequestFacade 和 ResponseFacade 。
桥接模式:JDBC
组合模式:CompositeCacheManager,Mybatis 在处理 xml 动态 sql 中用到了。
享元模式:String常量池, Integer 的静态内部类 IntegerCache。
策略模式:Cglib2AopProxy和JdkDynamicAopProxy分别代表两种策略的实现方式。
模板方法模式:JdbcTemplate实现了一系列常用的数据访问的算法骨架。
观察者模式: ApplicationListener, ContextLoaderListener等。
迭代器模式:集合。
责任链模式:handler,filter,Intercept。
命令模式:Tomcat 中命令模式在 Connector 和 Container 组件之间有体现。
备忘录模式:spring-webflow 中的stateManageableMessageContext.createMessageMemento()
状态模式:spring-statemachine spring状态机
访问者模式:Spring 中的 BeanDefinitionVisitor 类主要用于访问 BeanDefinition。
中介者模式:Java web 开发中 MVC 模式(Model-View-Controller)就用到了中介者模式,Controller 就是 Model 和 View 的中介
解释器模式:在 Spring 中,ExpressionParser 接口内部采用的是解释器模式。
如何解决瞬时大流量高并发?
将请求尽量拦截在系统上游(不要让锁冲突落到数据库上去)。传统秒杀系统之所以挂,请求都压倒了后端数据层,数据读写锁冲突严重,并发高响应慢,几乎所有请求都超时,流量虽大,下单成功的有效流量甚小。
创建线程有哪几种方式?(逢考必问)
1、继承Thread类
Java中的线程可以通过直接继承java.lang.Thread类来创建。你需要创建一个Thread类的子类并重写run()方法。这个方法中的代码将在线程启动后执行。
2、实现Runnable接口
另一种方式是实现java.lang.Runnable接口。创建一个实现了Runnable接口的类,并实现其run()方法。然后,使用Thread类的构造函数将Runnable对象传递给它
使用Runnable的好处是可以避免由于Java的单继承特性带来的限制,因为你可以同时实现多个接口
3、实现Callable接口
如果你希望线程执行后能够返回结果,可以使用java.util.concurrent.Callable接口。与Runnable类似,你需要实现call()方法,但是Callable方法可以返回一个结果,并且可以抛出异常
使用Callable时,你需要通过FutureTask包装器来创建线程,或者在ExecutorService中提交任务
每种方式都有其适用场景,选择哪种方式取决于你的具体需求。例如,如果你需要线程返回结果,那么Callable会是更好的选择;如果你的线程执行的任务比较简单,不涉及复杂的状态管理,使用Runnable接口会更加灵活。而直接继承Thread类则通常用于需要访问Thread类中其他方法或状态的场景
4、线程池创建
Java线程池类型有几种?(逢考必问)
newCachedThreadPool、newFixedThreadPool、newSingleThreadExecutor、newScheduleThreadPool。
1、newCachedThreadPool:创建一个可缓存的线程池,如果线程池长度超过处理所需,可灵活回收空闲线程,若线程数不够,则新建线程。
2、newFixedThreadPool:创建一个固定大小的线程池。可控制并发的线程数量,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。
3、newSingleThreadExecutor:创建一个单线程的线程池,即只创建唯一的工作者线程来执行任务,,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
4、newScheduleThreadPool:创建一个定时的线程池,支持定时及周期性任务执行。
线程池具体实现类以及重要参数?
Java中的线程池主要基于java.util.concurrent.ExecutorService接口和java.util.concurrent.AbstractExecutorService抽象类。但是,实际创建线程池时,我们通常使用java.util.concurrent.Executors工具类提供的工厂方法,它返回的是实现了ExecutorService接口的具体线程池实现类。
以下是Java中常见的几种线程池实现:
-
CachedThreadPool:可缓存的线程池
- 类型:
java.util.concurrent.ThreadPoolExecutor - 特点:可缓存的线程池,线程数量不定,线程空闲一段时间后会被回收。适用于执行大量短暂的异步任务。
- 类型:
-
FixedThreadPool:固定大小的线程池
- 类型:
java.util.concurrent.ThreadPoolExecutor - 特点:固定大小的线程池,线程数量固定,如果线程因异常结束,会被重新创建。适用于任务量大且任务执行时间较短的场景。
- 类型:
-
SingleThreadExecutor:单线程的线程池
- 类型:
java.util.concurrent.ThreadPoolExecutor - 特点:单线程的线程池,确保所有任务按照指定顺序执行。
- 类型:
-
ScheduledThreadPoolExecutor:定时的线程池
- 类型:
java.util.concurrent.ScheduledThreadPoolExecutor - 特点:定时线程池,可以安排任务在特定时间运行,或定期重复执行。它继承自
ThreadPoolExecutor。
- 类型:
-
WorkStealingPool:
- 类型:
java.util.concurrent.ForkJoinPool - 特点:使用工作窃取算法的线程池,特别适合于处理大量细粒度的计算任务,如并行流操作。
- 类型:
这些线程池都是基于ThreadPoolExecutor类构建的,ThreadPoolExecutor是AbstractExecutorService的子类,提供了更详细的线程池实现,允许用户自定义线程池的核心参数,如线程数量、队列类型、拒绝策略等。ThreadPoolExecutor的构造函数接受以下参数:
- 核心线程数(corePoolSize)
- 最大线程数(maximumPoolSize)
- 空闲线程存活时间(keepAliveTime)
- 时间单位(TimeUnit)
- 工作队列(workQueue)
- 线程工厂(threadFactory)
- 拒绝策略(handler)
通过这些参数,可以非常灵活地定制线程池的行为
自定义线程池如何设计,哪些重要的参数?(逢考必问)
自定义线程池通常涉及到java.util.concurrent.ThreadPoolExecutor类,它是ExecutorService接口的一个实现,提供了对线程池的高级控制。下面是如何设计一个自定义线程池的基本步骤,以及一些重要的参数说明:
步骤
-
确定线程池的参数:
- corePoolSize:核心线程数,即线程池中始终会维持的最小线程数。
- maximumPoolSize:最大线程数,线程池中允许的最大线程数。
- keepAliveTime:非核心线程的空闲存活时间,即当线程池中的线程数目大于核心线程数时,多余的线程在无任务可做时的存活时间。
- unit:keepAliveTime的时间单位,如TimeUnit.SECONDS。
- workQueue:用于存放待执行任务的阻塞队列,如
ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue等。 - threadFactory:创建新线程的工厂,可以自定义线程名称、优先级等。
- handler:拒绝策略,当线程池无法处理更多任务时的处理机制。
-
创建线程池:
使用ThreadPoolExecutor的构造函数,传入上述参数创建线程池。 -
执行任务:
使用execute(Runnable command)方法提交任务到线程池。 -
管理线程池:
- 调用
shutdown()方法停止接收新任务,等待已提交任务完成。 - 调用
shutdownNow()方法立即停止所有任务,并尝试取消正在执行的任务。
- 调用
示例代码
import java.util.concurrent.*;
public class CustomThreadPool {
public static void main(String[] args) {
// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // corePoolSize 核心线程数
10, // maximumPoolSize 最大线程数
60L, // keepAliveTime 非核心线程空闲存活时间
TimeUnit.SECONDS, // unit 时间单位
new LinkedBlockingQueue<>(100), // workQueue 阻塞队列
new NamedThreadFactory("MyPool"), // threadFactory 线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // handler 拒绝策略
);
// 提交任务
for (int i = 0; i < 15; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.println("Task ID: " + taskId + " is running by " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// 关闭线程池
executor.shutdown();
}
static class NamedThreadFactory implements ThreadFactory {
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
NamedThreadFactory(String namePrefix) {
this.namePrefix = namePrefix;
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());
return t;
}
}
}
在这个示例中,我们创建了一个具有5个核心线程和最多10个线程的线程池,使用LinkedBlockingQueue作为任务队列,并定义了一个简单的线程命名规则。当线程池无法接受更多任务时,采用CallerRunsPolicy策略,即调用者所在的线程会执行该任务。
Spring 框架中都用到了哪些设计模式?
简单工厂:根据一个工厂类传入的参数,动态决定应该创建哪一类
单例模式:保证一个类有一个实例,并提供一个访问他的全局访问点
动态代理:AOP为目标对象创建动态的一个代理对象
观察者模式:例如listener监听
策略模式Resource接口来访问底层资源
另外还有一个适配器模式
Git代码提交规范
| feat | 新功能 |
| fix | 修复Bug |
| docs | 文档修改 |
| perf | 性能优化 |
| revert | 版本回退,如执行git revert打印的message |
| ci | CICD集成相关 |
| test | 新增test用例或修改现有测试用例 |
| refactor | 代码重构,既没有新增功能,也没有修复bug, 比如提取某段代码为一个方法,重构某个功能等 |
| build | 构造工具的或者外部依赖的改动,比如maven/gradle |
| style | 不影响程序逻辑的代码修改,比如格式化,换行等 |
| chore | 不修改src或者test的其余修改, 例如构建过程或辅助工具的变动 |
Idea如何调整项目内存

修改-xmx

Spring常用的注解
组件扫描与 Bean 定义
@Component:通用的组件注解,用于标记一个类作为 Spring Bean。
@Repository:用于数据访问层(DAO)的组件注解。
@Service:用于业务逻辑层的组件注解。
@Controller:用于Web层的控制器组件注解。
@RestController:结合了@Controller和@ResponseBody,用于RESTful风格的Web控制器。
@Configuration:用于标记类可以当作 Bean 定义的来源,替
本文详述了Java从初级到高级的面试题,涵盖MVC模式、Spring Bean生命周期、自动装配、类加载过程、HashMap特性和区别、并发锁机制、设计模式、中间件(如RocketMQ与RabbitMQ的区别)、JVM调优和数据库事务等内容。通过这些知识点的深入探讨,旨在帮助求职者全面准备Java后端面试。
最低0.47元/天 解锁文章
1565

被折叠的 条评论
为什么被折叠?



