- java开发面试问答----基础篇
- java开发面试问答----多线程篇
- java开发面试问答----spring框架及数据库缓存篇
- java开发面试问答----设计模式篇
- java开发面试问答----分布式篇
- java开发面试问答----微服务篇
- java开发面试问答----devops篇
参数配置
YAML配置和properties配置相比有什么区别
- 配置有序,在一些特殊的场景下,配置有序很关键
- 支持数组,数组中的元素可以是基本数据类型也可以是对象
- 简洁
- 不支持 @PropertySource 注解导入,需要创建一个实现PropertySourceFactory接口的类
获取配置文件中的参数有哪几种方式
- @Value
- @ConfigurationProperties
- 通过Environment
final ApplicationContext ctx = SpringApplication.run(SpringBootDemo3Application.class, args); Environment environment = ctx.getEnvironment(); System.out.println(environment.getProperty("datasource.username")); - @PropertySource注解加载自定义的配置文件
spring
spring框架的原理
spring框架的核心是IOC控制反转和依赖注入。
- 什么是控制反转:通常一个对象要调用另外一个对象必须将对方new出来,然后在使用完后销毁掉,这就造成了对象之间的强耦合,而spring做的事情是将所有的对象注册到bean factory中,如果一个对象要调用另外一个直接从bean factory中取就好,对于一个对象而言,之前是它控制其他对象的生命周期,而现在是spring 控制所有对象的生命周期,这就是控制的反转(控制权上交)。
- 什么是依赖注入:既然所有对象的生命周期都被spring控制了,那如果一个对象要调用其他对象要怎么办呢,这就需要从spring中获取这个对象然后注入到自己里面来,这就是依赖注入。实现依赖注入的重要方法就是反射。
AOP和IOC原理
- IOC实现原理:一个bean有id,类型和属性,首先需要定义一个bean的配置,spring读取配置实例化bean写到一个map中,map的key是bean id,value就是这个bean,如果有依赖其他对象,则从map中获取这个对象然后使用set方法set到bean属性中,最后返回这个bean的实例。
- AOP:面向切面编程,在一个业务流程中有多个横向关注点,比如权限验证日志打印,在aop中几个重要概念:
- 连接点:指需要切入执行的方法
- 切入点:围绕连接点的一种判断表达式,判断是否要执行
- 通知:通知有前置,后置,环绕,后置返回四种,当满足切入点时会发起通知
- Aop实现技术有aspectj和spring aop两种,aspectj是编译时增强,需要按照规范写一个代理类增强业务类,而spring aop是动态代理实现,支持jdk代理和cglib代理,jdk动态代理是利用反射机制生成代理类连接点执行前执行的invokeHandler。
动态代理
动态代理是指通过类加载器和接口复制在具体方法执行时使用invokeHandler执行额外的操作。
beanfactory和factory bean的区别
beanfactory是ioc容器,管理所有bean的生命周期,而factorybean是一个特殊的bean,它可以生产某一个特定bean,通常用来封装复杂bean的实例化过程。
如何实现(保证)事务一致性完整性,spring中事务传播机制类型
- REQUEST:方法必须在事务中执行,如果当前有事务则执行,如果没有则启动一个新的事务执行
- SUPPORT:如果当前有事务则在事务中执行,如果没事务则以非事务执行
- REQUEST_NEW:方法必须在自己的事务中执行,每次启动一个新的事务,两个事务互不影响
- MANDATORY:方法必须在事务中执行,没有事务则抛错
- NOT_SUPPORT:方法总是非事务的执行,如果存在外层事务,则外层事务挂起,方法非事务的执行
- NEVER:方法总是非事务的执行,如果存在外层事务则抛错
- NESTED:如果当前存在事务则挂起外层事务,启动子的事务执行,子事务执行失败会回到save点,外层事务回滚会影响子事务,子事务在外层事务commit时才commit
spring如何定义一个bean?代码描述。Bean的生命周期?Bean的scope?
将bean注册到spring有三种方法:使用@Component@Service注解,使用xml配置文件定义,基于java配置@bean。 首先是bean的实例化,然后调用set方法设置属性,获取上下文,执行关联器的before方法,执行初始化bean接口的afterPropertiesSet方法,执行init方法,执行关联器的after方法,bean完成,容器关闭,执行destroy方法。spring管理的bean默认都是单例的,非单例的bean会交给用户自己管理
MVC相关
什么是servlet,servlet生命周期
servlet是服务器端处理http请求小程序,当客户端发起请求时,服务器接到请求并发送给servlet,当servlet第一次被访问时执行实例化,并init初始化操作,servlet执行service方法生成响应内容后返回给服务端,服务端返回给客户端,最后当servlet关闭时执行servlet的destory方法销毁。
注解restcontroller和controller的区别
@RestController = @Controller + @ResponseBody
1、如果使用@RestController注解controller,则controller中的方法无法返回页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是return的内容。
2、如果需要返回到指定页面,需要使用@Controller注解controller
3、如果需要直接返回内容如json,则需要在方法前使用@ResponseBody
拦截器和过滤器的区别
过滤器实现Filter接口,拦截器实现HandlerInterceptor接口
相同点:
- 都是aop编程思想的体现,可以在程序执行前后做一些操作,如权限操作,日志记录等
不同点:
- Filter是Servlet规范中定义的,SpringMVC的机制是由DispaterServlet来分发请求给不同的Controller,拦截器是Spring框架中的
- 触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的,过滤器在拦截器的外围
- 拦截器可以获取IOC容器中的各个bean,而过滤器就不行,拦截器归Spring管理
何时使用拦截器?何时使用过滤器?
- 如果是非spring项目,那么拦截器不能用,只能使用过滤器。
- 如果是处理controller前后,既可以使用拦截器也可以使用过滤器。
- 如果是处理dispaterServlet前后,只能使用过滤器。
spring mvc框架
(1)首先浏览器发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
(2)DispatcherServlet——>HandlerMapping,处理器映射器将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器对象、多个HandlerInterceptor拦截器)对象;
(3)DispatcherServlet——>HandlerAdapter,处理器适配器将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
(4)HandlerAdapter——>调用处理器相应功能处理方法,并返回一个ModelAndView对象(包含模型数据、逻辑视图名);
(5)ModelAndView对象(Model部分是业务对象返回的模型数据,View部分为逻辑视图名)——> ViewResolver, 视图解析器将把逻辑视图名解析为具体的View;
(6)View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构;
(7)返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
mybatis mysql
#{}和${}的区别
{}直接替换成变量的值,不做任何转换,这种是取值以后再去编译SQL语句。
- #{}:预编译处理,sql中的#{}替换成?,补全预编译语句,调用PreparedStatement的set方法来赋值,有效的防止Sql语句注入,这种取值是编译好SQL语句再取值。
CHAR和VARCHAR的区别
mybaits在处理char类型时会把字符串补齐长度再比较,如果数据库中数据小于定义的char长度则会右侧补齐空格,而varchar没有这个问题。
like查询的几种方式
- like '%${xxx}%'
- like "%"#{xxx}"%"
- like concat('%',#{xxx},'%')
事务的概念,脏读,如何定义一个事务,如何定义事务的隔离级别
- 事务是一个最小的完整业务工作单元,它具有原子性(事务不可分割),一致性(要求所有DML操作要么同时成功要么同时失败),隔离性(不同的事务之间互不影响)和持久性(事务完结内存数据写到磁盘)
- mybatis的事务管理是用sqlsession做的,打开一个session后事务开始直到session被commit;spring事务管理中将事务的实现交给jdbc,jta,自身封装相同的api,要实现一个事务,可以使用@transcational注解。
- 第一类更新丢失,指事务b回滚将事务a的修改也回滚了,这种是没有隔离
- 脏读的意思是读取了未提交的数据,事务a读取了事务b修改的数据,结果事务b回滚导致事务a中产生了脏数据。
- 不可重复读的意思是同一个事务中不能读取重复的数据,原因是并发状态同一个事务中可能前后两次读取的数据不一致。
- 第二类更新丢失,指事务b修改将事务a修改的数据覆盖了。
- 幻读和不可重复读有点像,意思是同一个事务中前后两次统计的条数不一致了。和不可重复度的区别是不可重复读读到的是别人修改的数据,而幻读读到的是别人新增的数据。
隔离级别
- 读未提交:事务读不锁其他事务写也不锁读,事务写只锁其他事务写不锁读,可以防止第一类更新丢失,对写操作上持续排他锁
- 读已提交:事务读不锁其他事务写也不锁读,事务写锁其他事务写也锁事务读,可以防止脏读,对写操作上持续排他锁,对读操作上临时共享锁
- 可重复读:事务读锁其他事务写不锁事务读,事务写锁其他事务写也锁事务读,可以防止不可重复读,写操作上持续排他锁,读操作上持续共享锁(mysql默认隔离级别)
- 串行化:所有操作串行化,表锁
锁的级别
innodb 有读锁(共享锁)和写锁(排他锁),读锁时其他事务只能读不能写,写锁时其他事务不能读也不能写。innodb在检索时如果不使用索引采取的是表级锁,采用索引则是行级锁,这是因为innodb是通过对索引项加锁实现的行级锁。另外innodb为了解决幻读问题采用了间隙锁,当范围查询时会将不存在的id也锁住防止新增数据。
redis相关
使用场景
- 计数器 数据统计的需求非常普遍,通过原子递增incr保持计数。由于redis中存的是字符串,在递增时会把字符串转成十进制64位有符号整数计算。例如,点赞数、收藏数、分享数等。
- 锁 setnx设置全局锁
- 缓存 缓存一些热点数据
- 消息队列 通过list的pop及push接口进行队列的写入和消费
持久化机制
- redis支持两种持久化机制
- 一种是rdb快照模式,将内存中的数据不断写入磁盘,优点是可以存储大量数据,缺点是每次生成快照时主线程会fork一个子线程写数据,会影响性能,另外如果突然断电数据还没落盘则会丢失。
- 一种是aof日志模式,记录每次更新的日志,这种方式详细记录了操作,弥补了rdb的一致性问题,但是aof文件记录太多会导致恢复很慢。
redis memcache的区别
- memcache将数据全部放在内存中,断电会丢失,而redis支持持久化存储可以将数据存在硬盘上
- redis支持的数据类型比memcache更丰富,在kv之外还支持如list,set,hash等
- memcache最大不能超过内存大小,而redis由于可以写磁盘可以突破内存大小
- 通常memcache仅用作数据库前的一层内存缓存,适合多读少写的场景;而redis由于支持更丰富的数据类型有更高的可靠性,可以当成内存数据库使用