文章目录
笔试
设计模式
排序算法
冒泡排序
选择排序
插入排序
希尔排序
快速排序
归并排序
堆排序
二分法排序
大小根堆
栈,堆,队列
递归输出斐波那契数列
递归实现阶乘
递归输出单链表
数组中是否有重复元素
字符串中重复元素的个数
字符串中不重复子串中的最大长度
面试
Java 基础
java8新特性
数据库
MySql
Mongo
Mongo和Mysql的区别
Linux
Docker
Jenkins
Git
框架
Spring
Spring MVC
Spring Boot
Spring Cloud
MyBatis
Redis
RabbitMQ
Maven
定时任务
Nginx
并发处理办法
缓存穿透,击穿,雪崩
分布式锁
分布式Session
分库,分表
事务
一致性HASH
CAP
BASE理论
线程
线程池
线程并发
微服务
其他
笔试
window64和32位的差异:是cpu运算方式的差异
32位,4G内存的效用,假如安装了大于内存为4G的应用,那么大于4G的部分不能很好的应用
有,家庭版16G,专业和旗舰版192G
遍历ArrayList遇到的坑 只遍历没有问题 forEach(String id,List)形式:边遍历,编修改会抛出异常。因为这种形式是通过Iterator来访问的,修改的时候,ArrayList会调用remove(),进而调用fastRemove():modCount+1,每次forEach的时候,都会调用checkForComodification,校验modConunt与ExpectedModCount不一致,会抛出异常 for:边遍历边修改无异常,但是结果有错,因为它不经过迭代器,直接访问ArrayList,不会引入fail-fast机制, 综上,使用集合类对象的时候,需要考虑fail-fast因素 当使用Iterator进行遍历的时候,里面的remove()方法会重置expectedModCount,重置动机:保证多个迭代器同时遍历时的数据一致
数据结构里的散列表高速索引机制 长度为n的线性表,存放无序数据,平均查找时间为n/2 hash函数,即散列函数,关联数据和存储位置,hashMap来源于散列表
散列表里解决冲突的方法:hash值可能相同,HashMap里面用到了”链地址法“,即链表里存放冲突数据
在HashMap里存储不带HashCode和equals对象(自定义的对象)时:会调用Object里的hashCode(返回对象的地址)和equals(根据地址进行判断) 此时拿不到具体数据 重写hashCode ,不重写equals,同样拿不到数据 重写equals方法和散列表里的冲突有关 重写规则:根据类的唯一主键来判断hashCode,是否一致,两对象是否该equals 如介绍项目时,可以说用到了HashMap,其中的键时自定义模块 当使用ArrayList对象时,频繁的查找其中的数据成为性能瓶颈,候用HashMap对象重构
短路现象: && :左边为false,右边不会执行,结果为false || : 左边为true,右边不会执行,结果为true 注意:尽量别在条件判断里进行运算 条件判断的语句不要太复杂,可嵌套改写 注意起始条件和退出条件,测试案例中覆盖边界值 技巧:重构代码时,或代码重审时,会着重检查短路现象,或避免条件分支太复杂 编写测试案例时,着重看下边界条件有没有覆盖
设计模式
设计模式的根本原因是提高项目的可维护性
注意设计模式后蕴含的思想,如开闭原则
设计模式不仅能给出具体解决方案,还能提供优化系统架构思路,所以在项目里,一般不会只用某个而会根据一些原则来优化代码,如解耦合和面向接口编程
不是为了好看才用的设计模式,而是为了解决特定类型的实际问题,从此意义上讲,更关心模式背后包含的原则思想。
设计模式背后包含的设计原则 1,依赖倒转原则:模块或类间的依赖关系,如相互调用,是通过interface和abstract类发生,实现类之间不发生或尽量少发生依赖关系。减少修改所影响的范围。即interface或abstract类不依赖于实现类,相反依赖于interface或abstract 2,单一职责:能让类更稳定,每个类或模块应该只具有单一职责,即只实现一种功能,多的进行拆分 3,里氏替换原则:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法,子类要扩展功能,可以增加自己特有的方法 违背该原则的后果:同一方法在3层里有不同的实现,维护困难,增加多态调用时的复杂度 4,通过合成复用原则优化继承的使用场景 合成服用原则的核心:优先使用组合和聚合,只有当父子类之间存在逻辑上的从属关系时,才考虑extends 聚合:表示整体和部分的弱关系,组合表示强关联关系 技巧: a.在项目里,定义类之间的关系时,会遵循合成复用原则,只有具有从属关系的类之间采用继承,否则会使用聚合或组合,这样类之间耦合度低,如果修改其中一个类,不会影响其他类 b.在……模块,专门讨论了编码规范,其中包含……原则,然后展开…… c.在详细设计阶段,会根据合成复用原则定义父子类之间的关系,或使用……原则,达到……效果
代理模式
降低了业务使用和业务提供者的耦合度,如处于数据安全的考虑,无法直接调用某服务,可用代理模式 比如在项目里把一些机密数据放在了secret的机器上,同时该机器上启动一个起到安全代理的服务类,该代理类会检查发起请求的模块是否有访问权限,如参数是否正确,通过这个代理,能有效保护数据。
图示 客户 ----------------------------------->对象 客户—————代理—————>对象 抽象对象角色:声明了目标对象和代理对象的共同接口,这样就可以在任何可以使用目标对象的地方使用代理对象
public abstract claa AbstractObject{
public abstract void operation ( ) ;
}
目标对象角色:定义了代理对象可代表的目标对象
public class RealObject extends AbstractObject {
@Override
operation ( ) ~ ;
}
代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象,代理对象提供一个与目标对象相同的接口,以便在任何时候替代目标对象,代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯的将调用传递给目标对象
public class ProxyObject extends AbstractObject {
private RealObject realObject = new RealObject ( ) ;
@Override
public void operation ( ) {
realObject. operation ( ) ;
}
}
测试:代理对象是对象的结构模式
ProxyObject proxyObject = new ProxyObject ( ) ;
proxyObject. operation ( ) ;
单例模式
说明:确保实例化对象只有一个,所以要构造函数私有,通过静态方法向外提供对象 改进1,多线程时也要保证一个对象,所以在同一时间段内只有一个线程调用,其他线程排队等待进入synchronized代码块 改进2,不应等待,双重检查,对象存在时不等待
public class Singleton {
private final static Singleton instance = new Singleton ( ) ;
private Singleton ( ) { }
public static Singleton getInstance ( ) {
return instance ( ) ;
}
}
public class Singleton {
private static Singleton instance;
private Singleton ( ) { }
public static synchronized Singleton getInstance ( ) {
if ( instance == null) {
instance = new Singleton ( ) ;
}
return instance;
}
}
public class Singleton {
private volatile static Singleton singleton;
private Singleton ( ) { }
public static Singleton getSingleton ( ) {
if ( singleton == null) {
synchronized ( Singleton. class ) {
if ( singleton == null) {
singleton = new Singleton ( ) ;
}
}
}
return singleton;
}
}
策略模式
行为模式 游客旅游举例说明
排序算法
内部排序:数据在内存中进行排序 外部排序:数据很大的时候,一次不能容纳所有记录,在排序的过程中需要访问外存,大文件的排序 内部排序的有,冒泡,选择,插入,希尔,快速,归并 稳定的有,冒泡,插入,归并
冒泡排序
说明:通过每一次的排序获取最大值或最小值,放在头部或者尾部,后除去排好的数据,继续排序
For ( int i = 0 ; i< a. length; i++ ) {
For ( int j = 0 ; i< a. length- i- 1 ; i++ ) {
if ( a[ j] > a[ j+ 1 ] ) {
t = a[ j] a[ j] = a[ j+ 1 ] a[ j+ 1 ] = t;
}
}
}
平均:O ( n²) 最好:O ( n) 最坏:O ( n²) 空间复杂度:O ( 1 )
选择排序
说明: 将第一个看成最小值,与后续进行比较,找出最小值和下标,与起始值进行交换
For ( i= 0 ; i< a. length; i++ ) {
Min = a[ i] ; Index = I;
For ( j = i+ 1 ;j< a. length; j++ ) {
If ( min> a[ j] ) {
Min = a[ j] ;
Index = j;
}
}
T = a[ i] a[ i] = min ; a[ index] = t
}
平均:O ( n²) 最好:O ( n²) 最坏:O ( n²) 空间复杂度:O ( 1 )
插入排序
说明:从第二个数据进行比较,如果2比1小,则交换,再用第三个数据比较,如果比前面的小,则交换,否则,退出循环
For ( i= 1 ; i< a. length; i++ ) {
For ( j = i; j> 0 ; j-- ) {
if ( a[ j] < a[ j- 1 ] ) {
T = a[ j] ; a[ j] = a[ j- 1 ] ; a[ j- 1 ] = t;
} else {
break ;
}
}
}
平均:O ( n²) 最好:O ( n) 最坏:O ( n²) 空间复杂度:O ( 1 )
希尔排序
说明:与插入排序相同,不同的是,每次循环的步长不同,通过减半来实现
For ( i= a. length/ 2 ; i> 0 ; i= i/ 2 ) {
For ( j = i ; j< a. length; j++ ) {
For ( k = j; k> 0 && k- i> 0 ; k= k- i) {
If ( a[ k] < a[ k- i] ) {
t = a[ k- i] ; a[ k- i] = a[ k] ; a[ k] = t;
} else {
Break;
}
}
}
}
平均:O ( N1. 3 ) 最好:O ( n) 最坏:O ( n²) 空间复杂度:O ( 1 )
快速排序
说明:冒泡排序的改进,选择一个基准数,分成左右两个部分,>=位于右侧,<=位于左侧,左侧又选择一个分界值,同上划分,右侧同理,左右两个排好序后,整个数组也排好序了 temp i——> <——j j选中小于temp的,存入a[i]中,移动i i移动同理,直到i,j相遇,然后将temp值存入a[i]中
public class QuickSort {
public static void main ( String[ ] args) {
int [ ] num = new int [ ] { 6 , 1 , 2 , 7 , 9 , 3 , 4 , 5 , 10 , 8 } ;
for ( int a: quickSort ( num, 0 , num. length- 1 ) ) {
System. out. print ( a+ " " ) ;
}
}
public static int [ ] quickSort ( int [ ] num, int leftPos, int rightPos) {
if ( rightPos < leftPos)
return num;
else {
int initLeftPos = leftPos;
int initRightPos = rightPos;
int baseNum = num[ leftPos] ;
while ( rightPos > leftPos) {
while ( num[ rightPos] >= baseNum & rightPos > leftPos) {
rightPos-- ;
}
while ( num[ leftPos] <= baseNum & rightPos > leftPos) {
leftPos++ ;
}
if ( rightPos > leftPos)
swap ( num, leftPos, rightPos) ;
}
swap ( num, leftPos, initLeftPos) ;
quickSort ( num, initLeftPos, leftPos- 1 ) ;
quickSort ( num, rightPos+ 1 , initRightPos) ;
return num;
}
}
public static void swap ( int [ ] num, int leftPos, int rightPos) {
int temp = num[ leftPos] ;
num[ leftPos] = num[ rightPos] ;
num[ rightPos] = temp;
}
}
平均:O ( nlog2n) 最好:O ( nlog2n) 最坏:O ( n²) 空间复杂度:O ( nlog2n)
O ( nlog2n)
归并排序
平均:O ( nlog2n) 最好:O ( nlog2n) 最坏:O ( nlog2n) 空间复杂度:O ( n)
堆排序
平均:O ( nlog2n) 最好:O ( nlog2n) 最坏:O ( nlog2n) 空间复杂度:O ( 1 )
时间复杂度如何计算
找到执行次数最多的语句,通常为循环体,加法常数用1代替
执行语句的数量级,忽略系数
用O表示
二分法排序
说明:在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们 中间的那个元素比,如果小,则对前半再进行折半,否则对后半 进行折半,直到left>right,然后再把第i个元素前1位与目标位置之间 的所有元素后移,再把第i个元素放在目标位置上。 二分法排序最重要的一个步骤就是查找要插入元素的位置,也就是要在哪一个位置上放我们要准备排序的这个元素。 当我们查找到位置以后就很好说了,和插入排序一样,将这个位置以后的所有元素都向后移动一位。这样就实现了二分法排序。 然后是怎么查找着一个位置呢,就是不断的比较已排序的序列中的中间元素和要排序元素,如果大于的话,说明这个要排 序的元素在已排序序列中点之前的序列。
public static void DichotomySort ( int [ ] array)
{
for ( int i = 0 ; i < array. Length; i++ )
{
int start, end, mid;
start = 0 ;
end = i - 1 ;
mid = 0 ;
int temp = array[ i] ;
while ( start <= end)
{
mid = ( start + end) / 2 ;
if ( array[ mid] > temp)
{
end = mid - 1 ;
}
else
{
start = mid + 1 ;
}
}
for ( int j = i - 1 ; j > end; j-- )
{
array[ j + 1 ] = array[ j] ;
}
array[ end + 1 ] = temp;
}
}
大小根堆
A[0]
B[1]-------------C[2]
A>=BC:大根堆 升排序
A<=BC:小根堆 降排序
如,一组数字,5,11,7,2,3,17 首先建立一棵完全二叉树,从左到右,左右节点都填上,再根据上述规则,进行大小根堆排序 5 11 -------------7 2-------3 ------- —17
栈,堆,队列
堆 :是一棵完全二叉树,大根堆,小根堆,顺序随意 在程序运行时非编译时,申请某个大小的内存空间,即动态分配内存
栈 :一种受限的线性表,又名堆栈,后进先出 受限是指在top端进行插入和删除操作,编译的时候,为线程或进程建立存储区域,push,pop操作
区别 栈的空间分配 是OS自动分配,存储函数参数值,局部变量 缓存方式 :一级缓存,调用完立即释放 数据结构 :先进后出 堆:空间分配 由程序员分配,若不释放,结束时由OS回收,分配方式类似于链表 缓存方式 :二级缓存,生命周期由JVM垃圾回收来决定 数据结构 :一棵树
队列 线性表,前出后进,先进先出,队尾进,队头出
递归输出斐波那契数列
int f ( int n)
{
if ( n== 1 || n== 2 ) return 1 ;
else return f ( n- 1 ) + f ( n- 2 ) ;
}
递归实现阶乘
public static int factorial ( int n) {
if ( n == 1 ) {
return 1 ;
}
else {
return n* factorial ( n- 1 ) ;
}
}
递归输出单链表
从尾到头打印链表每个节点的值。
首先定义一个节点类
class ListNode {
int val;
ListNode next = null;
ListNode ( int val) {
this . val = val;
}
}
利用递归返回类似栈的形式,实现递归算法
public ArrayList< Integer> printListFromTailToHead ( ListNode listNode) {
ArrayList< Integer> arrayList= new ArrayList < Integer> ( ) ;
if ( listNode!= null) {
this . printListFromTailToHead ( listNode. next) ;
arrayList. add ( listNode. val) ;
}
return arrayList;
}
数组中是否有重复元素
将数组中的元素放入set中,看set的最终结果的长度是否等于数组的大小
字符串中重复元素的个数
先用split()方法将字符串分割,存入数组中
数组循环放入map中,key为字符,value为个数
字符串中不重复子串中的最大长度
todo
面试
Java 基础
Java创建对象的方式 : (1)new 语句 (2)反射手段,调用java.lang.Class或者Java.lang.reflect.Constructor类的newInstance() (3)调用对象的clone() (4)反序列化手段 说明:1.2显示的调用构造函数,3.对内存上已有对象的影印,4.从文件中还原类的对象
Md5 :单向散列函数的加密算法
&& 短路运算,& 按位与
this :指这个对象,当前对象,表示类的成员变量而非函数参数,this不能用在static方法中,因为static无对象之说 a. 局部变量与成员变量重命名时 b.返回return this,或传递当前对象 c.构造器中调用其他构造器
java中的方法氛围静态方法和非静态方法
垃圾收集管理器 栈 :定义的基本数据类型的变量,对象的引用,函数调用的保存现场,堆heap :new和构造器创建的对象,是垃圾收集管理的主要区域 垃圾收集器采用分代收集算法,分为新生代和老生代,各个线程共享的内存区域:方法区,堆, 100,hello等和常量是放在常量池种的,常量池是方法区的一部分, 当栈用光的时候,会报StackOverflowError,当堆和常量空间不足的时候,会报OutofMemoryError错误 垃圾回收机制 : JVM用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间 方式 :手动System.gc(),自动 GC :垃圾收集,GC的功能可自动监测对象是否超过作用域,从而达到自动回收内存的目的 对象什么时候被回收 : 1,引用计数器法:给每个对象加一个,被引用一次+1,为0的时候回收 2,可达性分析法:向下搜索所走过的路径,称为引用链。当一个对象无任何引用链时,即这个对象不可达 综上,当这个对象对当前使用这个对象的应用程序变得不可触及时,这个对象就被回收了
J2SDK :是Sun公司开发的编程工具 java api :应用程序接口 JAR :java Archive Java归档文件 Unicode :是用16位来表示一个字的
2<<3:左移3位,相当于2的3次幂
Java类加载过程 包含加载,验证,准备,解析,初始化,使用【根据程序定义的行为执行】,卸载(由GC完成) 加载,连接(验证[文件格式,元数据,字节码,符号引用的验证],准备【为变量分配内存并设置类变量的初始化】,解析【将常量池内的符号引用替换成直接引用。主要包括四种类型引用的解析。类或接口的解析、字段解析、方法解析、接口方法解析。】),初始化 【初始化类的变量和其他资源,如static块,构造函数,父类初始化等】 通过一个类的全限定名来获取定义此类的二进制字节流。 将这个字节流所代表的静态存储结构转化为方法区域的运行时数据结构。 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区域数据的访问入口
java文件从编码完成到运行,包括编译,运行 编译:java文件通过javac命令,编译成字节码文件,即.class文件 运行:.class文件交给JVM运行 类加载过程即指JVM虚拟机把.class文件中类信息加载进内存,并运行解析生成class对象的过程,只加载一次 类加载器:类启动,扩展类,应用类,自定义 7. String类常用方法 equals() compareTo(unicode进行比较) indexOf() lastIndexOf() valueOf() 其他类型转字符串 concat() 追加字符串 contains() format() length() join() replace() spilt() replaceAll() trim() subString() matches() 8. 读取文件用到的类 File InputStream OutputStream FileInputStream FileOutputStream BufferedReader BufferedWriter File常用方法: exist() 文件路径是否存在 createFiles() delete() createDirectory() copy() move() size() read() writ() 9. Java类加载顺序 父类静态字段,父类静态代码块,子类静态字段,子类静态代码块,父类成员变量(非静态字段),父类非静态代码块,父类构造器,子类非静态代码块,子类构造器 10. 两个对象的hashcode相同,equals不一定为true 11. final 修饰的类不能被继承,修饰的方法不能被重写,修饰的变量必须实例化,不能被修改 12. Servlet的生命周期 :实例化,初始化init,接收,响应请求,销毁destroy 13. IO流 功能角度:输入流,输出流 类型角度:字节流,字符流 区别:字节流按照8位,以字节为单位输入输出数据 字符流按照16位,以字符位单位输入输出数据 14. java 集合容器 -----------------------------Collection --------List----------------------------Queue---------------------------Set Vector–ArrayList—LinkedList –PriorityQueue—HashSet—TreeSet Stack ----------------------------------------------------------LinkHashSet HashSet原理:底层实现是HashMap,值存放在hashMap的key上 15. 创建线程的方式 1,extends Thread 2,implements Runnable 3,通过Callable 和Future创建 16. 线程的五种状态 create,就绪,运行,阻塞,死亡 17. Java内存泄漏:让JVM误以为对象还在引用,无法回收了 可能导致内存泄漏的原因: 1,静态集合类HashMap,LinkedList…… 长生命周期的对象持有短声明周期对象的引用,尽管短声明周期的对象已经不再引用,但长生命周期的对象因持有它的引用而不能被回收 2,各种连接不关闭,如数据库,IO 3,变量不合理的作用域,如定义的作用范围>使用范围,还没有==null 4,内部类持有外部类,如一个外部类的实例对象的方法返回一个内部类的实例对象,而内部类的实例对象被长期引用,但外部类的对象不用了,此时外部因持有内部类不能被回收 5,改变哈希值,一个对象存入HeshSet后,不能更新对象中参与计算哈希值的字段,否则检索不到,也无法单独删除 18. JVM内存结构 -----------------------------JVM运行时内存划分 堆区---------------------------虚拟机栈 ---------------------本地方法栈 方法区---------------------------------------程序计数器 19. 异常 1,finally{} :放资源回收类代码 特性:不管发生异常,发生何种异常,就算try-catch语句里有return ,finally{}从句都会被执行 除非有System.exit(0)语句,才不会被执行 2,Exception:无需try-catch包含,一旦出现,程序终止,如除0,空指针异常 3,异常处理的准则: 在finally{}从句中释放资源 尽量缩小try语句的范围 先用专业的异常类来处理,益于定位,再用Exception类来兜底 在catch语句中尽可能详细的输出异常信息 处理机制:极可能缩小影响范围,平行业务间用不同的try-catch包起来
各种比较
==与equals的比较 == : 8种基本数据类型的比较用,比较值是否相等 引用数据类型中==比较的是引用的对象是否相等,即是否引用了同一对象 equals:介于两个对象间的比较,没用重写的情况下,equals与 == 在引用数据类型中比较的结果是一样的 当重写equals方法时,例如String,Integer,判断的是所存的值是否相等,String中equals方法重写成比较两个对象中对象的内容是否相等,而一般对象的equals方法判断两个对象是否属于同一个对象,如是String缓冲池内不存在与其指定值相同的String对象,那么JVM为其创建新的对象,并存放在缓冲池内 否则判断的是地址是否相等 instanceof:参数是否为正确的类型
String和string的区别 : String 是java中的一个类,而string是String类的一个对象
sleep和wait的区别 : 1,sleep是线程中的方法,wait是object的方法 2,sleep不会释放锁,wait会,且会进入等待队列 3,sleep不依赖于synchronized同步代码,wait需要 4,sleep不需要被唤醒,wait需要
JDK与JRE JDK:Java Development Kit java开发工具包 为java提供了开发和运行环境
String ,String Builder ,String Buffer的不同 3个区别在于,String 声明的是不可变的对象,每次操作都会生成新的对象,而后两者可以在原有对象的基础上进行操作 String Buffer是线程安全的,但String Builder性能高,所以在单线程的环境下推荐使用String Builder,多线程环境下推荐使用String Buffer,且使用String builder或String buffer的reverse()可使字符串反转
String s = “i”;与String s = new String(“i”);一样吗? 不一样,内存分配方式不一样,前者会分配到常量池中,后者会分配到堆内存中
普通类与抽象类的区别: 1,前者不含有抽象方法,可直接进行实例化 2,后者可含抽象方法,但不能被实例化,能够被继承,且必须继承抽象方法 3,有抽象方法的必然是抽象类,反之不然
接口与抽象类的却别 1,实现不同,implements,extends 2,接口没有构造函数,抽象类有 3,接口没有main(),抽象类里有并运行它 4,实现数量不同,类可实现多个接口(接口是对功能的封装,一个类允许有多种功能),但只能继承一个抽象类(若多继承,会导致方法逻辑混论,因为不重写equals,和hashCode,会调用Object类里的方法,导致混论,代码不易维护) 5,访问修饰符不同,接口中默认为public,抽象类中可以为任意
Collection 与Collections Collection:集合接口,提供了对集合对象进行基本操作的通用接口方法 Collections:集合类的工具类,帮助类,有一系列静态方法,如对元素的排序,搜索等
HashMap与HashTable的区别: 父类不同,但都实现了Map接口 •HashTable是线程安全的 •HashMap 中允许有一个key为null的键,HashTable key/value不允许null值。 •是否提供contains方法,HashMap中去掉了 •遍历用的Iterator内部实现不同 •Hash值不同,hashTable直接使用hashCode,而hashMap重新计算hash值 •初始化大小和扩容方式不同,table为11,map为16
何时用HashMap ,何时用TreeMap HashMap:在map中插入,删除,定位,链表散列,即数组和链表的结合体,jdk1.8后链表中超过8个后,链表会转换位红黑树来提高查询速度 先数组,后链表存储,数组的下标是:重新计算的hashcode值 TreeMap:有序key进行遍历
深拷贝和浅拷贝的区别: 浅:只是复制了对象的引用地址,两个对象指向同一内存地址,一个变另一个也会变 深:对象及其值复制过来,一个变另一个不会变
SOA与微服务的区别 SOA:大块业务逻辑,适用于任何类型的公司架构,着重中央管理,确保应用能交互操作 微服务:单独任务或小块业务逻辑,松耦合,适用于小型,专注于功能交叉团队,着重分散管理,目的:执行新功能,快速扩展开发团队
ArrayList 和LinkedList的区别 都实现了List和Collection接口 ArrayList底层实现是数组,实现了RandomAccess接口,随机查询速度快,增删元素慢 LinkList底层实现是链表,没有实现RandomAccess接口,增删速度快,查询速度慢 如一次性的通过add从集合尾部添加元素,后只读取一次,建议用ArrayList,如频繁添加,或在完成添加后频繁查找,建议用LinkedList 两者都不安全,Vector是线程安全的 ArrayList是扩容50%,Vector是100%,LinkedList是双向链表,无需扩容
重载,覆盖,重写 覆盖:两方法同名同参,子类覆盖父类 覆盖时两个准则:1,不能缩小父类的可见范围,违背面向对象里”父类定义通用的属性和方法原则“,2,不能抛出更宽泛的异常,因为父类定义的方法原型时外部类调用的规范,若修改,则会造成外部调用时无法处理抛出的异常 重载:同名不同参,能分离业务和业务实现细节,针对同类业务,同名的方法定义和实现(不同参数表示实现细节不同),提升代码可读性,两者解耦合,也提高了代码的可扩展性,多态的思想 重复:同名,同参,不同参数名(不同返回值)
final,finally,finaliza final:可作用再类,方法,属性上,引用上:说明该引用不能再指向其他内存空间,但引用指向的值可以改变 finally:从句里放资源回收的代码,如释放数据库的连接,释放IO对象,清空clear集合,设置大对象为null,以减少大对象上的强引用,从而提升大对象的回收空间 finalize:相当于C++里的析构函数,对象回收前会被调用,建议不重写,采用Object里默认的,若重写,需要慎重,一旦没有写好,会导致对象无法被回收,从而导致内存泄漏 技巧:1,在详细设计和代码review的过程中,会根据业务需求,在相关类和方法前加final,然后展开…… 2,项目注重异常处理流程,比如在finally从句中加入资源回收代码 3,项目里,因无需在对象回收前定义相关资源释放动作,所以无需重写finalize方法,并确保所有类的该方法都不重写
Arraylist和Array区别 Array类型的变量在声明的同时必须进行实例化(至少得初始化数组的大小),而ArrayList可以只是先声明; Array始终是连续存放的;而ArrayList的存放不一定连续; Array对象的初始化必须指定大小,且创建后的数组大小是固定的;而ArrayList的大小可以动态指定,空间大小可以任意增加; Array不能随意添加、删除;而ArrayList可以在任意位置插入和删除
List和Set的区别 List和set都是继承collection接口,存放对象,不同的是list存放有序可以重复的元素,set存放的无序不可重复元素,list比较常用的实现类有ArrayList和LinkList,Set是HashSet和TreeSet。 Set是通过HaseCode是否相等判断元素的重复
HashSet和TreeSet的区别 HashSet是通过哈希表实现的,存的是无序数据,TreeSet 是二差树实现的,TreeSet中的数据是自动排好序的,不允许放入null值。
线程中run和start的区别 run()相当于线程的任务处理逻辑的入口方法,它由Java虚拟机在运行相应线程时直接调用,而不是由应用代码进行调用。 而start()的作用是启动相应的线程。启动一个线程实际是请求Java虚拟机运行相应的线程,而这个线程何时能够运行是由线程调度器决定的。start()调用结束并不表示相应线程已经开始运行,这个线程可能稍后运行,也可能永远也不会运行。 Start()是启动一个新的线程,然后新的线程会调用run()方法,但是start()方法不可以重复调用,若会出现异常Exception in Thread “main” java.lang.IllegalThreadStateException.而且启动线程,会出现异步的效果,即线程创建和启动是随机的 run()方法类似一个一个普通方法,如果单独调用,仅仅会在当前线程启用,不会重新启动新的线程。启动线程是同步的。
设计模式
23种
创建模式:工厂,抽象工厂,创建者,原型,单例 5
结构模式:适配器,桥接,过滤器,组合,装饰器,门面,享元,代理 8
行为模式:解释器,模板方法,责任链,命令模式,迭代器,策略,参观者 7
面向对象
抽象:将一类对象的共同特种总结出来构造类的过程,数据(属性),和行为的抽象,不关心细节
继承:从已有类得到继承信息创建类的过程
封装:把数据和操作数据的方法绑定,通过接口进行访问,即隐藏一切可以隐藏的东西
多态:用同样的对象引用调用同样的方法但做了不同的事情 编译时的多态性:前绑定,方法重写override 运行时的多态性:后绑定,方法重载,overload,是面向对象的精髓 实现多态的两件事:1,方法重写 2,对象造型:用父类型引用引用了子类型对象,这样同类型引用调用同样的方法会根据子类对象的不同而表现出不同的行为
构造器不能被继承,所以不能被重写,但可以被重载
数据类型
8种基本数据类型:byte,short,int,char,lang,float,double,boolean 剩下的为引用数据类型
数组 是一种对象,有的是length属性,String 有的是length()方法,且String不能被继承,因为是final的,list是size()方法,
+=这种赋值运算符隐含了强制类型转换
自动拆箱和装箱机制 : int 的包装类:Integer,char的包装类:Character
switch可支持的数据类型:java版本不同,java5以前byte ,short,int,char ,java5版本:引入枚举,java7版本:引入字符串,lang在目前的版本中都不行
如整型字面量的值在-128到127之间,不会new新的Integer对象,而是直接引用常量池种的Integer对象进行比较
操作字符串有哪些类: String,String Builder,Sting Buffer,详见比较不同
Map中哪些线程是安全的? HashTable,因为get/put方法被synchronized修饰 SynchronizedMap ConcurrentHashMap
有序的Map有哪些? LinkedHashMap (维护着一个Hash表和双向链表)和TreeMap
java8新特性
新增Lambda表达式,代码简洁
Stream API的支持
List接口新增排序sort支持,
Optional类的使用,最大化的减少空指针
新增了线程安全的日期API
接口的默认方法和静态方法 default static
Java8代替匿名内部类:
Java8之前: new thread(new Runnable(){ @Overide Public void run(){sout(“”)} }).start(); Java8方式:new thread(()->sout(“”)).start(); Runnable r = new Runnable(){ @Override Public void run(){sout(“”)} } Java8方式: Runnable r = ()->sout(“”); 直接调用r.run();
数据库
java.sql:提供java存取数据库能力的包
MySql
去重3种办法:distinct,group by,row_number() over()
sql的优化: 按照1,SQL语句及索引的优化 2,表结构优化,如拆表 3,系统配置优化 4,硬件优化 1,在表中建立索引 2,select时使用具体字段代替* 3,在建立索引的情况下,避免使用in ,not in ,可以用exist,not exit代替,union 替代or,对数据开头就进行模糊查询,或进行表达式操作,避免在索引列上进行计算,这些都会导致数据库引擎放弃索引进行全表扫描,或数据量大的时候,避免使用where 1=1,进行nul值判断,可使用默认值0进行判断 4,设计表的时候尽量减少字段宽度,可用数字或简写等 5,join代替子查询
函数: 1,concat(st1,st2……)返回结果为连接参数产生的字符串,有一个为null,返回就为null,连接缺省为逗号 concat(str1,seperator,str2,sep……)带有分隔符 concat_ws(seprator,st1,st2……)一次性指定分割符,分隔符不能为nul,否则都为null group_concat():group by 产生的同一分组中的值连接起来,返回一个字符串 group_concat([distinct] 要连接的字段[order by 排序字段 desc/asc][seperator ‘分割符’]) 2, ABS()绝对值 MOD(N,M)余数 ROUND()四舍五入取余 Length()字符串长度 locate(a,b)返回a在b中第一个出现的位置,没有为0 instr(a,b)返回b在a中…… subString(str,pos)从str的起始pos位置返回一个串 replace(str,a,b)b替换a now() month(date) current_date() current_time() 控制流程的函数:case when if 系统信息的函数:version() user() connection_id() 返回服务器连接数 database() 数据库名 MD5() format(x,n):x 保留后n位,5进位 大小写转换:upper(s) lower(s) ucase() lcase() 去空格:trim() rand() ceil() >=最小 floor() <=最大 truncate(x,y) 返回x,保留y位 adddate(date,n)date后加上n天后 subdate(date,n)date后减去n天 addtime(time,n)time加上n秒后 subtime(time,n)time减去n秒后
三范式: 1,属性的原子性,不可拆分 2,记录的唯一性,有唯一标识 3,对字段冗余的约束,即字段不能由其他派生出来
存储过程语法 delimiter create procedure…… begin sql…… end delimiter
乐观锁 总是假设最好的情况,每次拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现,乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁 实现方式 : 版本号机制:一般是在数据表中加上一个version字段,表示数据被修改的次数,当数据被修改时,version+1。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。 CAS算法:compare and swap 一种有名的无锁算法
悲观锁 总假设最坏的情况,每次取拿数据的时候都会上锁,这样别人想拿这个数据,就会阻塞它拿到 共享资源每次只给一个线程使用,其他线程阻塞,用完之后再把资源转给其他线程。 如关系型数据库的读锁,写锁,表锁等,java中synchronized和reentrantLock等独占锁是悲观锁的实现。 两种锁的使用场景 :乐观锁适用于多读场景,写比较少,省去锁的开销,加大了系统的吞吐量。 多写的场景用悲观锁比较合适
Mongo
语句 db.dropDatabase() show collections/tables db.name.drop/insert/save/remove/update/find/findOne({age:2}) db.createUser
使用场景 1,存应用日志,查询比文本灵活,导出也方便 2,存监控数据 3,存储地理位置 4,作为缓存查询 5,第三方信息的抓取 不适用:复杂事务逻辑操作,统计汇总+复杂运算
Mongo和Mysql的区别
关系型数据库:由数据库+表+记录组成 Mong由数据库+集合+文档对象
前者非关系型,后者关系型
存储方式:前者以类json的文档格式存储 后者不同引擎由不同方式
数据处理方式不同,前者基于内存,高速读写,后者不同引擎不同
mongo相对来说热度低
前者只支持单文档事务性,弱一致性,后者支持事务
前者占用空间大,不支持join
Linux
读取权限:r=4,写入权限:w=2,执行权限:x=1
775:代表拥有者,组用户,其他用户的权限
命令: tail -f auth-service.log 动态实时日志 head -n 10 auth-service.lot 前10行日志 cat filename 一次显示整个文件 cat >filename:创建一个文件 cat file1 file2 >file 几个文件合并位一个文件 tac cat为正向显示,tac反向显示 more 一页一页的显示 编辑命令 1,vi filename 打开或创建一个文件 2,进入编辑模式:i或a 3,esc退回vi的命令模式 4,: 末行模式 5,wq保存 w:保存当前文件 x 保存并退出 q 退出vi q!不保存并退出 ifconfig :查看ip ctrl+c 强制退出 pwd:显示当前目录 cd:切换目录 cd ~John clear:清空 service network restart:重启网卡 service iptables status:查看防火墙状态 chmod:改变文件权限设置
Docker
Docker是一个容器化平台,将应用程序及其所有依赖项以容器的形式打包在一起,以确保应用程序在任何环境中无缝进行
Docker镜像image:Docker容器的源代码,包含运行容器的所有数据Docker镜像用于创建容器,build命令用于创建镜像
Docker容器container:包含应用程序及其所有依赖项,作为os的独立进程运行,相对于image是动态的
容器的状态:运行,暂停,重启,退出
命令:对镜像的操作:docker pull+serviceId,docker push +serviceId ,docker images(列出所有镜像),docker rmi+serviceId(移除镜像) 对容器的操作:docker ps(列出所有容器),docker rm+serviceId
Docker的整个生命周期:image+容器+仓库 可以类比image是类,容器是对象, image是文件,container是进程,image是由一层一层的文件系统组成,是只读的静态文件,包含镜像的位置
docker的默认仓库是dockerhub工共仓库
监控Docker容器的两种方式 1,通过脚本与Linux中的crontab结合 2,通过使用zabbix工具去监控docker使用率和cpu使用率,通过设置阀值去进行邮件报警
Jenkins
Java编写的开源持续集成工具,用于跟踪版本控制系统,并在发生更改时启动和监视构建系统
Git
git 分布式版本控制,SVN:集中式版本控制
命令 git fetch:从远程获取最新版本到本地 git merge:将内容合并到当前分支 git pull = git fetch + git merge git tag:查看标签 tag:一次commit的id,用来给开发分支做标记 git stash:缓存当前修改内容 git stash pop:恢复最新一次缓存 git branch -r :查看远程分支 git branch:查看分支情况 git push origin master:将本地分支推到远程分支 git commit 提交代码
框架
Spring
spring的注入Bean的方式:从容器中取出bean,注入到另一个bean中 a. 构造器注入 b. setter注入 c.基于注解注入 @Autowire(按照类型) @Qualifier(按照名称) @Resource
@注解: Component:定义bean Repository:对Dao实现类进行注解 Service:对Service实现类进行注解 Controller:对Controller实现类进行注解
spring的理解:是一个轻量级的IOC和AOP容器框架 核心是IOC容器:用于对对象的创建,维护,和销毁等生命周期的控制 spring按照设计模式打造的,实现了工厂模式的工厂类,BeanFactory
三种配置:基于XML,注解,Java类
AOP : 支持通用事务,如安全,事务,日志,权限等,是面向切面,将与业务无关的但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,降低了模块间的耦合度。
AOP的步骤: a. 引入AOP相关pom文件 b.编写切面类 c.在业务方法上配置切面,用@Aspect生命
AOP通知类型 : a.前置通知:在某连接点之前执行的通知 b.后置通知:有异常,没有正常返回时无法执行通知 c.抛出异常后的通知:在方法抛出异常退出执行的通知 d.环绕通知:在目标方法执行之前和之后都可以执行的通知 特:需要返回返回值,否则只得到null 可以控制目标方法是否执行,是否有返回值,及改变返回值 可以接收ProceedingJoinPoint,其他只能接收JoinPoint e.最终通知:在目标方法执行后执行的通知。与后置通知的区别是,即使出现异常也会执行
IOC :控制反转,指创建对象的控制权移交给Spring容器,使用java的反射机制,根据配置文件在运行时动态的去创建对象即管理对象并调用对象的方法。
Spring bean的生命周期:类似,大概,按照流程随便总结下
bean的作用域: 默认Singleton:每个容器种一个实例 request:每个网络请求一个实例,请求完成后bean会失效并被垃圾回收 session:每个session一个实例 prototype:每个bean请求一个实例 global-session:全局作用域
spring框架中用到的设计模式 工厂模式:beanFactory ,用于创建实例 单例模式:bean的产生 代理模式:AOP 模板模式:用来解决代码重复的问题,RestTemplate,JpaTemplate 观察者模式:当一个对象的状态改变,所有依赖于它的对象都会得到通知,被制动更新
Transactional :一般不指定的情况下出现rollback,运行时异常error的异常会出现回滚,出现Exception的异常不会回滚 解决办法:可以在注解属性上配置rollbackFor = Exception.class 或者手动触发回滚:TranscationStatus.setRollbackObly(); 事务可以加到抽象类或接口上,具体的业务方法上,继承抽象类或实现接口的子类也就继承了这个事务
Spring MVC
表现层框架,是面向web应用的,通过把model-view-controller进行过分离,是基于MVC架构的用来简化web应用程序开发的应用开发框架,是spring的一个模块
流程: a、用户发送请求至前端控制器DispatcherServlet。 b、DispatcherServlet收到请求调用HandlerMapping处理器映射器。 c、处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。 d、 DispatcherServlet调用HandlerAdapter处理器适配器。 e、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。 f、Controller执行完成返回ModelAndView。 g、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。 h、DispatcherServlet将ModelAndView传给ViewReslover视图解析器。 i、ViewReslover解析后返回具体View. j、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。 k、DispatcherServlet响应用户。
SpringMVC的控制器是单例模式,所以在多线程访问时有线程安全的问题,不要用同步,会影响性能,解决方案是在控制器里不能加字段
常用的注解 @RestMapping:用于处理请求url映射的注解 @RequestBody:接收http请求的json数据,将json转换为java对象 @ResponseBody:将Controller方法返回的对象转化为json对象响应给用户 控制器的注解:@RestController = Controller+ResponseBody
SpringMVC中的函数返回值 有多种类型,String ,ModelAndView(视图和数据合并在一起的)
SpringMVC用什么对象从后台返回数据到前台:ModelMap,放在put里
怎样把ModelMap里面的数据放在session里 在类上加@SessionAttributes注解,里面包含的字符串就是放在session里的key
拦截器如何实现 1,实现HandlerInterceptor接口 2,继承适配器类 然后在配置文件中配置拦截器
注解原理 本质上是继承了@Annotation的特殊接口,具体实现类是Java运行时生成的动态代理类,通过反射获取注解时,返回的是Java运行时生成的动态代理对象
MVC模式 :用于应用程序的分层开发 Model:代表一个存取数据的对象 View:模型包含数据的可视化 Controller:作用于Model+View,控制数据流向模型对象,并再数据变化时更新视图,使Model和View分离开
Spring Boot
理解:是Spring的子项目,是Spring组件的一站式解决方案,简化了配置,提供了各种启动器,简化了Spring的应用开发,约定大于配置,简化了maven配置,just run就能创建一个产品级别的应用
核心注解 :SpringBootApplication = SpringBootConfiguration(实现配置文件的功能)+EnableAutoConfiguration(实现自动配置的功能,也可关闭)+ComponentScan(组件扫描)
自动配置的核心 EnableAutoConfiguration+Configuration+ConditionalOnClass
核心配置文件 application(spring boot项目的 自动化配置文件) bootstrap
核心配置文件的格式 properties yml:是一种可读的数据序列化语言,用于配置文件,与属性文件相比,yaml更加结构化,有分层配置数据,采用缩进的格式,不支持@PropertySource注解导入配置
spring boot 内置了tomcat/jetty容器,不需要独立容器
Sping Boot的监视器:actuator 帮助访问生产环境中正在运行的应用程序的当前状态 该模块公开了一组可直接作为HTTP URL访问的REST断点来检查状态
运行Spring Boot方式 1,打包命令式放到容器中运行 2,Maven插件运行 3,main()
读取配置文件内容的方式 1,@Value(’${student.name}’) 2,@ConfigurationProperties 3,@PropertySource配合@Value 4,2和3配合 5,@Configuration配合@Value
Spring Cloud
理解: 是一系列框架的有序集合,简化了分布式系统基础设施的开发,如服务注册与发现,消息总线,负载均衡,断路器,数据监控等,都可以做到一键启动和部署
断路器的作用:某个服务单元发生故障之后,通过断路器的故障监控,向调用方法返回一个故障响应,而不是长时间等待,即不因调用故障服务长时间占用而不释放,避免故障在分布式系统中蔓延
核心组件 服务注册与发现Eureka Feign:基于动态代理机制,根据注解和选择的机器拼接请求url,发起请求 Ribbon:负载均衡,从一个服务的多台机器中选择一台 Hystrix:提供线程池,不同的服务走不同的线程池,实现不同服务调用的隔离,避免了服务雪崩的问题 Zuul:网关管理,由Zuul网关转发请求给对应的服务
Spring cloud中服务之间通过restful方式调用有两种: 1,restTemplate+Riiboe 2,Feign
Ribbon 服务间调用作负载,轮询请求实现均衡负载 基于Http和Tcp客户端的负载均衡器,在客户端配置服务端列表 Ribbon和Feign区别 Feign本身包含Ribbon 1,启动类注解不同:RibbonClient,EnableFeignClients 2,服务的指定位置不同:Ribbon是在RibbonClient注解上声明 Feign是在定义抽象方法的接口中使用@FeignClient声明 3,调用方式不同: Ribbon需要自己构建http请求,模拟http请求使用RestTemplate发送给其他服务 Feign则在Ribbon基础上做了改进,采用接口方式,将调用的其他服务的方法定义成抽象方法即可 ribbon也是依赖于Eureka,获得各个服务地址 Zuul :对外部请求做负载均衡
服务熔断3种状态 关闭:默认,打开,半开 关闭:请求次数异常超过设定比例,时,打开 打开:打开时执行降级方法 半开:定期尝试发起请求确认是否恢复,若yes,转为关闭或保持打开
Zuul的作用 类似于Nginx的网址重定向 过滤请求
Feign 调用服务默认时长是1s
服务熔断 :当某个服务出现不可用或者响应超时时,为了防止整个系统出现雪崩,暂时停止对该服务的调用
服务降级 :从整个系统的负荷情况触发,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或响应慢,在其内部暂时舍弃对一些非核心接口和数据的请求,而是直接返回一个提前准备好的的fallback错误处理信息,这样,虽然提供一个有损service,但却保证了整个系统的稳定和可用 区别:从可用和可靠角度,都是为了防止系统崩溃 不同,触发原因不同,前者是某个服务故障引起,后者是从整个系统的负荷考虑的
服务注册与发现 注册:将服务信息注册到注册中心上 发现:从注册中心上获取服务信息 若没有Eureka,则需要把新的服务器地址配置到所有依赖于某模块的服务上,并相继重启他们 目的:保证当某服务上下线发生变更时,服务的消费者和提供者能保证正常通信 步骤 1,启动注册中心 2,启动会员服务 3,当服务启动时,会把当前自己服务器的信息比如服务地址通讯地址(端口)等以别名的方式注册到注册中心 4,另一方消费者以该别名的方式去注册中心上获取实际的通讯地址(获取rcp远程调用地址) 5,如消费者获取实际RCP远程调用地址后,在本地使用httpClient技术实现调用 Eureka每30s更新一次服务调用地址
Spring Cloud支持三种注册中心: Eureka Zookeeper Consul go语言 Dubbo支持两种:Redis和Zookeeper
Eureka和Zookeeper的区别: Zookeeper保证了CP Eureka保证了AP,且能很好的应对因网络故障导致的部分节点失去联系的情况,而不会像Zookeeper使微服务瘫痪 C:一致性 P:分区容错性 A:高可用性
MyBatis
由于面向接口编程的趋势,Mybatis实现了通过接口调用mapper配置文件中的sql语句
Mapper接口没有实现的方法却可以使用? 由于动态代理
工作流程: a. 读取配置文件,如数据库连接信息,mapper映射文件等 b.创建SqlSessionFactory(程序级别),继而创建SqlSession(过程级别),目的是执行sql语句 c.返回结果映射到java对象
接口绑定方式 注解绑定,@Select,@Inset,@Update,Delete 优点:适合简单,效率高 缺点:sql有变化时需要重新编译 xml里写sql绑定
缓存 :是避免与数据库频繁交互 1,一级缓存:同一个SqlSession中,Mybatis会把执行方法和参数通过算法生成缓存的键值,将键值及结果存放在一个Map中,如果后续的键值一样,则直接从map中获取数据 2,不同的SqlSession之间的缓存时相互隔离的 3,用一个SlSessIon,可通过配置使得再查询前清空缓存 4,任何cud语句都会清空缓存 5,二级缓存:在SqlSeesionFactory得生命周期中 有全局和分开关 全局的在mybatis-config.xml中,< setting>标签中,默认为true 分开关在*Mapper.xml中,默认不开启
动态SQL :以便签的形式编写,根据不同的条件执行不行的sql语句 9种 < if ,where,choose,when,otherwise,set,trim,foreach,bind> 模糊查询也算一种’
参数占位符有两种 :#{},${} ${} :字符串替换,有sql注入的危险 #{}:通过?作为参数占位符,且预编译处理,可防止sql注入
模糊查询的3种方式 1,拼接% 2,concat()字符串拼接 3,bind标签 < bind name ="||" value="%"+number+"%"/> select * from orders where number like #{||}
sql注入 :将sql代码添加到输入参数种,传递到sql服务器解析并执行的一种攻击手法 如何执行:数字注入,where id = -1 or 1=1 字符串注入:如以sql中的#注释符来攻击,或— 注释符 如何让防止:严格检查输入变量类型和格式 如数字的强校验,字符串中的正则校验,如过滤和转义特殊字符,如单引,双引,反斜杠,null等
在mapper中如何传递多个参数: 1,Dao层的函数,无注解形式,直接写#{0},#{1} 2,@Param注解 3,多个参数封装成Map
**一对多(多对一)的几种方式:**多有两种,只不过是配置标签不同 联合查询和嵌套查询 联合:几个表联合查询,只查询一次,在resultMap里配置 嵌套:先查询一个表,根据这个表结果的外键id,再去另外一个表查询数据,在xml中的sql语句中使用select属性,进行配置 一对多:resultMap中配置Collection标签 多对一:resultMap中配置association标签 多对多:3张表 A B AB关联表C C中配置:1,根据AID查询数据 2,根据BID查询的数据 A,B中分别配置一对多的情况,collection标签中select属性为C中配置的
ORM和JDBC的区别 ORM:Object-Relation-Mapping 关系型数据库与对象之间映射 区别:JDBC代码复制,需要访问数据库,代码最大 ORM的底层实现是JDBC
Redis
默认有16个库,默认连接到0
支持的数据类型:String ,Hash,List,Set,Zset
持久化 :将内存数据写到磁盘中,防止因为宕机数据丢失 Redis的数据全部存放在内存中,如果挂了,没有配置持久化的话,重启的时候数据全部丢失。大量请求过来,缓存无法命中,造成缓存雪崩,mysql无法承载大量请求,造成系统崩溃。 方式:RDB 在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储 。 AOF(命令存储的形式) AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,在 redis 重启的时候,可以通过回放 AOF 日志中的写入指令来重新构建整个数据集。 可同时使用两种 比较:AOF更新频率快,RDB性能好
架构模式:单机版,主从复制,哨兵,集群
在项目中的应用 作为缓存的作用是减少数据库的访问压力,再结合过期时间expire,进行缓存数据更新 1,热点数据的缓存 2,限时业务的运用,如限时优惠活动,手机验证码等,到时redis会删除它,expire命令设置生存时间 3,计数器相关:incrby命令实现原子性递增,可用于高并发的秒杀活动,分布式序列号生成,如限制一个手机号可以发多少条短信,一个接口一分钟限制多少请求,调用多少次 4,排行榜问题:SortedSet进行热点数据的排序 5,分布式锁:setnx命令 6,延时操作:如订单生成后,10分钟后验证是否真正购买,若无购买,则还原库存 方案:再订单生成时,设置一个key,同时设置10分钟后过期,后台实现一个监听器监听key,key失效时将后续逻辑加上,也可用rabbitmq,activemq等中间件的延迟队列服务实现 7,分页,模糊查询 8,点赞,好友等相互关系的存储,set两人共同好友,是否点赞过 9,队列,list top,list push,方便执行队列操作
RabbitMQ
好处:解耦,异步,削峰(并发量大的时候,并发缓冲,避免了所有请求到数据库,造成数据库连接异常)
使用信道的方式传输数据,信道:是建立在真是TCP连接内的虚拟连接,且每条TCP连接上的信道数量无限制
消息以循环的方式发送给消费者
消息创建时生成一个routing key 绑定到交换器上–>将消息的routing key与queue的routing key进行匹配,匹配的进入队列,否则进去黑洞
交换器 :3种 topic:不同的message到达同一队列 direct:一对一完全匹配 fanout:广播到所有队列
缺点:系统的可用性降低了,挂了就全完了 复杂性上升,如一致性的问题(保证消息不被重复消费),消息的可靠性传输等
MQ的几种消息传递方式 P:生产这 exchange:交换机 C:消费者 1,简单模式 P ----->queue ------->C 2,工作模式 --------->C1 P--------------->Queue--------->C2 C1,C2为竞争关系,监听同一消息队列 3,发布和订阅 ------->queue1-------->C1 P----------->exchange----- >queue2--------->C2 多个消息队列绑定到交换机上 4,路由模式,路由key ------error------>queue1------------>C1 P------->exchange-----info—>queue2-------------> C2 ------error---->queue3------------> exchange根据key,选择性的将message给queue 5,主题模式 在4路由的基础上,key使用通配符如*.orange.*的形式,灵活度更高
消息丢失的情况 1,生产者丢失,可能时网络的问题 解决方案:可选择MQ的事务,但会降低吞吐量 MQ的发送确认模式,需要自己维护MQ分配的ID 2,MQ的丢失:开启持久化,同步到磁盘 3,消费者丢失,如还没处理,进程就挂掉了 可采用处理完成后,向MQ发送确认消息
保证消息的一致性 1,生产者再次发送消息 2,消费者查询下生产者业务是否完毕
Maven
理解:跨平台项目管理工具 1,构建项目:清理,编译,测试,生成报告,再到打包,部署 2,依赖版本管理工具 3,管理项目信息
打包类型:jar,war,或pom,ear
项目间有依赖和聚合的关系
Maven仓库 :存储jar文件,坐标定义存储路径 配置镜像地址:setting.xml中的mirrors的节点 Maven仓库 本地仓库 远程仓库 中央仓库 私服 其他公共库 repo2,aliyun
上传jar包到私服上: 1,在maven的setting.xml认证root,pwd 2,上传项目的pom.xml中配置jar包上传路径 3,执行命令,deploy发布项目到私服
下载jar包到本地仓库。也是在setting.xml中配置
maven命令: mvn clean 清理 mvn compile 编译 mvn test 测试 mvn package:打包 只打jar包:mvn jar:jar mvn install:安装项目到本地仓库 mvn deploy:发布项目到远程仓库 mvn dependency:tree 显示依赖 mvn dependency:list mvn dependency:sources 下载依赖包源码
定时任务
@Scheduled(cron=‘执行时间’)
Quartz:定时器的实现
ScheduledExecutorService接口实现类
jdk自带定时器的实现,Timer类
Nginx
HTTP服务器和反向代理服务器,也是IMAP,POP3,SMTP代理服务器 高效的反向代理,负载均衡,处理2-3万并发连接数 为什么使用?高并发连接,跨平台,配置简单 Nginx性能高的原因:异步非阻塞事件处理机制 正向代理:一个人发送一个请求直接到达了目标服务器 反向代理:请求统一被NG接收,NG收到之后,按照一定的规则分发给了后端的业务处理服务器进行处理
并发处理办法
采用HTML静态化:某访问过大,但内容不经常改变的页面,如首页,新闻页等
提供文件服务器单独部署 将文件系统单独拿出来提供专注于处理文件的存储,访问系统,将压力转移,分担风向
负载均衡:将工作量大的分摊到多个操作单元上 软,硬件负载均衡 从地理结构上,本地,全局负载均衡
反向代理,用户的请求请求到负载均衡设备上,再将请求分发到空闲的服务器上处理,后再通过负载均衡设备返回给用户
动静分离:将网站静态资源HTML,CSS,JS,IMG等与后台应用分开部署,提高访问静态代码的速度 有一种做法,是将静态资源部署到Nginx或CDN上,后台应用部署到应用服务器上
并发优化: 前后端分离,Ng,负载,限流,分库,分表,HTML静态化,动静分离
跨域
Cors ,http访问控制
数据量大的处理办法
sql优化
缓存,可将一些有时效性的经常访问的,不便于存储再数据库的数据,必要时,可将缓存应用服务器单独部署,数据量大时,还可以组成缓存服务器,集群,如redis,cache 好处:减少数据库的访问压力 相对于数据库,读写快
数据库读写分离 读(主),写(从)分开对应不同的数据库服务器 写时,同步到从服务器
数据库活跃数据分离,查不到时才到非活跃数据库中查询
批量读取,延迟修改(暂存缓存中),高并发时,可合并多个请求
数据库集群和库表散列
缓存穿透,击穿,雪崩
穿透:用户查询数据,缓存和数据库中都没有的数据,当用户很多的情况下,缓存都没有命中,于是请求到了持久层数据库,给数据库造成了压力 解决方案 : 1,布隆过滤器:对所有可能查询的参数以hash形式存储,用户想要查询时,不在集合内丢弃,不再对持久层进行查询 2,存储空对象
击穿:是指一个key很热点,扛着大并发,集中对这一个key进行访问,当key失效的瞬间,持续大并发穿破缓存,直接请求数据库
雪崩:指缓存层出现了错误,不能正常工作,于是所有请求到达存储层,存储层调用量暴增,导致存储层挂掉 解决方案 1,多增设几台redis, 确保redis高可用 2,限流降级:一个线程访问查询数据和写缓存,加锁,其他等待 3,数据预热:在正式部署之前,先把可能的数据先预先访问一遍,这样大量访问的数据就可以加载到缓存中,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同key的过期时间,让缓存失效时间尽量均匀
分布式锁
三种实现方式: 数据库乐观锁 redis 的setnx命令实现 基于zookeeper的分布式锁
分布式锁三种方案: 1,基于数据库 2,基于缓存环境,redis等 3,基于Zookeeper
分布式Session
避免A 用户两次登录平台,获得的Session不一样
实现方式: 1,粘性Session,负载均衡器设置了粘性Session 2,服务器Session 3,Session共享机制,使用Redis缓存方案 4,Session持久化到数据库 5,terractta实现Session复制
分库,分表
数据切分,纵向,水平 纵向:强调业务的拆分,不同业务不同表 水平:强调技术曾名的拆分,一个表,拆分成多个表数据的和
分库,分表要解决的问题 1,事务 2,分页 3,sql重写,如跨节点的join,count,order by 及聚合函数问题 4,数据迁移 5,容量规划,扩容等
分库策略:数值范围,如1-9999为一个库 取模计算:Id mod n 放第1,2,3,4……个库
事务
特性 原子性atomicity:要么全做,要么全不做) 一致性consistency:数据不会因为事务的执行而遭到破坏 隔离性isolation:并发事务间不受干扰 持久性durability:一旦提交,对事务的改变是永久性的
两种实现方式 :编码式,基于AOP技术实现的声明式 基于AOP技术实现的声明式事务管理,实质就是:在方法执行前后进行拦截,创建并加入事务,执行完目标方法后根据执行情况提交或回滚事务。
声明式事务管理又有两种方式 :基于XML配置文件的方式;另一个是在业务方法上进行@Transactional注解,将事务规则应用到业务逻辑中。 是否需要创建事务,是由事务传播行为控制的。读数据不需要或只为其指定只读事务,而数据的插入,修改,删除就需要事务管理了。
Spring 事务开启方式: Spring配置文件中关于事务配置由三部分组成:DataSource,TransactionManager 和代理机制。一般变化的式代理机制 DataSource、TransactionManager这两部分只是会根据数据访问方 式有所变化,比如使用Hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。 a.编程式事务管理 b.基于 TransactionProxyFactoryBean的声明式事务管理 (每个Bean一个代理或所有Bean共享一个代理) c.基于 @Transactional 的声明式事务管理 d.基于Aspectj (切面) AOP 拦截器配置事务 Spring Boot 开启事务:核心是使用@EnableTransactionManager注解开启事务管理器,开启后在需要使用事务的类或方法上标注@Transactional即可。
事务并发引起的三种情况 : 脏读:前一个事务修改了数据,未提交,被后一个事务读到 不可重复读:同一查询在同一事务中多次进行,由于其他事务做删除或修改,导致每次返回结果集发生变化 幻读:同一查询在同一事务中多次进行,由于其他事务做插入,导致每次返回结果集发生变化
Spring的隔离级别: 串行化 三种都不产生,隔离级别高 可重复读 避免不了幻读 读已提交 避免脏读 读未提交 会产生3种 默认
Spring事务的7个事务传播行为: Propagation_required:如果当前存在事务,则加入该事务,不存在就创建 –_supports:存在即加入,不存在即以非事务方式运行 Mandatory:存在加入,不存在抛出异常 Requires_new:存在延缓事务,创建一个新的 Not_supports:存在就暂停当前事务,以非事务方式运行 Never:以非事务方式运行,存在就报异常 Nested:没有就创建,有的话,就在当前事务种做嵌套
分布式事务
分布式系统会把一个应用系统拆分为可独立部署的多个服务,因此服务与服务之间需要远程协作才能完成事务操作,这种分布式系统环境下不同服务之间协作完成的事务叫分布式事务
产生原因:数据库的分库分表,业务应用服务化等
解决方案:2,3阶段提交或补偿事务
一致性HASH
使用取模算法,是对2的32次幂进行取模,将整个哈希值空间组成一个虚拟圆环,如假设某哈希函数的值空间为0~2的32次幂-1 圆环为hash环,顺时针1,2,3,4……2的32次幂-1 对某值进行哈希,确定是否在圆环上
CAP
C:一致性 客户端知道一系列的操作都会同时发生 A:可用性,每个操作都必须以可预期的响应结束 P:分区容错性 即使单个组件无法可用,操作也可以完成
BASE理论
对CAP的扩充 BA:基本可用 S:软状态 E:最终一致性
线程
例,建两个线程安全和不安全的ArrayList对象,通过100个线程,向两个对象里插入100个元素 安全:完成后有100个元素 不安全:由于会抢占,完成后可能会小于100个元素 从线程内存角度分析 :分为线程内存和主内存,两边都会读取数据,安全的会一个一个操作,不安全的会抢占资源,值会被冲掉
线程安全的对象 Vector,HashTable,StringBuffer 性能会差一些 不安全对象 ArrayList,LinkedList,HashMap,StringBuilder 把List包装成线程安全的:Collections.synchronizedList(List) Set--------Collections.synchronizedSet(Set) HashMap--------------Collections.synchronizedMap(map)
volatile
volatile不能保证原子性 int a =0; 线程1000个对其+1,结果小于1000 volatile修饰变量,若变量在多线程里并发操作时,并不能保证原子性
volatile能避免指令重排 在编译和执行代码时,出于优化考虑,会重排指令,大多数场景,不会影响结果,但在多线程下会有可能有问题,所以volatile能阻止指令重排
volatile可让变量在线程间可见
从ConcurrentHashMap看volatile用法 1,能实现并发的HashMap 2,private transient volatile long baseCount; 存储该对象长度的变量,volatile修饰,能保证多个线程同时读写ConcurrentHashMap对象,对长度的修饰能立即让其他线程感知,能保证线程安全
Synchronized
作用在代码块,方法和静态方法的效果 修饰代码块,是同步锁 修饰以{}包含的代码块,多个并发线程到达时,只有一个线程能被执行,其他线程阻塞 sychronized作用的对象(锁定的对象)是调用这个代码块的实例对象 修饰方法,与修饰代码块相似,只是作用范围不同 sychronized关键字不能继承,即子类如果覆盖父类方法,将不拥有synchronized特性 修饰静态方法:作用范围是整个静态方法 静态方法是属于类的,而不属于类的实例对象的,所以修饰静态方法时,锁定的时该类所有实例对象
具有重入特性 当线程请求由其他线程锁定的方法时,该线程会阻塞,但当请求由自己持有的方法时,该请求能够成功,即重入 sychronized是可重入锁,可重入特性适用于继承场景,比如父类方法和子类方法都可以用 sychronized修饰子类方法调用父类时,也具有可重入特性
能锁方法,但不能锁由多个方法组成的业务流程 此类场景,用lock sychronized能保证方法在同一时刻只被一个线程调用
技巧 a.说出作用在方法和静态方法时的不同表现:方法时锁实例,静态方法时是锁该类的所有实例对象 b.不适合锁业务流程,需要结合lock
锁
用ReentrantLock控制业务层面的并发
进一步了解可重入性 可重入锁也叫可递归锁,sychronized和ReentrantLock 同一线程再次进入同步代码时,可使用自己已获取到的锁 同一线程多次获取同一把锁时,防止死锁发生 如:某数据库的操作的线程需要多次调用被锁管理的“获取数据库连接的方法”,如使用可重入锁就可能避免死锁,反之,在第二次调用方法时,有可能被锁住
公平锁 启动顺序与获得锁的顺序一致,先启动先获得
非公平锁 先创建不一定先获得锁
公平锁和非公平锁的使用场景 1,公平锁会维护一个等待队列,多个在阻塞状态等待的线程会被插入该等待对列,在调度时按照他们所发请求的时间顺序获取锁 2,未必现需要保证先来先服务,非公平锁会有更多机会抢占锁 3,创建可重入锁时,可通过调用带有布尔类型参数的构造函数来指定该锁是否是公平锁 ReentrantLosk(boolean fair) 4,非公平锁性能高于公平锁,公平锁当前线程不是队列的第一个就无法获取锁,从而增加了线程切换次数 5,如线程占用(处理)时间要远长于线程等待,那用非公平锁其实效率并不明显,但用公平锁会给业务增强很多的可控制性
读写锁的使用场景 ReentrantReadWriteLock对象会使用两把锁来管理临界资源,一个是读锁,一个是写锁 某线程获得了资源的读锁,其它读操作可以并发,但写操作的线程会被阻塞,某线程获得了某资源的写锁,其他任何企图获得该资源“读锁”和“写锁”的线程都会被阻塞 如果读操作的数量远超过写操作时,那么更可以用读写锁来让读操作可以并发执行,从而提升性能。
TreadLock能定义线程本地变量 线程里可以使用定义在主内存里的变量,也可以通过TreadLock存储线程本地变量,注:定义的变量非跨线程可见的 如多个线程去爬取不同的网站,每个线程用自身的TreadLock来维护爬取不成功的列表
从TreadLocalMap进一步了解TreadLock特性 TreadLock是通过内部的TreadLockMap对象来存储本地变量,TreadLockMap里每个元素都是Entry,每个Entry是键值对,键是当前 TreadLock对象,value是本地变量 Entry是继承WeakReference,是弱引用,若Entry无强引用会被回收,一个线程类里可以有多个TreadLock变量,有一个TreadLockMap, 一个TreadLockMap里有多个Entry,每个Entry存储里一个TreadLock本地变量
TreadLock可能会导致内存泄漏,如何避免? TreadLock保存值时,会放入Entry对象,Entry是弱引用,如创建TreadLock的线程终止 ,会回收,但如创建的线程一致持续运行,那么其中的value就可能无法回收 避免方式:用好TreadLock对象后,需要及时remove()
技巧 用TreadLock来保存本地变量,内部实现TreadLockMap Entry内存泄漏,弱引用
线程池
基本用法 定义Runnable或Callable类型的任务 创建ThreadPoolExecutor,注参数 把任务放进线程池并运行,execute() 通过shutdown()关闭,即不接受新任务,当前线程执行完后退出
构造线程池时各项参数解析 coolPoolSize:创建线程池后,线程数为0,当有任务,会创建一个线程去执行,当线程数达到corePoolSize后,会把新任务放到缓存队列中 maximumPoolSize:表线程池中最多能创建多少个线程 keepAliveTime:表线程没有任务执行时最多保持多久时间会终止,unit表单位 workQueue:阻塞对列,用来存储等待执行的任务 handler:拒绝处理任务时的策略,4个值 常用:丢弃任务并抛异常 AbortPolicy 悄悄丢弃:DiscardPolicy
线程池的工作方式 创建线程池后,无线程,直到来任务,任务数达到corePoolSize后,放入到workQueue队列,workQueue如有界,满了以后创建线程,最大到maximumPoolSize,如无界,任务会一直丢到队列,最终导致OOM异常
设置成有界队列,避免造成内存泄漏
可以排查因线程池而导致的OOM异常说辞
面试题:为什么用线程池?避免因线程切换而造成的性能损耗 构造线程池时关注哪些参数? 线程池是如何接受并处理任务的?任务满了以后怎么办? 在使用线程池时,如何避免OOM异常?
线程并发
通过wait,notify管理并发 以生产者,消费者问题观察wait,notify 这两个方法需要放置在synchronized的作用域里,一旦执行wait方法,会释放synchronized所关联的锁,进入阻塞状态,无法再次主动地到可执行状态 一旦执行notify方法,会通知因调用wait方法而等待锁的线程,如有多个线程等待,则会任意挑选一个线程来唤醒,notifyAll会唤醒因wait而进入到阻塞状态的线程,但他们没有得到锁,因此会竞争锁,得到锁的继续执行,在它释放锁之后,其他线程继续竞争,因此类推 当仓库满,wait生产者线程,notify消费者线程 当仓库空,notify生产者线程,wait消费者线程 一旦执行notify方法,会通知调用wait方法而等待锁的线程,如有多个线程等待,则会任意挑选一个线程来唤醒
通过Condition实现线程间的通讯 当线程A调用Condition的await方法后,会释放相应的对象锁,并且让自己进入阻塞状态,等待被其他线程唤醒,线程B得到锁资源后,开始执行业务,完成后,能调用Condition的signal方法,唤醒A线程,让线程A恢复执行 基于Object类的wait().notify()。notifyAll()只能创建一个阻塞队列 通过Condition类,可以在不同的线程里创建多个阻塞队列
通过Semaphore管理多线程的竞争 多个线程需要竞争数量相对少的资源,比如100个线程需要连接到通过一个数据库上,但任何时刻数据库最多只能提供10个连接 Semaphore类是个计数信号量 构造函数
public Semaphore ( int permits, boolean fair) ;
permits: 表示初始化可用的资源数目,而fair表示是否是公平锁
用acquire ( ) 申请资源,用release ( ) 释放资源,
无可用资源时,进入阻塞队列,当有资源可用时,Semaphore自动唤醒
同步计数器CountDownLatch用法 CountDownLatch 有一个正数计数器。countDown()对计数器做减操作,直到所有的计数器都归0或中断或超时,await线程才会继续,否则会一直阻塞,能保证以CountDownLatch所标记的前置任务都完成后,主任务再进行
线程通过Callback返回结果,通过Future获取结果 CountDownLatch范例:通过Callable类对象得到返回结果,用future得到Callable的返回 多个线程任务用线程池管理 调用3个任务里全部得到结果后,再把结果一并组装成List,用CountDownLatch来统计3个线程的完成情况 通过await设置服务超时时间 Futrue----------------------VS----------------实际业务需求 每个Future是独立的 -----------------------多个Future间很难关联
通过CompletableFuture管理多线程
微服务
模块拆分成一个独立的服务单元通过接口来实现数据的交互。 简单来说微服务就是很小的服务,小到一个服务只对应一个单一的功能,只做一件事。
这个服务可以单独部署运行,服务之间可以通过RPC来相互交互,每个微服务都是由独立的小团队开发,测试,部署,上线,负责它的整个生命周期。
分布式服务 : 分散部署在不同的机器上的,一个服务可能负责几个功能,是一种面向SOA架构的,服务之间也是通过rpc来交互或者是webservice来交互的。 逻辑架构设计完后就该做物理架构设计,系统应用部署在超过一台服务器或虚拟机上,且各分开部署的部分彼此通过各种通讯协议交互信息,就可算作分布式部署, 分布式部署的应用 不一定是微服务架构的,比如集群部署,它是把相同应用复制到不同服务器上,但是逻辑功能上还是单体应用
联系 联系:微服务架构是分布式服务架构的子集,分布式只是一种手段,把不同的机器分散在不同的地方,然后这些机器间相互协助完成业务。分布式重在资源共享与加快计算机计算速度。 微服务架构通过更细粒度的服务切分,使得整个系统的迭代速度并行程度更高,但是运维的复杂度和性能会随着服务的粒度更细而增加。微服务重在解耦合,使模块间相互独立。
区别 (1)架构不同:微服务的设计是为了不因为某个模块的升级和BUG影响现有的系统业务。微服务与分布式的细微差别是,微服务的应用不一定是分散在多个服务器上,可以是同一个服务器。 (2)作用不同:分布式:不同模块部署在不同服务器上,分布式主要解决的是网站高并发带来问题。微服务:各服务可独立应用,组合服务也可系统应用。 (3)粒度不同:微服务粒度更小,耦合度更低,由于每个微服务都由独立的小团队负责,因此它敏捷性更高,分布式服务最后都会向微服务架构演化,这是一种趋势, 不过服务微服务化后带来的挑战也是显而易见的,例如服务粒度小,数量大,后期运维将会很难。
RPC 是两个子系统之间进行的直接消息交互,它使用操作系统提供的套接字来作为消息的载体,以特定的消息格式来定义消息内容和边界。 NIC :网络接口芯片 network interface circuit 消息从用户进程流向物理硬件,又从物理硬件流向用户进程,中间还经过了一系列的路由网关节点。 WebService 是一种可以跨平台的,基于HTTP协议和XML的Web API。 WebService能够让客户端像调用本地代码一样调用服务端代码,是一种分布式计算的Web应用程序组件。 发送Http协议,数据格式是XML WebService是Web服务器上应用;反过来说,Web服务器是WebService运行时所必需的容器。这就是它们的区别和联系。
就是基于Web的服务。它使用Web(HTTP)方式,接收和响应外部系统的某种请求。从而实现远程调用. XML Extensible Markup Language -扩展性标记语言 7. SOA架构 :SOA是不同业务建立不同的服务,服务之间的可以数据交互粗粒度的服务接口分级,这样松散耦合提高服务的重用性,也让业务逻辑变的可组合,并且每个服务可以根据使用情况做出合理的分布式部署,从而让服务变的规范,高性能,高可用。
其他
Unix系统中,Socket,共享内存,消息队列,信号量都可以用于进程间通信
IP地址根据网络ID的不同分为5种类型:分别是A类地址、B类地址、C类地址、D类地址和E类地址。
相关文章 笔试题