面试笔记
跨域问题
因为同源策略, 当客户端和服务端不再同一域下时, 要解决请求的跨域问题
一般有两种方法 1) JSONP 2) CORS
JSONP仅限于GET请求,有一定的局限性
CORS可以满足多种方法的请求, 需要做的是对response的响应头改写, 处理方式可以用Filter过滤指定范围的请求
简单请求和非简单请求
CORS请求分为简单请求和非简单请求
简单请求要满足以下条件
- 请求方法在这三个以内: HEAD GET POST
- 头部不超过以下几种字段:
Accept
、Accept-Language
、Content-Language
、Last-Event-ID
、Content-Type
(只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)
非简单请求时指对服务器有特殊要求的请求
比如PUT DELETE方法, Content-Type是application/json的请求
非简单请求会先发送一个预检请求, 用OPTION方法.
RPC是什么
Remote Procedure Call 远程过程调用 : 一个计算机通讯协议, 可以实现像调用本地服务一样调用远程服务, 并且让网络通讯过程透明. 一般使用IDL接口定义语言, 方便跨平台远程过程调用.
如阿里巴巴的hsf、dubbo(开源)、Facebook的thrift(开源)、Google grpc(开源)、Twitter的finagle(开源)等都是基于RPC的框架.
RPC做到让中间的网络通讯过程透明化, 一般选择动态代理的方式实现.
- 确定消息数据结构, 对消息进行序列化
- 进行网络通讯, 一般要支持BIO和NIO两种方式, 可以1) 自己开发JAVA NIO方式 2) 基于MINA 3) 基于Netty
- 消息里面有requestID是因为解决多条线程异步请求服务时, 回调能保证给正确的线程.
序列化
序列化是将数据结构或者对象转化成二进制串, 也就是编码的过程.
反序列化是将二进制串转换成数据结构或者对象的过程.
序列化是为了 进行网络传输
反序列化是为了 后续对其处理
Netty
Netty是一款基于NIO开发的网络通信框架, 对比于BIO, 他的并发性能得到很大提高.
很多RPC框架是基于Netty这一IO通信框架, 比如阿里的HSF, Dubbo, Twitter的finagle等.
RPC和HTTP的区别
RPC是基于TCP/IP协议的 , HTTP是基于HTTP协议的 , 传输效率RPC效率更高一些 .
代理模式
结构性模式,不是创建型模式
我们创建具有现有对象的对象, 并向外界提供功能接口. 以解决直接访问对象时带来的问题, 比如访问情景多样化, 直接访问会给使用者或者系统结构带来很多麻烦, 所以在访问此对象时, 加上一个对此对象的访问层.
代理模式是指 一个公共接口,一个实现类,一个代理类,代理类持有实现类实例,代理执行实例方法。 执行过程中不直接访问实体对象,而是通过代理对象访问。
代理过程中可以加上一些其他的用途。Spring的AOP面向切面编程是基于动态代理, 切入的点就是一个个被代理的类.
静态代理
代理类和实体类已经确定, 在编译之前已经完成.
动态代理
在程序执行过程中创建代理类是动态代理. 可以统一的管理代理类.
java.lang.reflect包下的Proxy类用来动态创建一个代理对象的类
并且需要实现InvocationHandler这个接口,让每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用
- 定义接口
- 定义实现类
- 实现InvocationHandler接口, 可以在invoke方法中加入预处理和后处理
- Proxy.newProxyInstance创建对应的代理对象
什么是RESTful
RESTful是一种架构风格, REST意思是表示层状态转化(Representation state transfer)
REST的特点是
- 面向资源 一般使用json或者xml的形式
- URI 唯一定位标识符 至少有一个URI定位到资源
- 统一接口 用HTTP的方法表示CRUD操作
- 无状态 可以直接定位, 和其他资源没有前置关系
依赖注入
异步同步
同步
程序同步执行 , 当代码A执行完之后再执行B , 如果A没有执行完 , B要等待 .
异步
程序异步执行 , 当代码A执行中 , B不需要等待A执行完再执行 , 可以进入就绪状态准备执行 .
回调函数
在A代码片段中 , 会执行B , 当B执行完 , B会执行A的callback函数 . 这是一种机制 . 可以将A和B抽象成接口 , 易于扩展 .
Spring 核心功能
Spring core
核心功能 , 核心容器提供IoC
Spring AOP
面向切面编程
Spring web
提供了针对web开发的特性
Spring Dao
集成了JDBC , 简化了DAO的开发步骤
Spring ORM
整合了第三方持久层框架
Spring MVC
提供了web的MVC实现
响应式编程
根据数据流和变化做出响应 , 通过异步和回调的方式 .
如何在上下文中获取bean
- ContextLoader
- new FileSystemXmlApplicationContext("applicationContext.xml");
- WebApplicationContextUtils
TCP和UDP的区别
TCP需要建立连接,UDP不需要建立连接 TCP的数据是可靠的,UDP不可靠 TCP的采用流的形式,UDP是报文的形式
对比Vector、ArrayList、LinkedList有何区别?
Vector和ArrayList都是数组形式的集合,Vector是线程安全的,ArrayList不是. ArrayList读取比较快,增删比较慢, LinkedLIst不是线程安全的,是链表形式的,他的增删比较快,但是读取慢 ArrayList初始容量是10,当有数组添加时才真正的分配容量 每次都是通过copyOf的方式扩容到之前的1.5倍
关于索引
索引的数据结构是:B+树 B-树 散列表 索引是放在内存中的,可以实现快速查询,但是会降低更新表的速度。 索引不走like,但是‘xx%’会走 索引列不能有null值
SQL优化
尽量在经常用的where和order by上建索引 尽量不要用in not in ,会扫描全表 尽量少用or ,会放弃索引
SOA
面向服务的架构 , 松耦合 位置透明 可在异构平台复用 便于测试
dubbo和Spring cloud
Dubbo是一个开源的SOA治理方案,是一个分布式服务框架。 注册中心严重依赖第三方zookeeper或者redis,组件出现问题,服务会中断 Dubbo只支持RPC调用 SpringCloud有自己的注册组件Eureka 支持RESTfulAPI 消息组建是Stream 集成了MQ和Apache kafka
ThreadLocal
线程本地副本 每个线程都会有一个副本,ThreadLocal创建的副本是存在线程的ThreadLocals里面 应用在数据库连接 session管理方面 解决了线程安全问题 线程可以随时访问 适用set/get方法。
Serializable序列化
java支持序列化机制,将一个对象表示为一个字节序列
callable和runable的区别
callable的方法是call(),runnable的方法是run() Callable执行方法有返回值 Runnable的执行方法没有返回值 Callable返回一个Future对象,可以通过get获取结果
volatile关键字
具有可见性,就是被修饰的变量,一旦被其他线程修改,会立即同步给主存,让其他线程知道 没有原子性 因为被修饰的变量可以被多线程修改
线程池
频繁的创建和销毁线程会降低工作效率 提高线程利用率 常用参数 corePoolSize(线程池大小) maximumPoolSize(最大线程数) keepAliveTime(可空闲时间) 执行顺序 1. 当前线程小于核心线程数,创建线程 2. 当前线程大于核心线程数,进入任务队列 3. 任务队列满了,核心线程数小于最大线程数,创建线程 4. 抛出异常
Integer的缓存范围
-127~128
synchronized和锁(ReentrantLock) 区别
synchronized最慢 synchronized和lock是实现同步锁(原子性)的两种方式 Lock提供了更广泛,更优雅的方式. synchronized在执行完后会自动释放,lock要手动释放 synchronized是jvm里面的,是java的关键字,lock是一个类 synchronized会让等待的线程一直等待,lock会尝试获得锁
如何保证集合是线程安全的
ConrurentHashMap做了什么 线程安全:Vector HashTable StringBuffer 线程不安全:ArrayList LinkedList HashMap HashSet TreeMap TreeSet StringBuilder Collections.synchronizedMap()可以使集合线程安全 ConrurentHashMap是线程安全的HashMap
对比HashTable HashMap TreeMap
谈谈你对HashMap的掌握 HashMap不是线程安全的,以数组方式存储Key-value构成的Entry对象,无限量扩容,扩容时要重新计算Hash
理解java的字符串
String StringBuffer StringBuider有什么区别 String 是不可变的,不能被继承和修改,用final修饰的类,线程安全. StringBuffer可以被改变,但是线程不安全. StringBuilder也是可变的,线程安全.
什么情况下java程序会产生死锁
如何排除 线程T1和T2,T1获得L1,但是要获得L2后才能释放L1,T2获得L2,但是要获得L1以后才能释放L2,这样有可能会出现死锁,避免方式是加synchronized同步锁.
JVM运行模块
程序计数器(相当于指针 不共享) 虚拟机栈 (运行时的数据,方法 不共享) 方法区 (常量,类信息,变异后的代码 线程共享) 堆 (创建的对象 线程共享) 本地方法栈 (本地方法运行时的数据 不共享)
Spring用到了那些设计模式
简单工厂模式
BeanFactory根据标识创建bean的过程
单例模式
singleton作用域创建的bean , SpringIoC容器中只有一个对应的实例 .
代理模式
SpringAOP基于JDK的动态代理
适配器模式
观察者模式
ApplicationListener的实现 . 定义一种一对多的关系 , 当一个对象状态发生改变时 , 其他的对象也对应发生改变 .
策略模式
SpringBoot
不是一个框架,而是快速构建项目的方式 默认的代码和注释配置 以最少的配置或者零配置开发和构建 适用新项目,不适合将SpringFramework的项目转化 SpringBoot约定过配置,不需要声明资源映射,资源映射会自动处理。
Spring线程安全
单例模式不一定线程安全,涉及多线程时要对其改造,一般是加锁或者适用threadlocal。
ZooKeeper
在分布式系统中 协调各个节点 监视各个节点的状态 根据节点提交的反馈进行下一步的合理操作
提供了文件系统 通知机制
根据是否持久化 / 是否有编号 分为四种znode节点 .
通知机制 是watch关心的节点 当发生变化时 , 通知客户端 .
命名服务
唯一的path 可以通过path相互发现
配置管理
管理配置 , 将配置信息放到zk的节点上去 并监听对应的节点 当有配置发生变化时可以通知应用程序 .
集群管理
有新的节点加入或退出 选举master
分布式锁
可以把zk的节点当做一把锁 , 所有程序都去创建这个节点 , 成功的即得到锁 , 用完删除即可释放锁 .
其他未得到锁的程序可以排序创建节点 , 等锁释放了 , 按照顺序得到锁 .
Spring bean的作用域和生命周期
singleton
单例作用域下 scope = singleton , 表示一个bean 在Spring IoC 容器中只有一个实例 .
prototype
prototype作用域中 , 每一次请求都会创建一个实例 , 并配置和装饰 , 但不会调用对象的生命周期回调函数 , 不会负责bean的生命周期 .
request / session
在每一次的HTTP 的request / session中创建实例 , 并且尽在request / session中有效 .
谈谈java反射机制, 动态代理是基于什么原理
java的反射机制可以获得对象的类 , 以及属性 , 方法 , 和构造函数 .
动态代理基于反射机制 . IoC的依赖注入也是基于反射机制 .
抽象类和接口的区别是什么
抽象类通过extends继承 , 接口是通过implements实现接口 .
抽象类可以有构造器 , 接口没有构造器 .
抽象类和接口都不能实例化
接口中的方法只能是public的 , 但抽象方法没有限制
只能继承一个抽象类 , 可以实现多个接口
事务的四个特性
原子性
事务要完整 , 要么全部做完 , 要么没有做
一致性
事务开始到结束 , 数据库的完整约束没有变 .
隔离性
事务在访问数据库时 , 不被干扰 , 相互隔离 .
持久性
事务完成后 , 数据库不能回滚 .
MySql支持的隔离级别
读未提交 read-uncommited
读已提交 read-commited
可重复度 repeateable - read
串行化 serializable
脏读
不可重复读
幻读
悲观锁和乐观锁的原理和应用场景
谈谈你对几种常见排序算法的理解
你解决过的最大并发是多少 你采用了那些方法 获得了什么成效
使用缓存技术 / 查询语句的优化 / 优化表结构加索引 / 集群的方式
进程和线程的区别
Spring的异常处理 如何返回错误信息
- 可以通过web.xml中的error-page来配置错误状态码 / 异常的跳转页面
- 实现HandlerExceptionResolver接口 , Spring提供了默认的实现类SimpleMappingExceptionResolver , 要在配置文件中配置 , 实现resolveException方法 , 返回一个ViewandModel
- 在类中实现 , 用@ExceptionHandler
Nigix的理解
基于C开发 / 跨平台 / 可以作为HTTP服务器作为网站的发布处理 / 作为反向代理服务器实现负载均衡
表分区
将一个数据表和索引分别存储在不同的物理文件中
-- 增加 partition by range(id){ partition user_1 values less than (10), partition user_2 values less than (20) } --删除 alter table user drop partition user_1 ; alter talbe user drop partition user_2;
分区的表不支持外键 , 可能会让索引失灵 .
JDBC操作数据库步骤
- 加载驱动 Class.forName()
- 获得连接 DriverManager.getConnection()
- 创建statement / preparestatement对象 conn.createStatement
- 执行SQL获得结果 stmt.executeQuery()
Dubbo
SpringCloud
ActiveMQ
集合基础操作
map.get(key);
map.put(key, value);
list.get(location);
list.add(object);
boolean flag = set.add(object);
dataType[] array = new dataType[size]
类加载过程
加载 - 连接(验证 - 准备 - 解析) - 初始化 - 使用 - 卸载
加载
将class加载到jvm的方法区中
连接
验证 检验加载类是否有问题
准备 将静态变量分配内存
解析 将符号转化成直接引用
初始化
执行Static静态的代码块 - 执行构造函数 (从父类开始)
BootstrapClassLoader jre/lib/rt下的
ExtensionClassLoader jre/lib/ext下的
AppClassLoader classpath下的
CustomClassLoader 自定义的