JavaEE 面试常见问题

这篇具有很好参考价值的文章主要介绍了JavaEE 面试常见问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、常见的 ORM 框架有哪些?

1.Mybatis

Mybatis 是一种典型的半自动的 ORM 框架,所谓的半自动,是因为还需要手动的写 SQL 语句,再由框架根据 SQL 及 传入数据来组装为要执行的 SQL 。其优点为:
1. 因为由程序员自己写 SQL ,相对来说学习门槛更低,更容易入门。
2. 更方便做 SQL 的性能优化及维护。
3. 对关系型数据库的模型要求不高,这样在做数据库模型调整时,影响不会太大。适合软件需求变更比较频繁的系统,因此国内系统大部分都是使用如 Mybatis 这样的半自动 ORM 框架。
其缺陷为:
不能跨数据库,因为写的 SQL 可能存在某数据库特有的语法或关键词

2.Hibernate

Hibernate 是一种典型的全自动 ORM 框架,所谓的全自动,是 SQL 语句都不用在编写,基于框架的 API,可以将对象自动的组装为要执行的 SQL 语句。其优点为:
1. 全自动 ORM 框架,自动的组装为 SQL 语句。
2. 可以跨数据库,框架提供了多套主流数据库的 SQL 生成规则。
其缺点为:
学习门槛更高,要学习框架 API SQL 之间的转换关系
对数据库模型依赖非常大,在软件需求变更频繁的系统中,会导致非常难以调整及维护。可能数据库中随便改一个表或字段的定义,Java 代码中要修改几十处。
很难定位问题,也很难进行性能优化:需要精通框架,对数据库模型设计也非常熟悉。

二、Bean容器/Ioc容器的理解

Spring 容器主要是对 IoC 设计模式的实现,主要是使用容器来统一管理 Bean 对象,及管理对象之间的依赖关系。
创建容器的 API 主要是 BeanFactory ApplicationContext 两种:
1. BeanFactory 是最底层的容器接口,只提供了最基础的容器功能: Bean 的实例化和依赖注入,并且使用懒加载的方式,这意味着 beans 只有在我们通过 getBean() 方法直接调用它们时才进行实例化。
2. ApplicationContext (应用上下文)是 BeanFactory 的子接口,与 BeanFactory 懒加载的方式不同,它是预加载,所以,每一个 bean 都在 ApplicationContext 启动之后实例化。
3. 除了基础功能,还添加了很多增强:
  • 整合了Bean的生命周期管理
  • i18n国际化功能(MessageSource
  • 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的 web
  • 事件发布响应机制(ApplicationEventPublisher
  • AOP

三、IoC/DI的理解

概念

IoC (Inversion of Control) 即控制反转,是面向对象编程中的一种设计原则。主要是通过第三方 IoC 容器,对Bean 对象进行统一管理,及组织对象之间的依赖关系。获得依赖对象的过程,由原本程序自己控制,变为了IoC 容器来主动注入,控制权发生了反转,所以叫做 IoC ,控制反转。
IoC 又叫做 DI :由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),相对 IoC 而言,依赖注入实际上给出了实现 IoC 的方法:注入。所谓依赖注入,就是由 IoC 容器在运行期间,动态地将某种依赖关系注入到对象之中。
依赖注入 (DI) 和控制反转 (IoC) 是从不同的角度的描述的同一件事情,就是指通过引入 IoC 容器,利用依赖关系注入的方式,实现对象之间的解耦。

实现方式

DI IoC 的实现方式之一。而 DI 的实现方式主要有两种:构造方法注入和属性 Setter 注入。

实现原理

主要依赖反射及 ASM 字节码框架实现(字节码框架操作字节码更为高效,功能更强大)。

四、Spring中的单例bean的线程安全问题

大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例 bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。
有两种常见的解决方案:
1. bean 对象中尽量避免定义可变的成员变量(不太现实)。
2. 在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

五、Spring中的bean的作用域有哪些?

1.singleton :唯一 bean 实例, Spring 中的 bean 默认都是单例的。
2.prototype :每次请求都会创建一个新的 bean 实例。
3.request :每一次 HTTP 请求都会产生一个新的 bean ,该 bean 仅在当前 HTTP request 内有效。
4.session :每一次 HTTP 请求都会产生一个新的 bean ,该 bean 仅在当前 HTTP session 内有效。
5.application :在一个应用的 Servlet 上下文生命周期中,产生一个新的 bean
6.websocket :在一个 WebSocket 生命周期中,产生一个新的 Bean

六、FactoryBean和BeanFactory

BeanFactory Spring 容器的顶级接口,所有 Bean 对象都是通过 BeanFactory 也就是 Bean 容器来进行管理
FactoryBean是实例化一个 Bean 对象的工厂类,实现了 FactoryBean<T> 接口的 Bean ,根据该 Bean 的 ID从 BeanFactory 中获取的实际上是 FactoryBean getObject() 方法返回的对象,而不是
FactoryBean 本身,如果要获取 FactoryBean 对象,请在 id 前面加一个 & 符号来获取。

七、Bean的生命周期

1. 实例化 Bean :通过反射调用构造方法实例化对象。
2. 依赖注入:装配 Bean 的属性
3. 实现了 Aware 接口的 Bean ,执行接口方法:如顺序执行 BeanNameAware BeanFactoryAware 、 ApplicationContextAware的接口方法。
4. Bean 对象初始化前,循环调用实现了 BeanPostProcessor 接口的预初始化方法 (postProcessBeforeInitialization
5. 执行 Bean 对象初始化方法
6. Bean 对象初始化后,循环调用实现了 BeanPostProcessor 接口的后初始化方法
postProcessAfterInitialization
7. 容器关闭时,执行 Bean 对象的销毁方法

八、Spring三级缓存的理解

这个问题或者换个问法: Spring 是如何解决循环依赖的?答案即是 Spring 的三级缓存

什么是循环依赖

简单说,就是 A 对象依赖 B 对象, B 对象又依赖 A 对象,类似的代码如下:
@Component
public class A{
@Autowired
private B b;
}
@Component
public class B{
@Autowired
private A a;
}
其他还有很多种方式,如 A 依赖 B B 依赖 C C 依赖 A ,或是 A 依赖 A 自己,只要产生了依赖关系的闭环, 即造成了循环依赖。
那么,循环依赖会引发什么问题呢?理解这个问题先得理解 Bean 的生命周期,以下先回顾下

Bean的生命周期回顾

1. 启动容器:加载 Bean
2. 实例化 Bean 对象
3. 依赖注入:装配 Bean 的属性
4. 初始化 Bean :执行 aware 接口方法、预初始化方法、初始化方法、后初始化方法
5. 关闭容器:销毁 Bean
在以上第四个步骤执行完毕,才算一个初始化完成的 Bean ,也即 Spring 容器中完整的 Bean 对象。
JavaEE 面试常见问题,框架,java-ee,面试,java,spring

循环依赖的问题

Spring 容器保存 Bean 的方式,是采取缓存的方式:使用 Map<String, Object> 的结构, key Bean
的名称, value Bean 对象。需要使用时直接从缓存获取。
假如 A B 互相依赖(循环依赖):
1. 容器中没有 A 对象,实例化 A 对象
2. 装配 A 中的 B 对象,发现 B 在容器中没有,需要先实例化 B
3. 实例化 B 对象
4. 装配 B 中的 A 对象,发现 A 在容器中没有,需要先实例化 A
5. 重复第一个步骤
这就套娃了 , 你猜是先 StackOverflow 还是 OutOfMemory
Spring 怕你不好猜,就先抛出了 BeanCurrentlyInCreationException
JavaEE 面试常见问题,框架,java-ee,面试,java,spring
[PS]
  • Bean会依赖某些注入的Bean来完成初始化工作
  • 由于Spring支持构造方法注入,属性/Setter注入的方式,所以不能简单的先把所有对象全部实例化,放到缓存中,再全部执行初始化。原因很简单,此时所有对象的引用都可以获取到,但属性都null,执行初始化甚至构造方法都可能出现空指针异常。
那么我们说 Spring 能解决循环依赖,也不是所有的情况都可以解决,只有以下情况才支持。

Spring支持的循环依赖

Spring 容器中注册循环依赖的 Bean ,必须是单例模式,且依赖注入的方式为属性注入。
原型模式及构造方法注入的方式,不支持循环依赖。以下为说明:
  • 原型模式(prototype)的Bean:原因很好理解,创建新的A时,发现要注入原型字段B,又创建新B发现要注入原型字段A... 还是典型的套娃行为...
  • 基于构造器的循环依赖,就更不用说了,官方文档都摊牌了,你想让构造器注入支持循环依赖,是不存在的,不如把代码改了。
那么默认单例的属性注入场景, Spring 是如何支持循环依赖的?

Spring解决循环依赖

Spring 是使用三级缓存的机制来解决循环依赖问题,以下为三级缓存的定义:
JavaEE 面试常见问题,框架,java-ee,面试,java,spring

 三级缓存的源码见 DefaultSingletonBeanRegistry

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>
(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new
HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new
ConcurrentHashMap<>(16);
}
以下是部分说明:
  • 三级缓存singletonFactories中保存的是ObjectFactory对象(Bean工厂),其中包含了 BeanNameBean对象,RootBeanDefinition,该工厂可以生成Bean对象。
  • 由于Bean可能被代理,此时注入到其他Bean属性中的也应该是代理Bean
单例模式的 A B 循环依赖执行流程如下:
JavaEE 面试常见问题,框架,java-ee,面试,java,spring

为什么要使用三级缓存

依照以上三级缓存的流程,其实使用二级缓存也能满足循环依赖的注入:
  • 普通的IoC容器使用一级缓存即可,但无法解决循环依赖问题。
  • 解决循环依赖问题:使用二级缓存即可。一级缓存保存完整Bean,二级缓存保存提前曝光的不完 整的Bean
  • 需要AOP代理Bean时,有两种实现思路:                                                                             (1)再加一级缓存                                                                                                                     (2)只使用二级缓存,其中二级缓存保存Bean的代理对象,代理对象中引用不完整的原始对象即可。
  • Spring使用三级缓存保存ObjectFactoryBean工厂,在代码的层次设计及扩展性上都会更好。 psObjectFactory内部可以根据 SmartInstantiationAwareBeanPostProcessor 这样的后置处 理器获取提前曝光的对象。

九、AOP的理解

AOP Aspect-Oriented Programming ):面向切面编程。对多个业务代码横切来实现统一的业务管理,而不用侵入业务代码本身。这样面向切面的编程思想就是AOP
使用场景:日志记录,事务管理,性能统计,安全控制,异常处理等
优点:代码解耦,统一业务功能对具体业务无侵入性,这样可扩展性更好,灵活性更高
SpringAOP 是采取动态代理的方式,具体是基于 JDK CGLIB 两种:
  • JDK动态代理:需要被代理类实现接口,使用 InvocationHandler Proxy 动态的生成代理类
  • CGLIB动态代理:需要被代理类能被继承,不能被final修饰。使用 MethodInterceptor 来对方法拦截。CGLIB底层是基于ASM字节码框架,在运行时动态生成代理类
SpringAOP 如何使用: @Aspect 定义切面,并注册到容器中,使用 @Pointcut 定义好切点方法后,可以对目标方法进行拦截:
  • 前置通知    使用@Before:通知方法会在目标方法调用之前执行。
  • 后置通知    使用@After:通知方法会在目标方法返回或者抛出异常后调用。
  • 返回之后通知    使用@AfterReturning:通知方法会在目标方法返回后调用。
  • 抛异常后通知    使用@AfterThrowing:通知方法会在目标方法抛出异常后调用。
  • 环绕通知    使用@Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。

十、Spring事务中的隔离级别有哪几种?

TransactionDefinition 接口中定义了五个表示隔离级别的常量:
  • ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ 隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。
  • ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
  • ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

十一、Spring事务中有哪几种事务传播行为?

TransactionDefinition 接口中定义了七个表示事务传播行为的常量。
支持当前事务的情况:
  • PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  • PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  • PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。
不支持当前事务的情况:
  • PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  • PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
其他情况:
  • PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED

 12.SpringMVC的流程

JavaEE 面试常见问题,框架,java-ee,面试,java,spring文章来源地址https://www.toymoban.com/news/detail-628329.html

SpringMVC 的请求响应步骤如下:
具体步骤:
  • 第一步:(发起)发起请求到前端控制器(DispatcherServlet)
  • 第二步:(查找)前端控制器请求HandlerMapping查找 Handler(可以根据xml配置、注解进行查找)
  • 第三步:(返回)处理器映射器HandlerMapping向前端控制器返回HandlerHandlerMapping 会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,多HandlerInterceptor拦截器对象),通过这种策略模式,很容易添加新的映射策略
  • 第四步:(调用)前端控制器调用处理器适配器去执行Handler
  • 第五步:(执行)处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
  • 第六步:(返回Handler执行完成给适配器返回ModelAndView
  • 第七步:(接收)处理器适配器向前端控制器返回ModelAndView ModelAndView
  • SpringMVC框架的一个底层对象,包括 Modelview
  • 第八步:(解析)前端控制器请求视图解析器去进行视图解析 (根据逻辑视图名解析成真正的视图 (jsp)),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
  • 第九步:(返回)视图解析器向前端控制器返回View
  • 第十步:(渲染)前端控制器进行视图渲染 (视图渲染将模型数据(ModelAndView对象中)填充request域)
  • 第十一步:(响应)前端控制器向用户响应结果
以下是对出现的一些组件的介绍:
(1) 前端控制器 DispatcherServlet (不需要程序员开发)。
作用:接收请求,响应结果,相当于转发器,中央处理器。有了 DispatcherServlet 减少了其它组件之间
的耦合度。
(2) 处理器映射器 HandlerMapping (不需要程序员开发)。
作用:根据请求的 url 查找 Handler
(3) 处理器适配器 HandlerAdapter (不需要程序员开发)。
作用:按照特定规则( HandlerAdapter 要求的规则)去执行 Handler
(4) 处理器 Handler (需要程序员开发)。
注意:编写 Handler 时按照 HandlerAdapter 的要求去做,这样适配器才可以去正确执行 Handler
(5) 视图解析器 ViewResolver (不需要程序员开发)。
作用:进行视图解析,根据逻辑视图名解析成真正的视图( view
(6) 视图 View (需要程序员开发 jsp )。
注意: View 是一个接口,实现类支持不同的 View 类型( jsp freemarker pdf…
ps: 不需要程序员开发的,需要程序员自己做一下配置即可。

十三、Mybatis中,#{}和${}的区别

  • #{变量名} 是预处理替换的方式,本质是 jdbc 中占位符的替换。如传入字符串,会替换为带单引号的值。可以安全性更好,
  • ${变量名} 是字符串的替换,只是对 sql 字符串进行拼接。如传入字符串,会直接替换为字符串的值,不加单引号。
# 的方式可以很大程度的防止 sql 注入,相对来说更安全。而 $ 的方式不能。

十四、Mybatis中如何一对一、一对多关联

十五、SpringBoot 自动配置原理

JavaEE 面试常见问题,框架,java-ee,面试,java,spring

到了这里,关于JavaEE 面试常见问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • Java进阶(ConcurrentHashMap)——面试时ConcurrentHashMap常见问题解读 & 结合源码分析 & 多线程CAS比较并交换 初识

    Java进阶(ConcurrentHashMap)——面试时ConcurrentHashMap常见问题解读 & 结合源码分析 & 多线程CAS比较并交换 初识

    List、Set、HashMap作为Java中常用的集合,需要深入认识其原理和特性。 本篇博客介绍常见的关于Java中线程安全的ConcurrentHashMap集合的面试问题,结合源码分析题目背后的知识点。 关于List的博客文章如下: Java进阶(List)——面试时List常见问题解读 结合源码分析 关于的Set的博

    2024年02月06日
    浏览(9)
  • 面试-Dubbo常见问题

    Dubbo 是一个RPC框架,包含注册中心,服务提供方,服务消费方,控制台,监控中心。 Dubbo 启动时会从注册中心拉取消费者需要的提供方信息,如果依赖的服务提供方不可用,Dubbo消费方会启动失败,并且不停的向注册中心请求提供方信息,抛出异常找不到对应的提供方。可以

    2024年02月08日
    浏览(10)
  • JVM基础,面试常见问题

    JVM基础,面试常见问题

    目录 一.运行时数据区域 1.线程独享 (1)栈 (2)程序计数器 2.线程共享 (1)方法区 (2)堆 二.内存如何分配 1.指针碰撞法 2.空闲列表法 3.TLAB 三.对象在内存中的组成 1.对象头 (1)markword (2)指向类型的指针 (3)如果是数组-》数组长度 2.实例数据 3.对齐填充 四.如何访

    2024年01月23日
    浏览(10)
  • 【数据结构面试常见问题】

    【数据结构面试常见问题】

    数据结构作为计算机的一门基础学科,它在面试中占有很大的比重,本科阶段,我们也学过数据结构与算法,内容比较多,也比较难,尤其是图的应用以及各类查找和排序算法,这些也都是核心内容。数据结构在实际的应用中也比较多,因此,整理一些常见的笔试、面试的数

    2024年03月22日
    浏览(5)
  • 项目经理岗面试常见问题

    一、注意事项   ·电面邀约确认(避免hr刷KPI): 请问贵司招聘的是什么岗位,是新建团队还是原有团队? 这边面试流程是怎样的,是 leader 直接面,还是?   ·面试前铺垫: 如果您对某部分感兴趣,请随时打断我。   ·面试中发挥: 尽量采用 STAR 原则回答,即 情境( Si

    2024年02月05日
    浏览(12)
  • 单片机面试常见问题

    1、中断的概念?简述中断的过程 (1)中断:指CPU在正常执行程序的过程中,由于内部/外部事件的触发或由程序的预先安排,引起CPU暂时中断当前正在运行的程序,转而执行为内部/外部事件或程序预先安排的事件的服务子程序,待中断服务子程序执行完毕后,CPU再返回到被

    2024年04月10日
    浏览(12)
  • docker常见面试问题详解

    docker常见面试问题详解

    在面试的时候,面试官常常会问一些问题: docker是什么,能做什么? docker和虚拟机的区别是什么呢? docker是用什么做隔离的? docke的网络类型?docker数据之间是如何通信的? docker的数据保存问题? 常用的docker命令? docker制作镜像相关? 下面,就让我来详细说明一些这些问

    2024年02月10日
    浏览(13)
  • 大数据常见面试问题汇总

    目录 第1章 核心技术 1.1 LinuxShell 1.1.1 Linux常用高级命令 1.1.2 Shell常用工具及写过的脚本 1.1.3 Shell中单引号和双引号区别 1.2 Hadoop 1.2.1 Hadoop常用端口号 1.2.2 HDFS读流程和写流程 1.2.3 HDFS小文件处理 1.2.4 HDFS的NameNode内存 1.2.5 Shuffle及优化 1.2.6 Yarn工作机制 1.2.7 Yarn调度器 1.2.8 HDFS块大

    2024年02月14日
    浏览(11)
  • List常见面试问题

    List常见面试问题

    Java中的List是一种存放有序的、可以重复的数据的集合,它允许重复元素的存在。List中的元素都有对应的一个序列号(索引)记录着元素的位置,因此可以通过这个序列号来访问元素。 ‍ Java中的List有三种实现方式:ArrayList、LinkedList和Vector。其中,ArrayList是基于数组实现的,

    2024年02月09日
    浏览(6)
  • kubernetes常见面试问题详解

    kubernetes常见面试问题详解

    在面试的时候,面试官常常会问一些问题: k8s是什么?有什么用? k8s由哪些组件组成? pod的启动流程? k8s里有哪些控制器? k8s的调度器里有哪些调度算法? pod和pod之间的通信过程? 外面用户访问pod数据流程? 你常用哪些命令? 容器的类型? 3种探针? pod的升级? HPA、V

    2024年02月10日
    浏览(9)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包