1. 项目
1.1. 项目介绍
1.1.1. SSO
- 利用cookie解决跨域身份识别
- sdk封装思路
- 安全风险分析
1.1.2. 事件总线
1.1.3. Gateway
1.1.4. redis秒杀实现
1.1.5. 基础框架项目
1.1.5.1. 调用链
- Threadlocal
- RPC隐式传参
- logback扩展
1.1.5.2. 国际化
1.1.5.3. JSON序列化List问题优化
- TypeReferenceWrapper
- code template
- 泛型擦除问题分析
1.1.5.4. AOP事件探针方案
- annotation
- aop
- threadlocalTraceId
1.1.6. 服务化改造类项目经验总结
1.2. 项目过程相关技能
1.2.1. git
1.2.1.1. 原理
1.2.1.2. 常用命令
1.2.1.3. 分支模型
1.2.2. maven
1.2.2.1. 原理
1.2.2.2. 生命周期
1.2.2.3. 常用插件
1.2.3. 单元测试
1.2.3.1. junit
- 基础配置
- 引入 spring-boot-test-starter,scope=test
- @RunWith(SpringJUnit4ClassRunner.class)
- @SpringApplicationConfiguration(classes = {ApplicationTest.class})
- @Configuration
- 测试代码
@Test
@SqlGroup({
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, value = "classpath:h2/clean.sql"),
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, value = "classpath:h2/init-data.sql")
})
...
1.2.3.2. 嵌入式数据库
- 配置 test/resources/application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test;MODE=MYSQL;
spring.datasource.schema=classpath:h2/init-table.sql
mybatis.mapper-locations=classpath:sql-mappers/**/*.xml
1.2.3.3. mockito
- 生成mock bean,可以直接mock接口,不需要有实现类
@Bean
protected AppInfoCloudService appInfoCloudService() {
return mock(AppInfoCloudService.class);
}
- mock bean调用示例
//mock服务调用行为
when(appInfoCloudService.getAppInfo(any(Integer.class), any(Integer.class))).thenReturn(APIResponse.success());
1.2.4. linux开发环境
2. 基础
2.1. JAVA SE 基础
2.1.1. StringBuilder StringBuffer
- 线程安全
- StringBuilder是非线程安全的,StringBuffer是线程安全的
- 二者继承自同一个父类:AbstractStringBuilder
- StringBuffer相比StringBuilder在很多方法上增加了synchronized关键字
- 性能问题
- StringBuilder默认初始化的数组大小只有16
- 扩容时需要重新开辟一块内存(length*2+2),并拷贝原有数据
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
- 使用时需要考虑扩容造成的性能损失
- 使用时机
- 如果编译器本身能对String操作做优化,使用StringBuilder并不合算
2.1.2. NIO
2.1.2.1. 实现原理
这里暂时只分析linux下的原理
- select
- 单个进程能够监视的文件描述符的数量存在最大限制,通常是1024(#define __FD_SETSIZE)
- 内核 / 用户空间内存拷贝问题,select需要复制大量的句柄数据结构,产生巨大的开销
- select返回的是含有整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件
- poll
- 数组改成链表,没有了监视文件数量的限制,但其他问题仍然存在
- epoll
2.1.2.2. 基本概念
- selector 监听IO就绪状态,实现多路复用
- buffer 高性能缓冲区
- channel 对IO连接的封装
2.1.3. 代理
- 静态代理
- 动态代理,要求实现类继承接口
- 遍历接口列表,不会大于65535
- 生成字节码文件,可选择是否写磁盘
- ClassLoader加载类
- Constructor创建实例,实际会有缓存,保证单例
- InvocationHandler.invoke
- Cglib,子类代理,不能代理final、private
2.1.4. 注解
- 注解的作用
注解也叫元数据,它主要的作用有以下四方面:
生成文档,通过代码里标识的元数据生成javadoc文档。
编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。
- @Target
表示该注解可以用于什么地方,可能的ElementType参数有:
CONSTRUCTOR:构造器的声明
FIELD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类、接口(包括注解类型)或enum声明
- @Retention
表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括:
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被VM丢弃
RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。
- @Document
将注解包含在Javadoc中
- @Inherited
允许子类继承父类中的注解
- 注解处理器就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定的处理
2.2. 集合
2.2.1. HashMap
- 使用数组加链表的结构实现
- 插入
- 获取要插入的key的hash
- 与当前length求模(例如:hash&63)
- 上一步的计算结果作为数组的index
- 生成链表,保存到对应的index
- 如果发生碰撞,作为当前value的next
- 1.8优化:如果链表长度超过8,转换为红黑树
- 扩容
- 当使用量超过75%(loadfactor,可设置),执行扩容
- 1.8优化:前一位为0时不做处理
2.3. 数据结构&算法
2.3.1. hash算法
- 直接寻址法
取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a?key + b,其中a和b为常数(这种散列函数叫做自身函数)
- 数字分析法
分析一组数据,比如一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体相 同,这样的话,出现冲突的几率就会很大,但是我们发现年月日的后几位表示月份和具体日期的数字差别很大,如果用后面的数字来构成散列地址,则冲突的几率会 明显降低。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。
- 平方取中法
取关键字平方后的中间几位作为散列地址。
- 折叠法
将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。
- 随机数法
选择一随机函数,取关键字的随机值作为散列地址,通常用于关键字长度不同的场合。
- 除留余数法
取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。
2.4. 线程
2.5. 锁
2.6. JVM
2.6.1. 运行时数据区
2.6.1.1. PC寄存器
2.6.1.2. 虚拟机线程栈
- 结构图
每个栈空间的默认大小为0.5M,在1.7里调整为1M,每调用一次方法就会压入一个栈帧,如果压入的栈帧深度过大,即方法调用层次过深,就会抛出StackOverFlow,,SOF最常见的场景就是递归中,当递归没办法退出时,就会抛此异常,Hotspot提供了参数设置改区域的大小,使用-Xss:xxK,就可以修改默认大小。
- 局部变量表
- 操作数栈
- 动态链接
2.6.1.3. 本地方法栈
2.6.1.4. 堆
2.6.1.5. 方法区(永久代)
2.6.2. 执行子系统
2.6.3. GC算法
2.6.3.1. 分类
- 标记清除
- 复制
- 标记整理
- 标记待回收对象
- 将存活对象向一端整理
- 删除所有已死亡对象
- 分代
2.6.3.2. GC算法案例
2.6.4. 性能优化
2.6.5. 踩坑记录
- ParallelCMSThreads > ParallelGCThreads 会引起此崩溃
- 线程池使用不当造成队列拥堵,引发内存溢出,dump排查
3. 核心
3.1. nginx
3.2. tomcat
3.3. mysql
3.4. redis
3.5. mongo
3.6. rabbitMq
4. 框架
4.1. spring mvc
- 运行原理
1、用户发送请求至前端控制器DispatcherServlet
2、根据Request信息,匹配handler
3、HandlerAdapter#handle 匹配session 入参 等
4、invokeHandlerMethod
5、Controller执行完成返回ModelAndView。
6、ViewReslover解析后返回具体View。
7、渲染数据,返回响应
4.2. spring
4.2.1. 骨骼架构
- bean是spring操作的核心元素,是对spring管理的Object的包装,spring可以理解为面向bean的编程
- context是IoC容器,为bean提供了生存环境
- core实现了对bean的核心操作能力
4.2.2. Ioc
4.2.3. AOP
- 原理
利用JDK Proxy 或者Cglib,在创建代理对象时织入代码
- 织入方式分类
- 编译期织入 aspectj ajc编译
- 类加载织入 agent 替换classloader
- 运行期织入 JDK Proxy Cglib
4.2.4. spring 事务
4.2.4.1. 事务隔离级别
4.2.4.2. 事务传播属性
4.2.4.3. MVCC
4.2.5. Spring生命周期
- 初始化对象
- 注入依赖
- 执行扩展点
- initializeBean
- ApplicationContextAware
- BeanPostProcessor
- BeanNameAware
4.3. mybatis
4.4. shiro
4.5. spring boot
5. 分布式技术
5.1. Dubbo
![](_paste_img/面试/2018-03-10-08-51-18.png)
> ```
>dubbo整个框架共分10个层
>第三层 proxy、第六层Monitor是两个分界线
>三层之前,1、2层的Service和Config是直接面向用户的,用户通过注解、XML等配置服务、服务依赖、配置信息等
>三层Proxy对用户的配置进行必要的包装
>三层到六层之间,4、5层是服务化的总控,通过4层注册中心、实现整个服务化系统的互通,5层Cluster的特点是以消费端为主
>六层Monitor主要做一些信息的收集工作
>六层以下是服务调用的落地部分,包括协议、信息交换、数据传输、序列化等
> ```
5.2. zookeeper
- zookeeper原理
ZooKeeper是一种为分布式应用所设计的高可用、高性能且一致的开源协调服务,它提供了一项基本服务:分布式锁服务。由于ZooKeeper的开源特性,后来我们的开发者在分布式锁的基础上,摸索了出了其他的使用方法:配置维护、组服务、分布式消息队列、分布式通知/协调等。
ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的。
- znode结构
ZooKeeper命名空间中的Znode,兼具文件和目录两种特点。既像文件一样维护着数据、元信息、ACL、时间戳等数据结构,又像目录一样可以作为路径标识的一部分。图中的每个节点称为一个Znode。 每个Znode由3部分组成:
① stat:此为状态信息, 描述该Znode的版本, 权限等信息
② data:与该Znode关联的数据
③ children:该Znode下的子节点
znode创建类型(CreateMode),有以下四种:
PERSISTENT 持久化节点
PERSISTENT_SEQUENTIAL 顺序自动编号持久化节点,这种节点会根据当前已存在的节点数自动加 1
EPHEMERAL 临时节点, 客户端session超时这类节点就会被自动删除
EPHEMERAL_SEQUENTIAL 临时自动编号节点
- 分布式锁获取过程
客户端调用create()方法创建名为“locknode/guid-lock-”的节点,需要注意的是,这里节点的创建类型需要设置为EPHEMERAL_SEQUENTIAL。
客户端调用getChildren(“locknode”)方法来获取所有已经创建的子节点,同时在这个节点上注册上子节点变更通知的Watcher。
客户端获取到所有子节点path之后,如果发现自己在步骤1中创建的节点是所有节点中序号最小的,那么就认为这个客户端获得了锁。
如果在步骤3中发现自己并非是所有子节点中最小的,说明自己还没有获取到锁,就开始等待,直到下次子节点变更通知的时候,再进行子节点的获取,判断是否获取锁。
6. 理论
6.1. 面向对象
6.1.1. 封装
6.1.2. 继承
6.1.3. 多态
6.2. 设计模式
6.2.1. 创建型
6.2.2. 结构型
6.2.3. 行为型
6.3. 服务化
6.3.1. 服务拆分
6.3.2. 服务治理
7. 协议&规范
7.1. http协议
7.1.1. cookie
7.1.2. session
7.1.3. status code