首页 > 技术文章 > SSM面试题

Y-wee 2021-12-08 17:08 原文

SSM面试题

整理一些常见的SSM面试题

Spring

Spring是一个轻量级Java开发框架,为开发Java应用程序提供全面的基础架构支持。spring是很多模块的集合,使用这些模块可以很方便地协助我们进行开发,特点:轻量级、控制反转、面向切面、容器、框架集合

列举一些重要的spring模块

  • Spring Core:基础,可以说Spring其他所有的功能都依赖于该类库。主要提供IOC和DI功能
  • Spring Aspects:该模块为与AspectJ的集成提供支持
  • Spring AOP:提供面向方面的编程实现
  • Spring JDBC:Java数据库连接
  • Spring JMS:Java消息服务
  • Spring ORM:用于支持Hibernate等ORM工具
  • Spring Web:为创建Web应用程序提供支持
  • Spring Test:提供了对JUnit和TestNG测试的支持

什么是spring的IOC和AOP

IOC(Inversion Of Controll,控制反转)是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由给Spring框架来管理。将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象的注入,这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来

AOP(Aspect-Oriented Programming,面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性

Spring AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP就会使用JDK动态代理去创建代理对象;而对于没有实现接口的对象,就无法使用JDK动态代理,转而使用CGlib动态代理生成一个被代理对象的子类来作为代理

动态代理不了解可以参考文章:https://www.cnblogs.com/leifei/p/8263448.html

请阐述spring编程式事务管理和声明式事务管理

  • 编程式事务:在代码中硬编码,使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。
  • 声明式事务:使用注解或在配置文件中配置,建立在AOP之上。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码
  • 显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。和编程式事务相比,声明式事务唯一不足地方是,它的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

Spring 中的 bean的作用域有哪些

  • singleton:唯一bean实例,Spring 中的bean 默认都是单例的
  • prototype:每次请求都会创建一个新的bean实例。
  • request:每一次HTTP请求都会产生一个新的bean,该作用域仅适用于WebApplicationContext环境
  • session:同一个HTTP Session共享一个bean,该作用域仅适用于WebApplicationContext环境
  • global-session: 全局session作用域,该作用域仅适用于WebApplicationContext环境,Spring5中已经没有了

Spring中的单例bean线程安全吗

不安全,解决方案:在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中

Spring中的bean生命周期

1.Bean容器找到配置文件中Spring Bean的定义

2.Bean容器利用Java Reflection API创建一个Bean的实例

3.如果涉及到一些属性值,利用set()方法设置一些属性值。

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

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

6.如果Bean实现了BeanFactoryAware接口,调用setBeanClassFacotory()方法,传入ClassLoader对象的实例。

7.与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。

8.如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessBeforeInitialization()方法。

9.如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。

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

11.如果有和加载这个Bean的Spring容器相关的BeanPostProcess对象,执行postProcessAfterInitialization()方法。

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

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

参考文章:https://www.cnblogs.com/javazhiyin/p/10905294.html

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

  • 工厂设计模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象
  • 代理设计模式:Spring AOP功能的实现
  • 单例设计模式:Spring中的bean默认都是单例的
  • 模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式
  • 包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
  • 观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用
  • 适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller

spring中BeanFactory和ApplicationContext的区别

参考:https://www.cnblogs.com/Y-wee/p/13813649.html

spring中的事务传播行为

事务的传播行为,默认值为 Propagation.REQUIRED。可以手动指定其他的事务传播行为,如下:

  • Propagation.REQUIRED:如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务

  • Propagation.REQUIRES_NEW:重新创建一个新的事务,如果当前存在事务,则将当前的事务挂起

  • Propagation.SUPPORTS:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行

  • Propagation.NOT_SUPPORTED:以非事务的方式运行,如果当前存在事务,则将当前的事务挂起

  • Propagation.MANDATORY:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常

  • Propagation.NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常

  • Propagation.NESTED:如果当前存在事务,就在当前事务中嵌套其他事务;如果当前没有事务,就新建一个事务

SpringMVC

SpringMVC是一个轻量级Web框架

SpringMVC的执行流程

  • 用户发送请求至前端控制器
  • 前端控制器收到请求后,调用处理器映射器,请求获取Handler
  • 处理器映射器找到具体的处理器返回给前端控制器
  • 前端控制器请求处理器适配器去执行相应的Handler处理器
  • Handler处理器执行业务逻辑
  • Handler处理器执行完毕之后会返回给处理器适配器一个ModelAndView对象
  • 处理器适配器接收到Handler处理器返回的ModelAndView后,将其返回给前端控制器
  • 前端控制器接收到ModelAndView后,会请求视图解析器(ViewResolver)对视图进行解析
  • 视图解析器根据View信息匹配到相应的视图结果,反馈给前端控制器
  • 前端控制器收到View具体视图后,进行视图渲染,向用户返回请求结果

springmvc中如何解决post请求和get请求乱码问题

post请求乱码:web.xml中配置编码过滤器

get请求乱码:修改tomcat的server.xml配置文件,在Connector标签中设置URIEncoding

<Connector URIEncoding="UTF-8"></Connector>

Mybatis

通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么

Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行映射文件中的sql,然后将sql执行结果返回

Dao接口里的方法,参数不同时,方法能重载吗

Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略

Mybatis是如何进行分页的

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页。还可以自己写sql实现分页功能或者使用分页插件实现分页。

Mybatis映射文件中,如果A标签通过include引用了B标签的内容,请问,B标签能否定义在A标签的后面,还是说必须定义在A标签的前面

虽然Mybatis解析Xml映射文件是按照顺序解析的,但是,被引用的B标签依然可以定义在任何地方,Mybatis都可以正确识别。

原理是,Mybatis解析A标签,发现A标签引用了B标签,但是B标签尚未解析到,尚不存在,此时,Mybatis会将A标签标记为未解析状态,然后继续解析余下的标签,包含B标签,待所有标签解析完毕,Mybatis会重新解析那些被标记为未解析的标签,此时再解析A标签时,B标签已经存在,A标签也就可以正常解析完成了。

Mybatis是否支持延迟加载

Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false

Mybatis延迟加载的实现原理

它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。

Mybatis的一级、二级缓存实现原理

一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,Mybatis默认打开一级缓存,一级缓存存放在BaseExecutor的localCache变量中

二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace)级别。Mybatis默认不打开二级缓存,可在xml配置打开

对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被清除并重新更新,如果开启了二级缓存,则只根据配置判断是否刷新

推荐阅读