Java面试题超详细整理《Spring篇,Java开发了解这些自然无惧面试


解析类-》加载对象-》依赖注入-》回调Aware方法-》后置处理器处理(初始化及初始化前后)-》使用-》销毁

  • Bean 容器解析类得到配置文件中 Spring Bean 的定义(BeanDefinition)。(解析)

  • Bean 容器利用 Java Reflection API 创建一个Bean的实例。(加载对象)

  • 如果涉及到一些属性值(加了@Autowride注解的属性)利用 set()方法给对象设置属性。(依赖注入)

  • 回调Aware方法:如果实现了其他 *.Aware接口,就调用相应的方法。(回调Aware方法)

    ①如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean的名字。

    ②如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。

  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor对象,执行postProcessBeforeInitialization() 方法。(后置处理器初始化前方法)

  • 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。(初始化方法)

  • 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。

  • 如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法。(后置处理器初始化后方法,会进行AOP)

  • 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。

  • 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

图示:

在这里插入图片描述

后置处理器BeanPostProcessor :在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。后置处理器分为 Bean Factory后置处理器(视线了Spring的扫描)和Bean后置处理器(实现了@ Autowired注解的属性自动赋值、AOP)

bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解


[](

)Spring 中的 bean 的作用域有哪些?


  • singleton(单例模式,默认) : 每个容器中只有一个bean的实例,单例的模式由 Beanfactory自身来维护。该对象的生命周期是与 Spring IOC容器一致的(但在第一次被注入时才会创建)。

  • prototype (原型模式): 每次请求都会创建一个新的 bean 实例。在每次注入时都会创建个新的对象

  • request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。

  • session:每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。

  • application:bean被定义为在 Servletcontext的生命周期中复用一个单例对象(可以实现跨容器)

  • global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。


[](

)Spring 中的单例 bean 线程安全吗?


存在安全问题的。Spring中的bean默认是单例模式的,框架并没有对bean进行多线程的封装处理,当多个线程操作同一个对象的时候,对这个对象的成员变量的写操作会存在线程安全问题。

但是大多数bean都是无状态的(不具有数据存储功能),比如说controller、 service和dao层,我们一般只是调用里面的方法,多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。但是dao层会操作数据库 Connection, Connection是带有状态的,比如说数据库事务, Spring的事务管理器,需要我们进行处理。

因此,不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,可以参考一下方案:

  • 使用 Threadloca把变量变为线程私有的,比如在dao层,可以使用Threadlocal为不同线程维护了一套独立的 connection副本,保证线程之间不会互相影响。

  • 改变 Bean 的作用域为 “prototype”:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。

  • 如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用 synchronized、OCK、CAS等这些实现线程同步的方法了。


[](

)Spring 框架中用到了哪些设计模式?


  • 工厂设计模式: 由一个工厂类根据传入的参数,动态决定创建那个产品类。Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建bean 对象。

  • 单例设计模式 : 保证一个类仅有一个实例,并提供一个访问它的全局访问点。Spring 中的 Bean 默认都是单例的。

  • 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式(HandlerAdapter)适配Controller,对应的每一种Controller都有一种对应的适配器实现类。

  • 代理设计模式 : Spring AOP 功能的实现。AOP把切面应用到对象并创建新的代理对象。

  • 观察者模式:Spring的事件驱动模型使用的是观察着模式,Spring中Observer模式常用的地方是Listener的实现

  • 策略模式:Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource的接口来访问底层资源。

  • 装饰器模式:动态地给一个对象添加额外的职责。Spring中类名包括Wrapper或Decorator使用了装饰器模式。

  • 模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。

  • 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。


[](

)Spring事务的实现方式


Spring 管理事务的方式有几种?

  • 编程式事务,在代码中硬编码。(不推荐使用)

  • 声明式事务,在配置文件中配置(推荐使用)

声明式事务又分为:

  • 基于XML的声明式事务

  • 基于注解的声明式事务

说一下 Spring的事务机制

  • spring事务底层是基于数据库事务和AOP机制的(事务这个概念是数据库层面的, Spring只是基于数据库中的事务进行了扩展)

  • 首先对于使用了@Transactional注解的bean,Spring会创建一个代理对象作为Bean

  • 当调用代理对象的方法时,会先判断该方法上是否加了@ Transactional注解

  • 如果加了,那么则利用事务管理器创建一个数据库连接,并把事务的自动提交设置为 false,然后再去执行原本的业务逻辑方法(sql)。

  • 如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务进行提交

  • 如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚

  • 针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的 rollbackfor属性进行配置,默认情况下会对 Runtimeexception和Error进行回滚。

  • Spring事务的隔离级别对应的就是数据库的隔离级别

  • Spring事务的传播机制是 Spring事务自己实现的,也是 Spring事务中最复杂的

  • Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开个事务,那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql


[](

)@Transactional注解了解吗?


Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。

当@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。

@Transactional(rollbackFor = Exception.class):

在@Transactional注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。


[](

)spring事务什么时候会失效?


spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不起作用了。常见情况有如下几种:@Transactional标识的方法只有被代理对象调用时,注解才会生效

  • 发生自调用,类里面使用this调用本类的方法,此时这个this对象不是代理类,而是Userservice对象本身(解决方法很简单,让那个this变成 Euserservice的代理类即可)

  • 方法不是public的,Transactional只能用于public的方法上,否则事务不会失效,如果要用在非public方法上,可以开启( Aspectj代理模式)。

  • 异常被吃掉,事务不会回滚或者抛出的异常没有被定义,默认为 RuntimeException。


[](

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


spring事务隔离级别就是数据库的隔离级别:外加一个默认级别

  • isolation_default(默认级别):使用后端数据库默认的隔离级别

  • read_uncommitted(读未提交读):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读

  • read_committed(读以提交、不可重复读):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

  • repeatable_read(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

  • serializable(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

数据库的配置隔离级别是 Read Commited,而 Spring配置的隔离级别是 Repeatable Read,请问这时隔离级别是以哪个为准?

以 Spring配置的为准,如果 spring设置的隔离级别数据库不支持,效果取决于数据库


[](

)Spring 事务中哪几种事务传播行为?


多个事务方法相互调用时事务如何在这些方法间传播:

方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。

  • REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务

  • SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行

  • MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则拋出异常

  • REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务

  • NOT_SUPPORTED:以非事务方式执行如果当前存在事务,则挂起当前事务

  • NEVER:不使用事务,如果当前事务存在,则抛出异常

  • NESTED:如果当前事务存在,则在嵌套事务中执行,否则 REQUIRED的操作一样(开启一个事务)

NESTED和 REQUIRES_NEW的区别:

REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关,而 NESTED则是当前存在事务时(我们把当前事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。在 NESTED情况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW情况下,原有事务回滚,不会影响新开启的事务

NESTED和 REQUIRED的区别:

REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一事务,那么被调用方出现异常时,由于共用一个事务,所以无论调用方是否 catch其异常,事务都会回滚而在 NESTED情况下,被调用方发生异常时,调用方可以 catch其异常,这样只有子事务回滚,父事务不受影响。


[](

)什么是bean的自动装配?自动装配有哪些方式?


在Spring框架中,在配置文件中设定了bean的依赖关系,Spring 容器能够自动装配相互合作的bean。这意味着容器不需要配置,能通过Bean工厂自动处理bean之间的协作,Spring可以通过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上,也可以设定在特定的bean上。

使用@Autowired注解自动装配的过程:

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找;
  • 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用Autowire来配置自动装载模式。在Spring框架xml配置中共有5种自动装配:

  • no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。

  • byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。

  • byType:通过参数的数据类型进行自动装配。

  • constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。

  • autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。


<!--byName-->

<bean id="cutomer" class="com.XXX.XXX.Cutomer" autowire="byName"/>

<bean id="person" class="com.XXX.XXX.Person"/>



<!--byName-->

<bean id="cutomer" class="com.XXX.XXX.Cutomer" autowire="byType"/>

<bean id="person" class="com.XXX.XXX.Person"/>



<!--construtor-->

<bean id="cutomer" class="com.XXX.XXX.Cutomer" autowire="construtor"/>

<bean id="person" class="com.XXX.XXX.Person"/> 


[](

)自动装配有哪些局限性?


  • 重写:你仍需用 和 配置来定义依赖,意味着总要重写自动装配。

  • 基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。

  • 模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。


[](

)Spring MVC的工作流程了解吗?


MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。Spring MVC 可以帮助我们进行更简洁的Web层的开发,并且它天生与 Spring 框架集成。Spring MVC 下我们一般把后端项目分为 Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层,返回数据给前台页面)。

SpringMVC工作流程:

  • 用户发送请求至前端控制器 Dispatcherservlet(用来处理HTTP请求与响应)

  • Dispatcherservlet 收到请求调用 Handler Mapping处理器映射器。

  • 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器及处理器拦截器(如果有则生成)并返回给 Dispatcherservlet。

  • Dispatcherservlet调用 HandlerAdapter处理器适配器

  • HandleraAapter经过适配调用具体的处理器(Controller,也叫后端控制器)

  • Controller执行完成返回 ModelAndView。

  • HandlerAdapter将 controller执行结果 ModelAndView返回给 Dispatcherservlet。

  • Dispatcherservlet将 Modelandview传给 ViewReslover视图解析器。

  • Viewreslover解析后返回具体View

  • Dispatcherservlet根据view进行渲染视图(即将模型数据填充至视图中)。

  • Dispatcherservle响应用户(浏览器)。

最后

我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

已经将知识体系整理好(源码,笔记,PPT,学习视频)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

vlet。**

  • Dispatcherservlet将 Modelandview传给 ViewReslover视图解析器。

  • Viewreslover解析后返回具体View

  • Dispatcherservlet根据view进行渲染视图(即将模型数据填充至视图中)。

  • Dispatcherservle响应用户(浏览器)。

最后

我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习

**[CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】](

)**

已经将知识体系整理好(源码,笔记,PPT,学习视频)

[外链图片转存中…(img-T2MwQf2P-1631173099826)]

[外链图片转存中…(img-LuM0KB3A-1631173099827)]

[外链图片转存中…(img-BFPVNjKG-1631173099828)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值