标题 | 地址 |
---|---|
Java虚拟机面试题总结(2022版) | https://blog.csdn.net/qq_37924396/article/details/125881033 |
Java集合面试题总结(2022版) | https://blog.csdn.net/qq_37924396/article/details/126058839 |
Mysql数据库面试题总结(2022版) | https://blog.csdn.net/qq_37924396/article/details/125901358 |
Spring面试题总结(2022版) | https://blog.csdn.net/qq_37924396/article/details/126354473 |
Redis面试题总结(2022版) | https://blog.csdn.net/qq_37924396/article/details/126111149 |
Java并发面试题总结(2022版) | https://blog.csdn.net/qq_37924396/article/details/125984564 |
分布式面试题总结(2022版) | https://blog.csdn.net/qq_37924396/article/details/126256455 |
1.常见问题
1.Spring是什么
Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。主要包括以下七个模块:
Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
Spring Core:核心类库,所有功能都依赖于该类库,提供IOC和DI服务;
Spring AOP:AOP服务;
Spring Web:提供了基本的面向Web的综合特性,提供对常见框架如Struts2的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器;
Spring MVC:提供面向Web应用的Model-View-Controller,即MVC实现。
Spring DAO:对JDBC的抽象封装,简化了数据访问异常的处理,并能统一管理JDBC事务;
Spring ORM:对现有的ORM框架的支持;
2.Spring 的优点
(1)spring属于低侵入式设计,代码的污染极低;
(2)spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;
(3)Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。
(4)spring对于主流的应用框架提供了集成支持。
3.Spring框架中都用到了哪些设计模式?
Spring设计模式的详细使用案例可以阅读这篇文章:https://blog.csdn.net/a745233700/article/details/112598471
(1)工厂模式:Spring使用工厂模式,通过BeanFactory和ApplicationContext来创建对象
(2)单例模式:Bean默认为单例模式
(3)策略模式:例如Resource的实现类,针对不同的资源文件,实现了不同方式的资源获取策略
(4)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
(5)模板方法:可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中,用来解决代码重复的问题。比如RestTemplate, JmsTemplate, JpaTemplate
(6)适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式,Spring MVC中也是用到了适配器模式适配Controller
(7)观察者模式:Spring事件驱动模型就是观察者模式的一个经典应用。
(8)桥接模式:可以根据客户的需求能够动态切换不同的数据源。比如我们的项目需要连接多个数据库,客户在每次访问中根据需要会去访问不同的数据库
ref:Spring中所使用的设计模式
4.BeanFactory和FactoryBean 的区别
BeanFactory是IOC最基本的容器,负责生产和管理bean;
FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&;
2.IOC
1.什么是 IOC?
(1)IOC就是控制反转,指创建对象的控制权转移给Spring框架进行管理,并由Spring根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部依赖。
(2)最直观的表达就是,以前创建对象的主动权和时机都是由自己把控的,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。
(3)Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
2.Spring 有哪些容器类?
1.BeanFactory:这是一个最简单的容器,它主要的功能是为依赖注入(DI)提供支持。
2.ApplicationContext:Application Context 是 Spring 中的高级容器。和 BeanFactory 类似,它可以加载和管理配置文件中定义的 Bean。 另外,它还增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。
一些常被使用的 ApplicationContext 实现类:
3.FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 Bean, 需要提供 XML 文件的完整路径。
4.ClassPathXmlApplicationContext:同样从 XML 文件中加载已被定义的 Bean,但无需提供完整路径,因为它会从 CLASSPATH 中搜索配置文件。
5.WebXmlApplicationContext:该容器会在一个 Web 应用程序的范围内加载在 XML 文件中已被定义的 Bean。
3.IOC的单例和多例
Spring框架的Bean默认为单例模式, 但是可以根据需要开启Bean的多例模式,具体的是 scope=“prototype” 指定bean工厂生成多实例对象。
scope:用来控制spring容器产生对象的方式,可以为单例也可以为多例
常用的值有:singleton(单例)、prototype(多例),默认值为单例
不常用的有:request、session
ref:Spring IOC-单例和多例
3.AOP
1.什么是SpringAop?
一般称为面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。
2.AOP的相关概念
(1)切面(Aspect): 在Spring Aop指定就是“切面类” ,切面类会管理着切点、通知。
(2)连接点(Join point): 连接点是在应用执行过程中能够插入切面(Aspect)的一个点。这些点可以是调用方法时,抛出异常时。它是一个虚拟的概念,例如坐地铁的时候,每一个站都可以下车,那么这每一个站都是一个接入点。假如一个对象中有多个方法,那么这个每一个方法就是一个连接点。
(3)通知(Advice): 就是需要增加到业务方法中的公共代码, 通知有很多种类型分别可以在需要增加的业务方法不同位置进行执行(前置通知、后置通知、异常通知、返回通知、环绕通知)
(4)切点(Pointcut): 核心方法, 结合切点表达式进行实现
(5)目标对象(Target Object): 指定是增强的对象
(6)织入(Weaving) : spring aop用的织入方式:动态代理。 就是为目标对象创建动态代理的过程就叫织入。
核心原理:观察所调用的方法是否符合切入点表达式,如果符合,则使用代理执行增强方法
3.AOP底层原理
AOP底层使用动态代理,有两种情况动态代理
第一种
有接口情况,使用 JDK 动态代理,创建接口实现类代理对象,增强类的方法
第二种
没有接口情况,使用 CGLIB 动态代理,创建子类的代理对象,增强类的方法
ref:AOP-底层原理
4.JDK动态代理和CGLIB动态代理的区别
JDK动态代理只提供接口的代理,不支持类的代理
该代理类是实现了目标类接口, 并且代理类会实现接口所有的方法增强代码。
调用时 通过代理类先去调用处理类进行增强,再通过反射的方式进行调用目标方法。从而实现AOP
如果代理类没有实现 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
CGLIB在运行时动态的生成目标类的一个子类。并且会重写父类所有的方法增强代码,调用时先通过代理类进行增强,再直接调用父类对应的方法进行调用目标方法。从而实现AOP。
4.Bean
1.Spring Bean 的生命周期?
Bean 在 Spring 容器中从创建到销毁经历了若干阶段,每一阶段都可以进行个性化定制。
1)Spring 对 Bean 进行实例化;
2)Spring 将配置和 Bean 的引用注入到对应的属性中;
3)如果 Bean 实现了 BeanNameAware 接口,Spring 将 Bean 的 ID 传递给 setBeanName() 方法;
4)如果 Bean 实现了 BeanFactoryAware 接口,Spring 将调用 setBeanFactory() 方法将 BeanFactory 容器实例传入;
5)如果 Bean 实现了 ApplicationContextAware 接口,Spring 将调用 setApplicationContext() 方法将 Bean 所在的应用上下文的引用传入进来;
6)如果 Bean 实现了 BeanPostProcessor 接口,Spring 将调用它们的 postProcessBeforeInitialization() 方法;
7)如果 Bean 实现了 InitializingBean 接口,Spring 将调用它们的 afterPropertiesSet() 方法。类似地,如果 Bean 使用 initmethod 声明了初始化方法,该方法也会被调用;
8)如果 Bean 实现了 BeanPostProcessor 接口,Spring 将调用它们的postProcessAfterInitialization()方法;
9)此时,Bean 已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
10)如果 Bean 实现了 DisposableBean 接口,Spring 将调用它的 destroy() 接口方法。同样,如果使用 destroymethod 声明了销毁方法,该方法也会被调用。
2.Spring中的单例Bean是线程安全的吗?
答:不是
Spring中的Bean默认是单例模式的,框架并没有对bean进行多线程的封装处理。
注:单例bean是指IOC容器中就只有这么一个bean,是全局共享的,有多少个线程来访问用的都是这个bean。
如果Bean是有状态的,那就需要开发人员自己来进行线程安全的保证,最简单的办法就是改变bean的作
用域 把 "singleton"改为’‘protopyte’ 这样每次请求Bean就相当于是 new Bean() 这样就可以保证线程的
安全了。
有状态就是有数据存储功能。比如:一个Service里有个count的变量计数。
无状态就是不会保存数据
controller、service和dao层本身并不是线程安全的,只是如果只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。
Dao会操作数据库Connection,Connection是带有状态的,比如说数据库事务,Spring的事务管理器
使用Threadlocal为不同线程维护了一套独立的connection副本,保证线程之间不会互相影响(Spring
是如何保证事务获取同一个Connection的)
不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,那么就使用ThreadLocal把变量变
为线程私有的,如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用synchronized、lock、CAS等这些实现线程同步的方法了。
3.Bean的作用域
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.global-session:全局session作用域,仅仅在基于Portlet的Web应用中才有意义,Spring5中已经没有了。Portlet是能够生成语义代码(例如HTML)片段的小型Java Web插件。它们基于Portlet容器,可以像Servlet一样处理HTTP请求。但是与Servlet不同,每个Portlet都有不同的会话。
4.将一个类声明为Spring的bean的注解有哪些?
5.事务
1.Spring事务的开启方式
-
编程式事务
编程式事务每次实现都要单独实现,但业务量大功能复杂时,使用编程式事务无疑是痛苦的 -
声明式事务
声明式事务属于无侵入式,不会影响业务逻辑的实现
声明式事务实现方式主要有2种,
1.使用Spring的tx:advice定义事务通知与AOP相关配置实现,
2.通过@Transactional实现事务管理实现
2.Spring中事务隔离级别default (数据库默认事务)
-
default (使用数据库默认的事务隔离级别)
-
read uncommitted (读未提交),这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
-
read committed (读已提交),保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
-
repeatable read (可重复读)这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免不可重复读。(mysql默认的事务隔离级别)
-
serializable (串行化)这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
3.Spring事务的传播级别?
spring事务的传播机制说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。事务传播机制实际上是使用简单的ThreadLocal实现的,所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的。
默认 Required 级别。
级别 | 描述 |
---|---|
REQUIRED | 支持当前事务,如果没有事务会创建一个新的事务 |
SUPPORTS | 支持当前事务,如果没有事务的话以非事务方式执行 |
MANDATORY | 支持当前事务,如果没有事务抛出异常 |
REQUIRES_NEW | 创建一个新的事务并挂起当前事务 |
NOT_SUPPORTED | 以非事务方式执行,如果当前存在事务则将当前事务挂起 |
NEVER | 以非事务方式进行,如果存在事务则抛出异常 |
NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作 |
二者非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。但 |
1)使用 REQUIRES_NEW 时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要 JTA 事务管理器的支持。
2)使用 NESTED 时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。
4.Spring事务什么时候会失效
spring 事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不起作用了。常见情况有如下几种:
1.发生自调用,类里面使用this调用本类的方法(this通常忽略),此时这个this对象不是代理类,而是xxxService对象本身,解决方法很简单,就是让这个this变成xxxService的代理类即可
2.方法不是public的
@Transactional 只能用于public 的方法上,否则事务会失效,如果要用在非 public 方法上,可以开启AspectJ 代理模式
3.数据库不支持事务
4.没有被spring管理
5.异常被catch,事务不会回滚(或者抛出的异常没有被定义,默认为RuntimeException)
5.@transactional注解原理
这个事务注解很简单。其实就是通过拦截器拦截注解,然后加载注解参数,根据隔离级别来判断是否需要创建事务,
如果有多个事务隔离级别,就会涉及到事务保存点, 或者是不同事务之间还会涉及掉事务挂起
- 事务保存点:依托mysql数据库机制,用于回滚部分逻辑。比如事务有三个时间点(A->B1->B2->C),其中B1->B2是事务保存点,
如果这时候B失败,并没有抛异常到上一个方法,这时候只会回滚B1->B2执行的sql逻辑
– 嵌套事务NESTED就是依托于事务保存点来处理,这就是为什么出异常子方法回滚了,而调用它的方法事务不会回滚(正常执行的时候子方法执行完会移除事务保存点)
6.SpringMVC
1.SpringMVC请求流程
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
2.SpringMVC核心组件讲解
1、前端控制器DispatcherServlet
作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
2、处理器映射器HandlerMapping
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
4、处理器Handler
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。
5、视图解析器View resolver(不需要工程师开发),由框架提供
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。
6、视图View
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)