- 一. Spring面试基础
- 二. Spring面试重点
- 三. SpringMVC面试题
- 四. Mybatis面试题
- {}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
使用建议:
能用 #{} 的地方就用 #{},不用或少用 ${}
表名作参数时,必须用 ${}。如:select from ${tableName}
order by 时,必须用 ${}。如:select from t_user order by ${columnName}
使用 ${} 时,要注意何时加或不加单引号,即 ${} 和 ‘${}’ - 五. SpringBoot
一. Spring面试基础
1. Spring框架相关组件
1) Spring Core:核心类库,提供IOC服务;
2) Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
3) Spring AOP:AOP服务;
4) Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
5) Spring ORM:对现有的ORM框架的支持;
6) Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;
7) Spring MVC:提供面向Web应用的Model-View-Controller实现。
2. 什么是IOC和DI
IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。
DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
3. SpringBean的配置方式
1) 基于XML的配置
2) 基于注解的配置(@Component、@Repository、@Controller @Service)
在Spring的配置文件中 定义注解扫描的范围
这样 在com.itcast包下的所有标注了 @Component、@Repository、@Controller注解的类,会被注册到容器中
3) 基于Java类+配置注解的方式(@Configuration @Bean)
4. IOC容器Bean的常见属性
id标签是bean的唯一标识,IoC容器中bean的id标签不能重复,否则报错。
name是bean的别名,可以定义多个
class属性是bean常用属性,为bean的全限定类名,指向classpath下类定义所在位置
factory-method属性factory-method工厂方法属性,通过该属性,我们可以调用一个指定的静态工厂方法,创建bean实例。
scope属性 bean的作用范围
init-method和destory-method属性 Bean的初始化和销毁时执行的方法
autowire属性 表示bean的自动装配方式 可选值: no:默认,不进行自动装配 .byName .byType
5. IOC容器Bean的作用域
singleton:表示整个IOC容器共享一个Bean,也就是说每次说每次通过getBean获取的bean都是同一个。
prototype:每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。 request:每次HTTP请求将会生成各自的bean实例
session:每次会话请求对应一个bean实例
global-session:全局作用域
6. IOC依赖注入方式
7. IOC容器中重要的类
IOC容器的顶级接口 BeanFactory , 仅提供了最基本的容器方法
ApplicationContext接口 则扩展了BeanFactory,提供了很多功能,使我们常用的容器
BeanFacotry的实现类 XmlBeanFactory
ApplicationContext的实现类:
ClassPathXmlApplicationContext:可以加载类路径下的配置文件,实现容器的实例化。
FileSystemXmlApplicationContext:可以加载磁盘任意路径下的配置文件,实现容器的实例化。(必须有访问权限)
AnnotationConfigApplicationContext :扫描配置注解,根据注解配置实现容器的实例化。
8. Spring的常用注解
@ComponentScan 组件扫描, 会扫描指定包下的 @Component @Controller @Service @Repository @Controller 标注当前类为容器的对象,代表控制组件 @Service 标注当前类为容器的对象,代表服务组件 @Repository 标注当前类为容器的对象,代表持久组件 @Component 标注当前类为容器的对象,代表组件 @Autowired 自动装配注解 默认按类型装配 @Transactional 事务注解 @Value 将配置文件中的值,注入到指定字段 @Bean 配置bean对象 标签作用一致 @Configuration 标注当前的java类是一个配置类
9. Autowired和Resource注解区别
1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2、 @Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以搭配@Qualifier注解进行使用
3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
二. Spring面试重点
1. IOC容器初始化流程
1) 创建配置: 基于xml 或 基于注解 配置Spring Bean
2) 配置解析:
①读取xml内容,并得到一个Document对象
②解析Document对象,遍历bean标签的节点
③将每一个Bean标签封装成一个BeanDefinition对象
3) 注册bean定义到容器中:
①将bean的定义对象 存储到容器中的map集合中
②map集合: 在容器的核心实现类 DefaultListableBeanFactory中, ConcurrentHashMap
③以 bean标签中配置的id作为key
④以 beanDefinition对象作为value存储到map集合中
4) 初始化所有单例对象
①完成注册后,查看所有注册bean定义
②如果是非抽象 、 并且不是懒加载的单例对象会被立刻创建
③创建出来的单例对象会存储到singletonObjects map集合中 也是一个ConcurrentHashMap
2. IOC容器getBean流程
1) 判断单例map集合中 是否已经创建该对象
①有返回
②没有下一流程
2) 判断是否存在父容器,且父容器是否包含该对象
①包含: 调用父容器的getBean
②没有下一流程
3) 准备尝试创建对象,beanDefinitionMap中获取bean定义
①没有 抛出NoSuchBeanDefinition
②有下一流程
4) 判断bean定义的scope属性
①单例: 1.调用createBean创建对象 2.加入单例map集合
②多例: 调用createBean创建对象
③其它
5) createBean创建对象
①获取要创建bean的class
②判断是否使用工厂方法创建对象: 调用工厂方法创建对象
③运行到这里说明是使用构造器创建:
1.根据构造器参数的个数、类型
2.确定到底使用哪个构造器创建
3.使用JDK反射方法创建对象
6) 依赖注入: 调用populateBean方法进行依赖注入
3. SpringBean的循环依赖和覆盖问题
1) 循环依赖
- 如果对象都是多例对象 会报循环依赖异常
- 如果是单例对象:
- 如果是通过构造器依赖的属性, 会报循环依赖异常
- 如果是通过属性依赖产生的循环依赖, 默认允许循环依赖
- 设置allowCircularReferences为false 会报循环依赖异常
2) 同名bean的覆盖问题
默认情况:同一个配置文件中出现id相同的bean会报错
不同的配置文件出现id相同的bean, 后加载的bean会将先加载的bean覆盖掉, 称为bean的覆盖
bean的覆盖不会报错, 但可能影响我们的项目, 可以通过属性设置, 不允许bean的覆盖
allowBeanDefinitionOverriding设置为false
4. Spring管理Bean的生命周期
1) bean对象的实例化
2) 封装属性,也就是设置properties中的属性值
3) 如果bean实现了BeanNameAware,则执行setBeanName方法,也就是bean中的id值
4) 如果实现BeanFactoryAware或者ApplicationContextAware ,需要设置setBeanFactory或者上下文对象setApplicationContext
5) 如果存在类实现BeanPostProcessor后处理bean,执行postProcessBeforeInitialization,可以在初始化之前执行一些方法
6) 如果bean实现了InitializingBean,则执行afterPropertiesSet,执行属性设置之后的操作
7) 调用
8) 如果存在类实现BeanPostProcessor则执行postProcessAfterInitialization,执行初始化之后的操作
9) 执行自身的业务方法
10) 如果bean实现了DisposableBean,则执行spring的的销毁方法
11) 调用
5. SpringAOP面试点
1) 谈谈你对AOP的理解
Aspect Orieted Programming ,中文叫“面向切面编程”或“面向方面编程”
是一种编程模式,将分布在多个类中的功能封装到一个类中,这些功能称为cross-cutting concerns(横切关注点),如日志、事务、缓存权限、安全等
不是替代OOP,而是对其的补充
2) 项目中AOP的实际应用场景?
比较常用的 事务、权限、异常、 用户行为日志、 性能监控、缓存等等
3) AOP的具体使用方式?
①定义切面类 我们使用注解的方式 @Aspect @Component
②定义切入点表达式 可以通过 扫描包的方式 也 可以通过指定注解的方式
③定义通知: 通知分5种 前置、后置、异常、最终、环绕通知
4) 以用户行为日志举例AOP的使用
①日志效果
②定义日志注解,在需要记录日志的方法中加上注解
③引入aop依赖
④定义切面及切入点
⑤定义环绕通知,记录日志内容
ThreadLocal获取当前登录用户信息
将日志行为信息保存数据库
5) 基于AOP实现读写分离数据源动态处理
①配置读写两个数据源
②使用AOP根据方法名,动态选择数据源
6) AOP的工作原理?
①AOP的底层的工作原理 就是使用动态代理对目标业务进行增强
②而动态代理主要有JDK 和 CGLIB两种动态代理实现
③JDK是自带的的动态代理实现,要求被代理的类必须实现接口
④CGLIB是开源的动态代理实现,需要引入依赖,要求被代理的类必须可以被继承
6. Spring事务面试点
1) Spring事务的配置方式
①注解方式配置
②基于aop的tx标签配置
2) Spring事务的隔离级别: Spring 默认使用数据库的隔离级别
①ISOLATION_READ_UNCOMMITTED:读未提交
②ISOLATION_READ_COMMITTED:读已提交
③ISOLATION_REPEATABLE_READ:可重复读
④ISOLATION_SERIALIZABLE:串行化
3) Spring事务的失效场景
①数据库引擎不支持事务(innoDB )
②没有被Spring管理
③方法不是public的
④自身调用问题
⑤数据源未配置事务管理
⑥传播行为中设置了不支持事务
⑦异常被捕获掉
⑧异常类型错误, 默认捕获RuntimeException异常
4) Spring事务的传播行为
①PROPAGATION_REQUIRED
表示当前方法必须在一个具有事务的 上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。( 如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
②PROPAGATION_REQUIRES_NEW
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
③PROPAGATION_SUPPORTS
表示当前方法不必需要具有一个事务 上下文,但是如果有一个事务的话,它也可以在这个事务中运行
④PROPAGATION_MANDATORY
表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常
⑤PROPAGATION_NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务。
⑥PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常
⑦PROPAGATION_NESTED
表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中 ,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。如果封装事务不存在,则同propagation. required的一样
7. Spring使用的设计模式
1) 工厂模式: Spring中的FactoryBean就是典型的工厂方法模式。使用工厂模式创建对象的实例
2) 单例模式:在Spring配置文件中定义的Bean默认为单例模式
3) 模板方法:用来解决代码重复的问题,比如我们常使用的RestTemplate、JmsTemplate、JpaTemplate都是基于模板方法
4) 代理模式: AOP的底层实现就是基于JDK动态代理 及 CGLIB动态代理
5) 观察者模式:
①定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
②spring中Observer模式常用的地方是listener的实现。如ApplicationListener
6) 适配器模式:AOP的方法拦截器中
7) 策略模式:Spring中在实例化对象的时候用到Strategy模式
三. SpringMVC面试题
1. SpringMVC的常用注解
1) @RequestMapping 指定请求资源路径
2) @ResponseBody 注解表示将该方法的返回值 直接返回到客户端,一般我们返回的都是 json
3) @RequestBody 接收前台 json参数
4) @RequestParam 接收前台表单参数 key = value 形式参数 ? a=1 & b=2
5) @PathVariable 获取路径参数的** http:ip:port/user/{id}
6) @RestController 相当于 @ResponseBody 和 @Controller的合体
7) @ControllerAdvice controller的增强注解,用于统一处理功能:如统一异常处理
8) @ExceptionHandler 异常处理
9) @CookieValue 指定cookie中的参数
10) @RequestHeader 指定请求消息头中的参数
2. SpringMVC运行流程
1) 用户发送请求至前端控制器DispatcherServlet;
2) DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
3) 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
4) DispatcherServlet 调用 HandlerAdapter处理器适配器;
5) HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
6) Handler执行完成返回ModelAndView;
7) HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
8) DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
9) ViewResolver解析后返回具体View;
10) DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
11) DispatcherServlet响应用户。
3. Filter、Interceptor、Aop实现与区别
AOP使用的主要是动态代理;过滤器使用的主要是函数回调;拦截器使用是反射机制 。
一个请求过来 ,先进行过滤器处理,看程序是否受理该请求 。 过滤器放过后 程序中的拦截器进行处理 ,处理完后进入 被 AOP动态代理重新编译过的主要业务类进行处理 。
Filter:和框架无关,可以控制最初的http请求,但是更细一点的类和方法控制不了。
Interceptor:可以控制请求的控制器和方法,但控制不了请求方法里的参数(用于处理页面提交的请求响应并进行处理,例如做国际化,做主题更换,过滤等)。
Aspect : 可以自定义切入的点,有方法的参数,但是拿不到http请求,可以通过其他方式如RequestContextHolder获得。
都可以实现权限检查,日志记录。不同的是使用的范围不同,规范不同,深度不同。
4. SpringMVC如何上传图片
1) 依赖两个jar包 commons-io.jar 及 commons-fileupload.jar
2) 首先在spring mvc的配置文件中配置 Mutipart解析器
3) 然后前端上传图片的时候需要在form 表单上加上enctype=mutilpart-data
4) 后台controller的接收方法中 使用spring的 MutilpartFile接收文件对象
四. Mybatis面试题
1. #{}和${}的区别是什么
{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
使用建议:
能用 #{} 的地方就用 #{},不用或少用 ${}
表名作参数时,必须用 ${}。如:select from ${tableName}
order by 时,必须用 ${}。如:select from t_user order by ${columnName}
使用 ${} 时,要注意何时加或不加单引号,即 ${} 和 ‘${}’
2. 实体类中的属性名和表中的字段名不一样,怎么办
写sql语句时起别名 ,别名和属性相对应
在MyBatis的全局配置文件中开启驼峰命名规则 ,mybatis会将数据库中 下划线的字段自动转为驼峰格式的属性
在Mapper映射文件中使用resultMap来自定义映射规则
3. 常见的mybatis的动态标签
4. 标签的作用及如何使用
5. Mapper接口里的方法,参数不同时,方法能重载吗
不可以,不论是注解配置的mybatis 还是xml配置的mybatis,被解析后每个方法都会封装成一个MappedStatement 存储到一个map集合中,集合的key使用的是mapper接口的全限类名+方法名,value就是MappedStatement对象。
如:
我想写个重载方法 findUser 一个带ID参数 返回值User 一个不带参数 返回值为List
6. 如何获取自动生成的(主)键值
1.可以通过查询最后一条的sql语句
SELECT LAST_INSERT_ID()
2.也可以通过mybatis的标签属性
useGeneratedKeys
7. 在Mapper中如何传递多个参数
1) 通过实体类传参
2) 通过map传参
3) 通过定义多个@Param注解传参
8. MyBatis如何执行批量插入
1) 通过mybatis的
2) 利用 MyBatis 批处理特性,批量提交(ExecutorType.BATCH)
3) SimpleExecutor 简单执行器
4) ReuseExecutor 可复用的执行器
5) BatchExecutor 批量
9. 介绍一下MyBatis的二级缓存
1) 一级缓存:默认开启
一级缓存的范围是同一个SqlSession对象,当我们使用SqlSession对象进行查询时mybatis会帮我们把查询的数据存入到内存中,当我们在这个SqlSession中再一次执行同样的查询操作时,我们就可以直接去缓存中获取数据
2) 二级缓存:默认关闭
二级缓存是mapper级别的缓存,多个SqlSession共享,其作用域是mapper的同一个namespace,不同的SqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。
3) 顺序: 二级缓存 ———> 一级缓存 ——> 数据库
10. 一对一、一对多的关联查询
1) 一对一关联查询
在xml中定义映射关系, 使用association代表关联一个实体类, property映射的属性名,javaType该属性的实体类类型,fetchType是否延迟加载,column用于执行select方法所传递的参数,select需要执行的mapper方法的全限定名称
2) 一对多的关联查询
在xml中定义映射关系,因为是一个集合 所以使用collection标签,ofType代表集合中实体类的类型,其他属性和上面对一的情况一致
11. MyBatis是如何进行分页的
可以通过pageHelper插件实现分页
PageHelper.startPage(1,1); // 在代码中执行startPage方法 第一个参数第几页,第二个是几条数据
PageHelper分页的实现在我们执行SQL语句之前动态的将SQL语句拼接了分页的语句,从而实现了从数据库中分页获取数据的过程。
12. MyBatis与Hibernate有哪些不同
1) Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
2) Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
3) Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。
13. Mybatis中使用到了哪些设计模式
1) Builder模式,例如SqlSessionFactoryBuilder、XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder、CacheBuilder;
2) 工厂模式,例如SqlSessionFactory、ObjectFactory、MapperProxyFactory;
3) 单例模式,例如ErrorContext和LogFactory;
4) 代理模式,Mybatis实现的核心,比如MapperProxy、ConnectionLogger,用的jdk的动态代理;还有executor.loader包使用了cglib或者javassist达到延迟加载的效果;
5) 装饰者模式,例如Cache包中的cache.decorators子包中等各个装饰者的实现;
6) 组合模式,例如SqlNode和各个子类ChooseSqlNode等;
7) 模板方法模式,例如BaseExecutor和SimpleExecutor,还有BaseTypeHandler和所有的子类例如IntegerTypeHandler;
8) 适配器模式,例如Log的Mybatis接口和它对jdbc、log4j等各种日志框架的适配实现;
9) 迭代器模式,例如迭代器模式PropertyTokenizer;
五. SpringBoot
1. Spring 和 SpringBoot的区别
介绍:
SpringBoot 是Spring旗下的一款开发框架,他可以让我们创建基于Spring的应用变得更加的方便,
SpringBoot 整合了常用的Spring和第三方的类库,整合后提供带Starter的pom,整合后的项目采用自动配置,如果配置不满足需要,SpringBoot也提供了配置文件 只需简单的修改便可以。
SpringBoot内置了 servlet容器(tomcat,jboss)使得我们的项目启动部署更加的方便 (java -jar xx.jar)
Springboot 提供了企业级应用的健康检测方案
优点:
①快速搭建项目,
②与主流框架集成无需配置集成.
③内嵌服务容器.
④具有应用监控.
⑤开发部署方便
2. SpringBoot中常见的starter
https://docs.spring.io/spring-boot/docs/2.3.12.RELEASE/reference/html/using-spring-boot.html#using-boot-starter
3. SpringBoot的配置文件
springboot启动后 会默认的去指定文件夹加载 名称为 application的文件,后缀为
.properties 或 .yml .yaml
如果在同一目录下出现多个配置文件: springboot会都加载
application.properties > .yml > .yaml
属性名相同: 优先级高的生效
属性名不同: 都生效
项目目录:
config:
application.yml
项目目录:
application.yml
项目目录:
resources:
config
application.yml
项目目录:
resources:
application.yml
4. yml配置文件语法
配置普通数据:
语法: key: value
如: name: xiaoming
注意: : 和 value间一定要有空格
配置对象或map数据:
语法: key:
key1: value1
key2: value2
或: key: {key1: value1,key2: value2}
如: person:
name: xiaoming
first: 1 (会报错)
age: 3
注意: 相同缩进代表同一级别. name和age同一级别都是person的属性
如果属性有了值就不能在有下级属性
配置集合数组:
语法: key:
- value1
- value2
或: key: [value1,value2]
注意: -符号 一定要在同一级别,并且和属性间要有空格
配置对象集合
语法: key:
- key1: value
key2: value - key1: value
key2: value
或: key: [{key1: value1,key2: value2},{key1: value1,key2: value2}]
注意: -符号 一定要在同一级别,并且和属性间要有空格5. 如何读取自定义的配置
1) @Value
@Value(“${name}”)
String name;
@Value(“${person.name}”)
String personName;
@Value(“${city[0]}”)
String cityFirst;
2) @ConfigurationProperties(prefix = “xxl.job”)
@Data
@Component
@ConfigurationProperties(prefix = “config-attributes”)
public class ConfigModel {
private String val;
private int[] valArr;
private ListcityList;
private Map valMap;
private List6. 如何定义多环境配置
如果所有环境配置都写到一个配置文件中,不好维护
可以定义多个环境配置文件的方式来实现:
如:
application-{环境名称}.yml
application-dev.yml
application-test.yml
application-prod.yml
spring:
profiles:
active: prod 激活生产环境的配置7. SpringBoot自动配置的原理
@SpringBootApplication
1) @SpringBootConfiguration: 代表启动类可以直接使用@Bean来配置对象
2) @EnableAutoConfiguration 开启自动配置
①@AutoConfigurationPackage 扫描当前工程下的相关配置
②@Import 导入配置
1.获取候选配置列表: 所引依赖 META-INF/spring.factories文件
2.筛选配置:
1)去除重复的配置
2)去除指定排除的配置 exclude排除的
3)通过条件注解过滤配置:
①@ConditionalOnClass
②@ConditionalOnMissingBean
③@ConditionalOnXXXXX
3.筛选通过的配置,会被加载
3) @ComponentScan