面试 Java 框架八股文十问十答第七期
相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!
⭐点赞⭐收藏⭐不迷路!⭐
1)Spring 一共有几种注入方式?
Spring 一共有三种注入方式:构造器注入、Setter 方法注入和字段注入(通过 @Autowired 注解实现)。
2)说下 AOP?
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它通过在程序运行时动态地将代码切入到类的方法或对象的特定位置来增强功能或修改行为。AOP 主要用于解决程序中的横切关注点(cross-cutting concerns),如日志记录、事务管理、安全性等,使得这些关注点的代码可以被模块化、重用和集中管理,提高了程序的可维护性和灵活性。
3)Spring AOP默认用的是什么动态代理,两者的区别?
Spring AOP 默认使用的是 JDK 动态代理。JDK 动态代理是基于接口的代理,它利用 Java 反射机制在运行时创建一个实现了目标接口的代理类,并将方法的调用委托给该代理类。与之相对的是 CGLIB(Code Generation Library)动态代理,它是基于继承的代理,通过动态生成目标类的子类来实现代理。两者的主要区别在于:
- JDK 动态代理要求目标类必须实现接口,而 CGLIB 动态代理则可以代理任何类,包括没有实现接口的类。
- JDK 动态代理是通过 Java 反射机制来实现的,效率相对较低,而 CGLIB 动态代理是通过字节码生成技术实现的,性能更高,但在生成代理类时会消耗更多的内存和时间。
- 由于 JDK 动态代理要求目标类实现接口,因此对于没有实现接口的类无法使用 JDK 动态代理,而只能使用 CGLIB 动态代理。
在 Spring AOP 中,默认情况下如果目标类实现了接口,则使用 JDK 动态代理,否则使用 CGLIB 动态代理。可以通过配置来强制使用某种代理方式,或者禁用代理。
4)能说说拦截链的实现吗?
拦截链是指在 AOP 中,对于一个被增强(Advice)的目标方法,在其执行过程中,可能存在多个通知(Advice)需要在不同的切点(Join Point)进行拦截。这些通知按照一定的顺序组成一个拦截链,当目标方法被调用时,拦截链中的通知将按照其定义的顺序依次执行,以实现对目标方法的增强或修改。
在 Spring AOP 中,拦截链的实现通常是通过代理对象来实现的。当客户端调用目标对象的方法时,实际上是调用了代理对象的方法,代理对象内部维护了一个拦截链,根据切点配置和通知的顺序,依次执行各个通知,最终再调用目标方法。
5)Spring AOP 和 AspectJ 有什么区别?
Spring AOP 是 Spring 框架提供的 AOP 实现,它基于代理机制实现 AOP,主要针对 Spring 容器中的 Bean 进行增强。而 AspectJ 是一个独立的 AOP 框架,它提供了比 Spring AOP 更加强大和灵活的功能,支持在编译时、类加载时或运行时织入切面,可以对任何 Java 类进行增强,不限于 Spring 容器管理的 Bean。因此,Spring AOP 更适合在 Spring 应用中使用,而 AspectJ 则更适合在独立的 Java 项目中使用或者与 Spring AOP 结合使用。
6)什么是循环依赖(常问)?
循环依赖指的是在对象之间形成了循环的依赖关系,导致无法完成对象的初始化。例如,类 A 依赖类 B,而类 B 又依赖类 A,这样就形成了循环依赖。在 Spring 容器中,循环依赖通常指的是单例 Bean 之间的循环依赖,因为 Spring 默认情况下会尽可能地创建单例 Bean,并且在创建 Bean 的过程中解决循环依赖是比较复杂的。Spring 通过提前暴露尚未完全初始化的 Bean 实例来解决循环依赖问题,但是如果循环依赖链过长或者存在复杂的构造函数依赖关系,可能会导致循环依赖无法解决而抛出异常。
7)Spring 如何解决循环依赖?
Spring 解决循环依赖的主要方式是通过三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)来控制 Bean 的实例化过程。当 Spring 容器创建一个单例 Bean 时,会先将该 Bean 的 ObjectFactory 存放到 singletonFactories 中,以便在需要时能够提前暴露一个未完全初始化的 Bean 实例。接着,容器会将该 Bean 的早期引用(early reference)存放到 earlySingletonObjects 中,这样在后续创建循环依赖的 Bean 时,能够提前暴露一个早期引用,避免直接调用尚未完成初始化的 Bean 导致循环依赖问题。
8)为什么循环依赖需要三级缓存,二级不够吗?
循环依赖需要三级缓存的原因是因为在解决循环依赖时,涉及到对 Bean 的创建、初始化和缓存的多个阶段,而二级缓存(一级缓存是 singletonObjects,二级缓存是 earlySingletonObjects)只能解决部分场景下的循环依赖。在某些情况下,如果只使用二级缓存,可能会导致在后续创建 Bean 的过程中,无法获取到早期引用,从而无法正确解决循环依赖。
9)说下 Spring Bean 的生命周期?
Spring Bean 的生命周期包括以下阶段:
- 实例化(Instantiation):容器根据 Bean 的定义创建 Bean 的实例。
- 属性设置(Populate Properties):容器将配置文件或注解中指定的属性值或引用注入到 Bean 实例中。
- 初始化(Initialization):如果 Bean 实现了 InitializingBean 接口,容器将调用其 afterPropertiesSet() 方法进行初始化;如果配置了 init-method 方法,则调用指定的初始化方法。
- 使用(In Use):此时 Bean 已经可以被应用程序使用。
- 销毁(Destruction):如果 Bean 实现了 DisposableBean 接口,容器在销毁 Bean 时会调用其 destroy() 方法;如果配置了 destroy-method 方法,则调用指定的销毁方法。
10)说下对 Spring MVC 的理解?
Spring MVC 是 Spring 框架提供的一种基于 MVC(Model-View-Controller)设计模式的 Web 框架,用于开发 Web 应用程序。它主要包括以下几个核心组件:
- DispatcherServlet:前端控制器,负责接收所有请求并将其分发给相应的处理器(Controller)进行处理。
- HandlerMapping:负责将请求映射到对应的处理器。
- Controller:处理请求并返回相应的模型数据和视图。
- ModelAndView:模型和视图的持有者,包含处理器处理请求后返回的数据和视图信息。
- ViewResolver:根据视图名称解析出视图对象。
- View:负责渲染模型数据,生成最终的响应结果。
开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system
前后端总计已经 1300+ Star,2W+ 访问!
⭐点赞⭐收藏⭐不迷路!⭐