Java面试题汇总

Jasper是Tomcat的JSP引擎,它可以解析JSP,并将其转换成Servlet。在运行过程中,Jasper可以检测JSP文件的变化,并重新编译它们。

Tomcat的默认端口是8080。

Tomcat有两种连接器:

1、HTTP连接器,它有很多属性可供修改,比如重定向或代理转发。

2、AJP连接器,使用该连接器可以和Apache等连接。

Tomcat作为Windows服务的好处:

1、自动启动。

2、启动无活动用户的登录的服务器。

3、可以与Windows用户绑定,增强安全性。

如何使用.war文件部署应用:

将JSP或Servlet放在相应的子目录中,然后压缩目录,生成一个.war文件,把这个文件放置到Tomcat的webapps目录下。

当Tomcat启动时,会自动解压缩war文件,从而完成部署。

什么是Tomcat Valve?

Tomcat4引入的新技术,允许将一个Java类的实例映射到特定的Catalina容器。

Tomcat配置了4种类型的Valve:

1、访问日志;

2、远程地址过滤;

3、远程主机过滤;

4、客户请求记录。

Servlet的声明周期:

1、Tomcat通过init方法来启动Servlet;

2、调动Servlet的服务方法;

3、调用destroy方法来销毁Servlet。

NAT协议的目的是将私有IP地址从公有IP地址隐藏起来,给组织提供一定的安全性。

JDK和JRE的区别:

JDK(Java开发工具包),提供了开发Java所需要的工具(比如编译器和调试工具),也提供了Java程序的运行环境。

JRE(Java运行环境),如果只需要运行Java字节码,不需要编写Java源代码,只安装JRE就可以了。

==和equals的区别:

对于基本类型,==比较数值是否相同;对于引用类型,比较的是对象在内存中的存储位置是否相同。

equals方法可以被重写为自己想要的比较逻辑,因此返回值是true还是false,要看对象的具体equals方法的代码是怎么写的。

final的作用:

1、用在类上,表示类不可以被继承。

2、用在变量上,表示变量不可以被修改。

3、用在方法上,表示方法不可以被重写。

Math.round(-1.5)是多少?

-1

java.lang.String不是基本类型,它是对象类型。

String、StringBuffer、StringBuilder:

String是不可变的,对其进行加法运算会产生新的字符串。

StringBuffer是可变的字符串,且线程安全。

StringBuilder也是可变字符串,线程不安全。

String s = "A"和String s = new String("A")不同,前者会在常量池中分配存储空间,而后者会被分配到堆中。

通过StringBuffer和StringBuilder的reverse方法,可以反转字符串的内容。

String类的常用方法:

1、indexOf

2、charAt

3、replace

4、trim

5、split

6、getBytes

7、length

8、toLowerCase

9、toUpperCase

10、substring

11、equals

抽象类不一定要含有抽象方法。

普通类不能含有抽象方法,可以实例化。

抽象类可以含有抽象方法,不可以实例化。

抽象类不能用final修饰。

抽象类的子类用extends"继承",接口的子类用implements"实现";

抽象类可以含有构造器,接口不行;

抽象类可以含有main方法(并且可以运行),接口不行;

子类可以实现多个接口,但只能继承一个抽象类;

接口的方法默认是public的,抽象类的方法可以是任意访问权限。

IO流的分类:

按功能分类:输入流、输出流;

按类型分类:字节流、字符流。

BIO,同步阻塞式IO,也是我们平时使用最多的IO,编程简单,并发性不好;

NIO,同步非阻塞式IO,Client和Server通过Channel通信,实现了多路复用;

AIO,异步非阻塞式IO,基于事件和回调函数实现。

List接口:有序存储,元素可以重复;

Set接口:无需存储,元素不可以重复。

ArrayList和LinkedList都实现了List接口。ArrayList底层使用了数组存储元素,LinkedList使用的是双向链表。

ArrayList底层使用数组存储元素,是数组的升级版,提供了数组所没有的一些方法,方便编程调用。

Map以键值对的形式存储数据,存储的数据是无序的,键不重复。

如何防止SQL注入?

1、使用PreparedStatement;

2、编程实现解析器,特殊字符进行转义。

使用CallableStatement可以调用数据库端的存储过程。

数据库连接池用于管理数据库连接,使多个线程可以交替使用预存的连接,不需要每次都重新与数据库建立连接(连接数据库是消耗系统时间的)。

数据连接池还可以关闭过多的空闲连接,以防止数据库端连接过多而造成的性能问题。

所以,使用连接池比每次都新建连接,性能要更占优势。

数据源技术:DBCP、C3P0。

使用数据源技术的好处:通过配置文件(而不是硬编码)维护数据库信息,修改数据库信息时,不需要重新编译源代码。

一个线程只能属于一个进程,而一个进程可以有多个线程。

同一个进程的所有线程可以共享进程的所有资源。

不同进程的线程通过消息通信的方式进行同步。

串行收集器和吞吐量收集器的区别:

吞吐量收集器使用并行版本的新生代收集器,用于中大型规模的程序,串行收集器对多数小应用就足够了。

采用字节码的好处:

消除了解释器的低效性,也保留了解释器的可移植性。

任何可以解释执行Java字节码的软硬件,都可以看做Java虚拟机。

包含static void main(String\[\] args) {}的类叫做Java主类,main不一定要是public的。

字符常量和字符串常量:

1、字符常量是单引号括起来的一个字符,字符串常量是双引号括起来的N个字符。

2、字符常量是一个无符号整型值,字符串常量是对内存的引用地址。

3、字符常量仅占用2个字节,字符串常量占用若干个字节(取决于字符串的长度)。

Java语言采用Unicode字符集,为每个字符指定了唯一的值。

构造器不能被override,因为构造器不能被继承,所以也就谈不上被重写。

构造器可以被overload,一个类中可以有多个构造器,这就是重载。

在类中定义一个无参构造器,如果该构造器里没有任何代码,则会默认调用父类的无参构造器。

如果父类没有无参构造器,就会编译报错。

这就是在一个类中定义无参构造器的原因。

import java和import javax的区别:

实际上java和javax没有区别,都是包名。

早期,java包下的类是标准API,javax下的类是非标准API。

随着后续版本的发布,javax也变成了标准API的一部分。

所以这是个历史遗留问题。

成员变量与局部变量的区别:

1、成员变量可以被访问限定修饰符修饰,也可以是static的,局部变量不行。

2、成员变量通常存储在堆中,而局部变量在栈中。

3、成员变量随着所属对象的创建而存在,而局部变量随着栈的退出而消亡。

4、不给成员变量赋初值,编译器会给出默认值,而局部变量没有初始值就被使用,编译器会报错。

构造器可以对对象进行初始化,可以没有构造器,没有构造器的类,在编译阶段,会被编译器强行添加一个无参构造器。

所以,实际上每个类其实都是有构造器的。

JDBC最佳实践:

1、批量插入和更新。

2、使用PreparedStatement防止SQL注入。

3、使用数据库连接池。

4、使用列名获取数据,而不是使用index。

不要这样重载:一个方法的参数是int,而另一个重载方法接受的参数是Integer。

不要这样重载:两个方法的参数个数一样,而只是参数类型不同。

如果方法的参数个数多于5个,使用可变参数。

DateFormat的所有子类,包括SimpleDateFormat,都不是线程安全的。

有两种方法把一个字符串解析为整数:

Integer.parseInt(s);

Integer.valueOf(s).intValue();

接口规定了功能模块的规范,在接口出现的位置,其实现类都可以出现。

因为接口的出现,可以为功能模块提供多种实现。

接口中没有具体方法,所以必然是抽象不可实例化的。

Java8中允许声明静态的默认方法,默认方法是具体的。

适配器模式用于接口转换,你的功能模块中有一种接口,而另一个功能模块有另一种接口。

为连接两个功能模块,需要实现一个适配器,来连接两种接口。

强制依赖使用构造器注入,可选依赖使用setter注入。

同样是把组件从代码中分离出来,依赖注入不关注被注入的对象是怎么来的,而工厂模式要通过工厂来获取需要的对象。

适配器模式用于桥接两个接口,而装饰器模式旨在不修改类的情况下,给类添加新的功能。

都是对真正执行操作的类进行封装。

适配器模式用于桥接两个接口,而代理模式是在原类的外部再套一层壳,以提供更多的功能。

开闭原则:

比如策略模式,如果需要新的策略,只需要实现接口,增加配置,不需要改变核心逻辑。

Serializable接口声明了一个类可序列化,是JVM内嵌的默认的序列化方式,不安全。

Externalizable允许你控制整个序列化过程,只能二进制格式,增加了安全机制。

DOM解析器会把整个XML文件载入内存,然后创建一棵DOM树,可以更快地查找和修改XML结构。

SAX解析器是基于事件的,不会直接完整加载XML文件。

DOM比SAX更快,并要求更大的内存配置,但不适合解析大的XML文件。

JDK7的4个新特性:

1、try-with-resource。

2、Fork-Join池,实现了Java版的Map-reduce。

3、Switch中允许使用字符串。

4、右侧不需要声明泛型的具体类。

JDK8的5个新特性:

1、lambda表达式,允许像对象一样船体匿名函数。

2、Stream API,充分利用多核CPU。

3、新的日期时间库。

4、接口可以有静态默认方法。

5、可以在一个类型上多次使用同一个注解。

Maven和ANT的区别:

都是Java构建工具,但Maven做的事情更多,比如提供标注的Java项目接口。

Maven还能够为应用程序提供自动依赖管理。

B/S架构:浏览器/服务器程序。

C/S架构:客户端/服务器程序,桌面应用程序。

常见网络协议:

HTTP:超文本传输协议。

FTP:文件传输协议。

SMPT:简单邮件协议。

TELNET:远程终端协议。

POP3:邮件读取协议。

Java的3个开发平台:

JavaSE:客户端开发。

JavaEE:web服务程序开发。

JavaME:在嵌入式领域使用。

Java中的常见数据结构:

线性表(ArrayList)

链表(LinkedList)

栈(Stack)

队列(Queue)

图(Map)

树(Tree)

Java的8种基本类型:byte、short、int、long、boolean、char、float、double。

使用BigDecimal可以解决浮点型运算产生的误差。

创建Java对象有2种方式:

1、new。

2、反射。

数组可以是volatile的,但是数组元素不受保护。

volatile型的long或double变量的读写都是原子的。

volatile变量提供顺序性和可见性保证,还能提供原子性。

一个线程的同步代码和2个线程的同步代码,复杂度相同。

因为同步代码与线程数量是相互独立的。

但是线程多了,需要合理选择同步技术,如锁分离。

wait()方法应该放在循环中执行,因为当前线程获取到CPU开始执行时,其它条件可能还没有满足。

所以在处理前,需要循环检测条件是否满足。

通过命令kill -3 PID(或Windows下的Ctrl + Break),JVM会将线程的dump文件打印到标注输出或错误文件中。

Swing不是线程安全的,不能通过多线程来更新Swing组件。

int类型可以强制转换为byte类型。

如果int值超出byte可表示的范围,会把int类型的高24位丢弃。

Cloneable是一个接口,不含有任何具体方法。

clone方法定义在Object中,且是一个本地方法。

++运算符不是线程安全的。

x = x + y 和 x += y 的区别:

+=运算符会隐式地将操作结果强转为持有结果的类型。

如果加法操作的结果比x的最大值大,则 x + y 会出现编译错误,x += y 没有这个问题。

3 * 0.1 == 3.0 返回false,因为有些浮点数不能精确表示。

Integer应该比int占用的内存更多,比如Integer要持有对象的元数据之类的。

Serial与Parallel GC的区别:

都会stop-the-world。

serial收集器默认是复制收集器,单线程。

parallel收集器是多线程的。

WeakReference,一旦失去最后一个强引用,就会被GC清理。

SoftReference,会延迟到JVM内存不足的时候才会被收集。

它们都有利于GC和内存效率。

WeakReference的工作方式:

与正常的HashMap类似,但是使用弱引用作为key。

当key没有更强的引用时,key/value会被回收。

JVM的选项-XX:+UseCompressedOops有什么用?

32位扩展到64位时,对象指针会占用更多内存,使用该选项可以压缩指针。

通过系统属性sun.arch.data.model或os.arch等,可以知道当前JVM是32位的,还是64位的。

理论上,32位JVM堆内存最大可以有2^32,即4GB;64位JVM可以有2^64的堆。

调用System.gc和Runtime.gc可以要求JVM进行垃圾回收,但无法保证立即执行。

Runtime.freeMemory():获取剩余空间的字节数。

Runtime.totalMemory():总内存的字节数。

Runtime.maxMemory():最大内存的字节数。

在JVM中,堆和栈属于不同的内存区域。

栈用于保存方法帧和局部变量,而对象总是分配在堆上。

栈通常远小于堆。

栈是属于线程的,不会在多个线程间共享。

堆被所有线程共享。

根据Java规范,失灵使用equals()方法,相等的对象,其hash code也一样。

但hash code一样,未必equals()方法返回true。

编译器常量是指我们程序中声明的公共静态不可变(public static final)的字段。

public是可选的。

编译器常量可能会存在如下问题:

编译器发现了程序中的编译器常量,会把他们内联到使用这些常量字段的位置。

如果编译器常量的声明在第三方包中,那么用新版本的第三方库的jar包。

你自己的class的文件中可能使用的还是老的常量值。

解决这个问题,需要重新编译你自己的源代码。

poll()和remove()都是从队列中取出一个元素。

但是poll()获取元素失败,返回null。

而remove()抛出异常。

PriorityQueue保证最高或最低优先级的元素总在队头。

LinkedHashMap内部维护数据的顺序是元素被插入的顺序。

但是遍历PriorityQueue时,没有任何顺序保证,LinkedHashMap有。

可以使用TreeSet或TreeMap来进行元素排序。

也可以使用List等,然后通过Collections.sort()来排序。

数组没有实现toString方法,所以直接把数组引用传给System.out.println()无法打印出数组的内容。

可以使用Arrays.toString()来打印每个元素。

也可以遍历数组,打印出每个元素。

TreeMap是使用红黑树实现的。

Hashtable是JDK1的遗留类,HashMap是后来加入的。

Hashtable是线程同步的,HashMap没有加同步。

Hashtable不接受空的key,HashMap允许。

HashSet内部使用HashMap实现,set的元素作为key,每个key都有一个默认的value。

HashSet只允许一个null元素。

在遍历ArrayList时,删除其中的一个元素:

使用Iterator遍历,然后调用Iterator中的remove方法删除指定的元素。

否则会触发ConcurrentModificationException异常。

使用实现了Iterable接口,就可以作为一个集合从而使用for-each循环。

实现Collection接口也可以。

ArrayList的默认容量是10,HashMap的默认容量是16。

Comparator与Comparable的区别:

Comparator是一个比较器(compare方法)。

而Comparable是定义了当前对象与其它对象的顺序(compareTo方法)。

byte\[\] bytes = new byte10;

ByteBuffer buf = ByteBuffer.wrap(bytes);

多线程最佳实践:

1、给线程命名,有利于调试。

2、指给关键部分做同步,减小颗粒度。

3、尽可能使用volatile,而不是synchronized。

4、使用更高层次的并发工具,而不是wait、notify来实现线程通信,比如CountDownLatch。

5、使用并发集合,而不是对集合进行同步。

Collections的最佳实践:

1、处于性能考虑,能使用ArrayList,就别使用Vector。

2、优先使用并发集合,而不是对集合进行同步,并发集合可扩展性好。

3、使用接口代表和访问集合,如List list = new ArrayList();

4、使用迭代器遍历集合。

5、使用泛型。

IO的最贱实践:

1、使用带缓冲区的IO类。

2、使用NIO和NIO2.

3、在finally块中关闭流,或使用try-with-resource。

4、使用内存映射文件获取更快的IO。

delete和truncata的区别:

1、delete可以选择性地删除某些数据,truncate只能删除整张表。

2、delete删除整张表的速度要低于truncate。

XML有几种解析方式:

1、DOM:读取整个文件,解析成树状结构,利于对节点做修改,适用于较小的文件。

2、Sax:基于事件的解析方式,速度快,适用于大型文件的解析。

SQL优化:

1、建立索引:在频繁检索、更新较少的字段上建立索引。

2、分表查询。

3、读写分离。

4、建立存储过程。

聚集索引和非聚集索引的区别:

聚集索引用于决定表中数据的物理存储顺序,一张表最多只有一个聚集索引。

聚集索引的字段尽量不要修改,否则数据的物理顺序会跟着一起调整。

通常主键就是聚集索引。

非聚集索引就是普通的索引,不会决定表的物理存储顺序。

一张表最多249个非聚集索引。

什么是事务:

单个逻辑块执行一系列操作,要么全部执行,要么全部不执行。

事务的特征:

1、原子性。

2、一致性。

3、隔离性。

4、持久性。

servlet的生命周期:

1、加载。

2、实例化。

3、初始化。

4、服务。

5、销毁。

函数必须要有返回值,存储过程不需要。

函数可以在select中直接使用,存储过程不行。

session.invalidate()语句可以使session失效。

ORM:对象关系映射。

Hibernate的SessionFactory是线程安全的。

Hibernate的Session是线程不安全的,可以通过ThreadLocal或调用sessionFactory.getCurrentSesssion()。

Hibernate中Session的load和get的区别:

查无记录,get方法返回null,load抛异常。

get直接返回实体类对象,load会包一层代理。

Hibernate管理的bean有3种状态:

1、瞬时态(transient)。

2、持久态(persistent)。

3、游离态(detached)。

瞬时态的实例通过save、persist、saveOrUpdate方法变成持久态。

游离态的实例通过update、saveOrUpdate、lock、relicate变成持久态。

MyBatis:

#把传入的数据当成参数处理,没有SQL语句注入的问题。

$是直接拼接字符串,有SQL注入的问题。

float x = 3.4; 不能编译通过,因为3.4是double型,不能直接赋值给x。

想赋值给x,需要这么做:

x = 3.4f; 或者 x = (float) x;

short s = 0;

s = s + 1; 编译报错,因为s + 1是int型,不能直接赋值给s。

s += 1; 没有问题。

Java保留了const和goto,但没有使用。

&是按位与,&&是逻辑与。

&不短路,&&短路。

switch不能用在long上。

数组有length属性,String有length()方法。

equals返回true,hashCode必须相同,否则不符合Java规范。

抽象方法不能是static的,也不能是native的,也不能是synchronized的。

抽象方法需要子类重写,而静态方法无法被重写,只能覆盖。

1、实现Cloneable接口并重写clone方法,可以进行对象克隆。

2、实现Serializable接口,并通过序列化和反序列化,可以实现真正的克隆。

一个.java文件里可以有多个类,但是最多只能有一个公开类。

这个公开类必须和文件名一致。

匿名内部类可以继承其它类或实现其它接口。

内部类可以访问它的外部类对象的成员,包括私有成员。

断言是一个包含布尔表达式的语句,如果表达式为false,会抛出AssertionError。

assert (a > 0);

常见运行时异常:

NullPointerException

ClassCastException

IllegalArgumentException

IndexOutOfBoundsException

方法上的synchronized是针对当前对象的,不是只针对这个方法的。

所以一个线程进入某对象的方法A时,其它线程连该对象的方法B也不能进入。

与线程同步以及线程调度有关的方法:

wait

sleep

notify

notifyAll

notify的死锁问题:

假设有两个消费者线程来消费队列里的任务,两个生产者线程来生产任务并放入队列。

假设队列的最大size为1。

两个消费者线程先执行,由于队列为空,所以阻塞并放弃锁。

第一个生产者线程被唤醒,往队列中放入一个任务,然后notify。

结果被唤醒的是第二生产者线程,由于队列已满,所以阻塞。

结果4个线程都被卡住了。

如果用notifyAll就没有这个问题。

Java中实现多线程的方式:

1、继承Thread类。

2、实现Runnable接口。

1、newSingleThreadExecutor:创建一个单线程的线程池。

2、newFixedThreadPool:创建固定大小的线程池。

3、newCachedThreadPool:创建一个可缓存的线程池,线程可部分回收。

4、newScheduledThreadPool:创建一个大小无限的线程池。

Lock能完成synchronized所实现的所有功能。

Lock有比synchronized更精确的线程语义和更好的性能,且不强制性要求一定要获得锁。

synchronized会自动释放锁,Lock要求开发人员手动释放锁。

XML的文档定义形式:

1、DTD。

2、Schema。

Schema本身也是一个XML文件,可以被XML解析器解析。

对XML的解析主要有DOM、SAX、StAX。

提升读取数据的性能,可以通过ResultSet的setFetchSize方法批量抓取数据。

提升更新数据的性能,可以通过PreparedStatement批量更新。

JDBC中如何处理事务?

Connection提供了事务处理的方法。

调用setAutoCommit(false)可以设置手动提交事务。

调用commit()提交事务。

调用rollback()回滚事务。

调用savepoint()方法设置回滚点。

获取类对象的方法:

1、.class。

2、.getClass。

3、Class.forName()。

JVM内存模型:

根据JVM规范,JVM内存分为程序计数器、堆、栈、方法区、本地方法栈。

元空间存储的是类的元数据信息。

元空间和永久代最大的区别是:元空间不在虚拟机中,而是使用本地内存。

栈帧包括:

1、局部变量表。

2、操作数栈。

3、动态链接。

4、方法返回地址。

类的实例化顺序:

先静态,先父后子。

父静态变量->子静态->父类->子类静态代码块->非静态代码块->构造函数。

对象在from区和to区来回复制15次,如果还存活,就转存到老年代。

如果对象的尺寸大于Eden区的二分之一,会直接分配到老年代,如果老年代不够,会进行一次majorGC。

如果小于Eden的一半,但是又没有足够空间,会执行一次minorGC(新生代GC)。

minorGC后,survivor仍旧放不下,则放到老年代。

full gc 频繁,排查步骤:

1、perm gen没有足够空间时,会触发full gc,所以先看看perm gen是不是太小了。

2、minor gc后晋升到老年代的对象平均尺寸大于老年代剩余空间时,会触发full gc。

可能是eden去设置过小。

可能是大对象太多,很多数据被直接分配在老年代。

可能是老年代尺寸太小。

通过定义自己的ClassLoader,并重写父类的loadClass方法来打破双亲委派模式。

服务提供发现(SPI)也是打破双亲委派模式的例子。

新创建的对象在新生代存不下的时候,执行minorGC。

三种最基础的GC算法:

1、标记清理法。

2、复制算法。

3、标记压缩算法。

4、分代收集算法。

6种垃圾收集器:

1、Serial收集器。

2、ParNew收集器:多线程版本的Serial收集器。

3、Parallel收集器,类似于ParNew,关注吞吐量。

4、Parallel Old收集器,是Parallel Scavenge收集器的老年代版本,使用标记整理算法。

5、CMS收集器,标记清除算法,会产生大量的内存碎片。以获取最短停顿时间为目标。会消耗额外的CPU和内存资源。

6、G1收集器。面向服务器的收集器(多核大内存),旨在减少停顿时间的同时,提供吞吐量。

根加载器、扩展类加载器、系统类加载器、自定义类加载器。

JVM内存模型:

1、方法区,存储类信息、常量、静态变量等。

2、堆,存放对象实例。

3、栈,存储局部变量表、操作数栈、动态链接、方法出口等。

4、本地方法栈,为native方法服务。

5、程序计数器,下一条要执行的指令的行号。

引用计数法、可达性分析。

GC Roots:

1、栈中引用的对象。

2、方法区类静态属性引用的对象。

3、方法区常量池引用的对象。

4、本地方法栈引用的对象。

吞吐量收集器是serial收集器的并行版本,用于大型程序,serial用于小型程序。

运行时数据区:

虚拟机在执行Java程序的过程会把内存划分为不同的数据区:

线程私有的:程序技术区、栈、本地方法栈。

线程共享的:堆、方法区。

运行时常量池是方法区的一部分。

直接内存不属于运行时数据区,也不是虚拟机规范定义的内存区域。

NIO基于通道与缓冲区,它可以使用native方法直接分配堆外内存。

避免了Java堆和native堆来回复制数据。

直接内存不受Java堆大小的限制。

对象的内存布局:

对象在堆中的存储布局可分为对象头、实例数据、对齐填充。

对象头占12字节,包括对象标记和类型指针。

对象标记存储哈希码、GC分代年龄、锁标志、偏向线程ID等,占8字节,称为Mark Word。

类型指针是对象的元数据的指针,占4字节。

实例数据是对象的有效信息。

对齐填充,如果对象实例数据没有对齐,需要补全。

对象的访问方式有句柄和直接指针两种。

任一类都必须由类加载器和这个类本身共同确立其在虚拟机中的唯一性。

两个类只有由同一个类加载器加载才有比较意义。

否则即使两个类来源于同一个class文件,只要类加载器不同,这两个类就必定不相等。

并非可达就一定会存活,还要看引用的类型,软引用、弱引用、虚引用的对象是会被垃圾回收的。

如何查看JVM的系统默认值?

-XX:+PrintFlagsFinall参数可以看到参数的默认值。

-Xms:初始化内存。

-Xmx:最大分配内存。

-Xss:线程栈大小。

CPU过高,如何定位问题?

1、top -H命令查看CPU最高的线程ID,转16进制。

2、jstack命令获取栈信息,搜索这个16进制,附近很可能有具体原因。

GC日志里的real、user、sys是什么意思?

real:从开始到结束所花费单时间。

user:进程在用户态所花费的时间。

sys:进程在核心态花费的时间。

字符串常量存放在哪个区域?

1、字符串常量池(JDK8之前是perm区,之后放到了堆上)。

2、类文件常量池,在元数据区。

老年代一般用标记清除算法、标记整理算法,年轻代一般用复制算法。

对象分配在堆区,没有逃逸出方法的对象也可能分配在栈中。

JVM中的常量池:

1、字符串常量池,存储在堆中。

2、运行时常量池,存储在方法区,属于元空间。

3、类文件常量池。

JDK8之前,方法区的实现是永久代。

JDK7把永久代中的常量池、静态变量移到了堆中。

JDK8移除永久代,使用元空间,元空间分配在本地内存中。

JVM内存模型:

JVM定义了统一的内存模型,将各种底层硬件已经操作系统的内存访问差异就行封装。

使Java程序可以在不同环境上运行。

JVM中分工作内存和主内存,线程无法直接操作主内存。

线程间通信,只能通过主内存进行消息交换。

排查内存溢出:

1、加参数,当内存溢出时,自动dump堆内存到指定目录。

2、jstat查看JVM的内存和GC情况。

3、使用MAT工具载入dump文件,分析内存占用情况。

堆外内存溢出:

Unsafe类申请内存、JNI对内存进行操作、Netty调用操作系统的malloc,

这些内存不受JVM控制,需要指定大小,否则容易溢出。

如何定位线程死锁?

使用jstack命令dump出JVM的线程信息:

jstack -F -I <pidthreads.txt

如果存在死锁,一般文件里可以找到deadlock的数量与线程信息。

Lambda表达式就是通过invokedynamic指令实现的,使用方法句柄实现。

JVM类加载过程:

1、加载,读取二进制流,转换成Class对象。

2、验证,文件格式验证,元数据验证,字节码验证。

3、准备,为静态变量分配内存,赋默认值。

4、解析,符号引用转直接引用。

5、初始化,为静态变量赋初始值。

MyBatis的编程步骤:

1、创建SQLSessionFactory。

2、创建SQLSession。

3、通过SQLSession执行数据库操作。

4、调用commit提交事务。

5、调用close关闭会话。

调用mapper接口时有那些要求:

1、Mapper接口方法名必须与Mapper.xml中定义的SQL的id相同。

2、Mapper接口方法的参数类型和xml文件中的每个sql参数类型要一致。

3、Mapper接口的返回值类型要与xml中定义的一致。

4、xml中的namespace必须是Mapper接口的类路径。

MyBatis的一级缓存:

一级缓存就是SQLSession,MyBatis默认开启一级缓存。

在同一个SQLSession中,执行相同的语句,第一次会查库并缓存起来,第二次就直接从缓存中取。

发生了增删改查操作,会清空缓存。

MyBatis的二级缓存:

二级缓存是mapper级别的,默认不开启二级缓存。

第一次调用mapper去查询,查到的数据会存放到该mapper对应的二级缓存。

第二次调用相同sql,回去对应的二级缓存内取结果。

MyBatis分页:

需要手动编写SQL进行分页(真分页)。

MyBatis动态SQL标签:

trim

where

set

foreach

if

choose

when

otherwise

bind

MyBatis支持延迟加载。

原理是使用CGLIB创建目标对象的代理对象。

MySQL存储引擎:

1、MyIsam。

2、InnoDB。

3、Memory。

默认存储引擎是InnoDB,使用B+树存储数据。

使用场景:

1、经常更新的表,适于处理多重并发的更新请求。

2、支持事务。

3、可以通过bin-log恢复数据。

4、支持外键。

5、支持列值自增。

创建索引的原则:

1、为需要排序、分组的列创建索引。

2、为作为查询条件的列创建索引。

3、限制索引数量,索引过多降低更改效率。

4、最左前缀匹配。

5、为区分度高的列创建索引。

6、不要在索引列上使用表达式或函数。

SQL语句前加explain关键字,可以查看SQL语句是否使用了索引。

1、like以%开头索引无效,以&结尾索引有效。

2、or语句,只有前后列均为索引列,索引才有效。

3、使用is not null,索引无效。

4、使用not、<>、!=时,索引无效。

5、索引列位于表达式或函数中时,索引无效。

alter table table_name add index index_name(column1, column2, ...);

与哈希索引比,B+树更适于区间查询。

哈希索引无法完成排序,B+树可以。

数据重复厉害的时候,哈希索引效率下降。

聚簇索引和非聚簇索引的区别:

聚簇索引的页子节点存的是整行数据,非聚簇索引存的是主键,需要在通过主键查询具体数据(也叫回表)。

非聚簇索引也可以不回表。

比如一个索引:idx_a(column1, column2)。

如果select语句中的列只有column1和column2,则不需要回表。

索引下推原则可以减少回表次数。

1、超键,能唯一标识元素的属性集。

2、候选键,最小超键,即没有冗余元素的超键。

3、主键。

4、外键,指向另一个表的主键。

SQL约束:

1、not null。

2、unique。

3、primary key。

4、foreign key。

5、check。

datetime和timestamp的区别:

1、datetime的范围是1001~9999,timestamp是1970~2038。

2、datetime与时区无关,timestamp与时区有关。

3、datetime占8字节,timestamp占4字节。

4、datetime默认值是null,timestamp默认系统当前时间。

tinytext:256字节。

text:65535字节(64KB)。

mediumtext:16777215字节(16M)。

longtext:4294967295字节(4GB)。

1、from

2、where

3、join

4、on

5、group by

6、having

7、select

8、distinct

9、union

10、order by

11、limit

ref值的是使用了普通的索引。

range对索引进行范围检索。

index索引物理文件全扫描,比range还慢。

select * from table where age > 20 limit 1000000, 10; 可以优化为:

select * from table where id in(select id from table where age > 10 limit 1000000, 10);

1、开启慢查询日志。

2、配置项:slow_query_log。

3、在datadir下产生一个xxx-slow.log的文件。

4、设置临界时间。

5、配置项:long_query_time。

一旦SQL执行时间超过临界时间,就会被记录到xxx-slow.log中。

Netty的使用场景:

1、作为RPC框架的网络通信工具。

2、实现自己的HTTP服务器。

3、实现即时通讯系统。

4、实现消息推送系统。

Netty的核心组件有哪些?

1、Channel接口。

包括了基本的IO操作,如bind、connect、read、write。

2、EventLoop接口。

用于处理网络连接的生命周期中所发生的事件。

并负责调用事件处理器进行相关IO操作的处理。

3、ChannelFuture。

Netty是非阻塞的,所有的IO操作都是异步的。

4、ChannelHandler和ChannelPipelin。

ChannelHandler是消息的具体处理器。

ChannelPipeline为ChannelHandler的链,提供了一个容器并定义了沿着链入站和出站事件流的API。

当Channel被创建时,它会被自动分配到专属的ChannelPipeline。

EventLoopGroup和EventLoop的关系:

EventLoopGroup包含多个EventLoop。

EventLoop处理的IO事件都将在它专属的Thread上被处理,是线程安全的。

Bootstrap是客户端的启动类。

EventLoopGroup group = new NioEventLoopGroup();

Bootstrap b = new Bootstrap();

b.group(group)...

ChannelFuture f = b.connect(host, port).sync();

f.channel().closeFuture().sync();

ServerBootstrap是服务端的启动类。

ServerBootstrap b = new ServerBootstrap();

b.group(bossGroup, workerGroup)...;

ChannelFuture f = b.bind(port).sync();

f.channel().closeFuture().sync();

NioEventLoopGroup默认的构造函数会启动的线程数为2*CPU核心数。

Netty是靠NioEventLoopGroup线程池来实现线程模型的。

实现服务端的时候,会初始化两个线程组:

1、bossGroup:接收连接。

2、workerGroup:负责具体的IO处理,交由对应的handler处理。

通过Netty实现心跳机制的话,核心类是IdleStateHandler。

Netty中的零拷贝:

1、CompositeByteBuf类可以将多个ByteBuf合并成一个逻辑上的ByteBuf。

2、ByteBuf支持slice操作,可以将ByteBuf分解为多个共享同一个存储区域的ByteBuf。

3、通过FileRegion包装的FileChannel.transferTo实现文件传输,可直接将文件缓冲区的数据发送到目标Channel。

Netty的高性能表现在那些方面:

1、同步非阻塞。

2、内存零拷贝。

3、申请的内存可以重用,比如直接内存。

4、串行化读写,避免上锁的开销。

5、高性能序列化协议,支持protobuf。

Netty有两种发送消息的方式:

1、直接写入Channel中。

2、写入ChannelHandlerContext总。

NIO Epoll会导致Selector空轮询,最终导致CPU 100%。

Netty对Selector的select操作周期进行统计。

每完成一次空的select操作进行一次计数。

在某个周期内连续发生N次空轮询,则判定触发了Epoll死循环bug。

IdleStateHandler定时检测是否空闲,还会发送心跳。

多次心跳失败,会关闭现有资源,并重新发起连接。

Spring Framework有哪些功能:

1、IOC,控制反转。

2、AOP,将业务功能和系统服务分离。

3、创建和管理对象的容器。

4、MVC,对web应用提供了高度可配置性。

5、事务管理。

6、JDBC异常处理功能。

Spring Framework有哪些模块:

1、Spring核心容器。

2、Spring Core。

3、Spring Bean。

4、SpEl。

5、Spring Context。

Spring Bean支持的5种scope:

1、singleton,每个IOC容器一个实例。

2、prototype,每个请求一个实例。

3、request,每次http请求一个实例。

4、session,每次http请求一个实例,该实例仅在当前session有效。

5、global-session。

Spring Bean容器的生命周期:

1、根据配置实例化bean。

2、使用依赖注入填充所有属性。

3、如果bean实现了BeanNameAware接口,调用setBeanName。

4、如果bean实现了BeanFactory接口,调用setBeanFactory。

5、如果存在与bean关联的BeanPostProcessors,调用preProcessBefopreInitialization。

6、调用bean的init方法。

7、如果存在与bean关联的BeanPostProcessors,调用PostProcessAfterInitialization。

8、如果bean实现了DisposableBean接口,当容器关闭时,调用destory。

9、如果为bean指定了destory方法,调用它。

只有将bean用作另一个bean的属性时,才能将bean声明为内部bean。

内部bean总是匿名的,总是作为原型。

容器默认未开启注解装配,通过<context:annotation-config/>启动。

1、@Component。

2、@Controller。

3、@Service。

4、@Repository。

@Required,应用于bean属性setter方法。

@Autowired,类型驱动的注入。

@Qualifier,区分多个相同类型的bean,消除歧义。

Spring DAO使得JDBC、Hibernate、JDO这样的数据访问技术可以以一种统一的方式工作。

Bean生命周期方法:

1、setup,容器加载bean的时候调用。

2、teardown,容器卸载类的调用。

bean标签有两个对应的属性init-method和destroy-method。

也有相应的注解:@PostConstruct和@PreDestory。

不同方式的自动装配:

1、byName,通过参数名装配。

2、byType,通过参数类型装配。

3、constructor,类似于byType,但是要提供给构造器参数,失败抛异常。

4、autodetect,首先尝试constructor装配,失败则改为byType装配。

自动装配的局限性:

1、仍需配置来定义依赖。

2、基本数据类型无法装配。

3、自动装配不如显式装配精确。

可以在Spring中注入null和空字符串。

@Required注解:

表明bean的属性在配置的时候设置,未被设置则抛异常。

@Autowired注解:

控制在何处以及如何完成自动装配。

@Qualifier注解:

有多个相同的bean,却只有一个需要自动装配的时候,配合@Autowired注解消除这种混淆。

spring的事务管理有哪些优点:

1、为不同的API(JDBC、Hibernate等)提供统一的编程模式。

2、支持声明式事务管理。

声明式事务管理要由于编程式事务管理。

最常用的BeanFacotory实现是XmlBeanFactory。

什么是SpringBoot?

用来简化spring应用的初始搭建和开发过程。

main方法运行,

嵌入Tomcat,无需部署war文件。

简化maven配置。

SpringBoot的核心注解:

1、@SpringBootConfiguation,组合了@Configuration注解,实现配置文件的功能。

2、@EnableAutoConfiguration,打开自动配置功能。

3、@Component,spring组件扫描。

什么是JavaConfig?

1、面向对象的配置。一个配置类可以继承另一个,重写它的@Bean方法等。

2、减少或消除XML配置。JavaConfig提供了纯Java方法来配置XML概念相似的spring容器。

3、类型安全和重构友好。由于泛型的支持,可以按类型而不是名称检索bean。不需要强制转换或基于字符串的查找。

bootstrap.yml和application.yml的区别:

1、springcloud构建于springboot之上,在springboot中有两种上下文,一种是bootstrap,一种是application。

2、application用于springboot项目的自动配置。

3、bootstrap是父上下文,优先于application加载。

4、bootstrap主要从额外的资源来加载配置。

5、两个上下文共用一个环境。

6、bootstrap优先加载,默认不能被本地配置覆盖。

7、bootstrap里面的属性不能被覆盖。

springboot常用的starter:

1、spring-boot-starter-web。

2、spring-boot-starter-data-jpa。

3、spring-boot-starter-data-redis。

4、spring-boot-starter-data-solr。

5、mybatis-spring-boot-starter。

springboot配置加载顺序:

1、properties文件。

2、yaml文件。

3、系统环境变量。

4、命令行参数。

SpringBoot有哪几种读取配置的方式?

1、@PropertySource。

2、@Value。

3、@Environment。

4、#ConfigurationProperties。

SpringBoot通过实现一个ControllerAdvice类,来处理控制器类抛出的所有异常。

如何重新加载springboot上的更改,而不需重启服务器?

使用DEV工具实现。

springboot有一个Dev Tools模块,可以重新加载springboot上的更改,而无需重启服务器。

该模块在生产环境中将禁用。

springboot监视器是什么?

spring boot actuatorspring是启动框架中的重要功能。

监视器可以访问生产环境中正在运行的应用程序的状态。

监视器模块公开了一组可以通过http访问的接口来检查状态。

通过application.properties中可以指定服务端口:

server.port=8080

如何在springboot中禁用actuator端点安全性?

默认所有敏感http端点都是安全的,只有具有http actuator角色的用户才能访问。

可以使用management.security.enabled=false来禁用安全性。

什么是spring batch?

提供可重用的函数,包括日志/跟踪,事务管理,作业处理统计信息等。

通过优化和分区,可实现极高批量处理。

开启springboot特性有哪几种方式?

1、继承spring-boot-starter-parent项目。

2、导入spring-boot-dependencies项目依赖。

如何集成springboot和activemq?

添加spring-boot-starter-activemq,并添加一些配置。

swagger用于可视化api,为前端开发人员提供在线沙箱。

用于生成restful web服务的可视化表示工具、规范和完整框架实现。

springboot通过使用@ImportResource注解导入老的spring项目,从而兼容老的spring项目。

springboot的核心配置文件是application和bootstrap。

bootstrap配置文件有以下几个应用场景:

使用spring cloud config配置中心时,需要在bootstrap中添加连接到配置中心的配置属性来加载外部配置中心的配置信息。

一些固定的不能被覆盖的属性。

一些加解密的场景。

springboot有.properties和.yml两种格式。

springboot启动类上的注解是@SpringBootApplication,也是springboot的核心注解。

主要包含3个注解:

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan

开启springboot特性有两种方式:

继承spring-boot-starter-parent项目。

导入spring-boot-dependencies项目依赖。

springboot的最大优势是约定优于配置。

springboot starter的工作原理:

1、启动时会去依赖的starter包中寻找resources/META-INF/spring.factories文件,根据文件配置寻找项目所依赖的jar包。

2、根据spring.factories配置加载AutoConfigure类。

3、根据@Conditional注解的条件,进行自动配置并将bean注入spring context。

使用springboot集成Aatomikos来支持分布式事务,也可以通过消息的补偿机制来处理分布式的事务。

cas和oauth是解决单点登录的组件。

shiro负责权限安全方面的工作。

所以就有cas+shiro或者oauth+shiro这样的组合。

spring cache常用缓存注解:

1、@Cacheable,声明方法返回值是可缓存的,后续参数不变时,调用方法,数据直接从缓存提取。

2、@CachePut,不会从缓存取,但是每次都会往缓存写。

3、@CacheEvict,标注的类的每个方法都会触发缓存清除操作。

JPA是一种ORM规范,只提供了一些相关的接口,不能直接使用。

Hibernate是JPA的一个实现集。

JPA实现动态SQL,需要动态构建实体类。

springboot是为了让开发者更简单地使用spring框架,而不是替代它。

springcloud是一系列框架的集合,利用springboot简化了分布式系统基础设施的开发。

如服务发现、配置中心、消息总线、负载均衡、断路器、数据监控等。

什么是spring initializer?

它是一个网络应用程序,可以帮助开发者生成一个springboot项目,正确构建项目目录结构。

springboot提供了哪些核心功能?

1、独立运行spring项目。

2、内嵌servlet容器。

3、starter简化maven配置。

4、自动配置spring bean。

5、应用监控。

springboot自动配置的原理:

在main方法中添加@SpringBootApplication。

会自动去maven中读取每个starter中的spring.factories文件,该文件里配置了所有需要被创建spring容器中的bean。

springboot自动配置原理:

1、启动时加载主配置类,开启自动配置功能@EnableAutoConfiguration。

2、@EnableAutoConfiguration作用:

将META-INFO/spring.factories里配置的所有值加入到容器中。

每一个这样的xxxAutoConfiguration类都是容器中的组件,都加入到容器中,用它们来自动配置。

3、每一个自动配置类进行自动配置。

4、一旦这个配置类生效,就会给容器中添加各种组件。

5、所有在配置文件中能配置的属性都是在xxxAutoConfiguration类中封装着,配置文件能配置什么就可以参照某个功能对应的这个属性类。

怎么用好自动配置?

1、springboot启动会加载大量自动配置类,看我们需要的功能有没有springboot默认写好的自动配置类。

2、再看这个自动配置类中到底配置了哪些组件,只要已经有我们需要的组件,就不需要我们自己配置了。

3、给容器中添加自动配置类时,会从properties文件中读取某些属性值,我们可以在配置文件中指定这些属性值。

如何给静态变量赋值?

springboot无法通过@Value给静态变量赋值。

需要给当前类加@Component注解,通过set方法设置@Value注解。

什么是微服务?

1、微服务是一种架构风格。

2、大型复杂软件应用由多个微服务组成。

3、是一种松耦合的能够被独立开发和部署的无状态化服务(独立扩展、升级和可替换)。

微服务之间是如何通信的?

1、Dubbo使用的二进制RPC通信。

2、springcloud使用的是HTTP RESTFul方式。

什么是服务熔断?

如果频繁超时,就把consumer调用provider的请求,直接短路掉。

不实际调用,而是直接返回一个mock的值。

什么是服务降级?

consumer端:consumer如果发现某个provider出现异常情况(比如超时),这时,consumer就可以降级provider的逻辑,直接返回固定的值。

provider端:发现流量激增时,为了保护自身稳定性,也可以降级服务。

1、直接给consumer返回固定数据。

2、需要写数据库的,先缓存到队列,异步写入数据库。

微服务的优点:

1、每个微服务仅负责自己业务领域的功能。

2、微服务是一个独立的实体,可以独立部署、升级、通信。

3、易于维护。

4、简化部署。

5、横向扩展。

6、技术异构。

微服务的缺点:

1、复杂度高:无法利用数据库本身的事务机制来保证一致性。

2、运维复杂:需要设计监控系统对各个微服务进行监控。

3、通信延迟。

要确保Hystrix超时时间要长于Ribbon超时时间。

微服务技术栈:

1、服务网关Zuul。

2、服务发现Eureka+Ribbon。

3、服务配置中心Apollo。

4、限流熔断和流聚合Hystrix/Turbine。

Zookeeper和Eureka的区别:

Zookeeper保证CP,一致性和分区容错性。

Eureka保证AP,可用性和分区容错性。

eureka服务注册与发现原理:

1、每30秒发送心跳检测重新进行租约,如果多次不能更新租约,90秒后被移出服务注册中心。

2、注册信息会被复制到其他Eureka节点,每30秒复制一次。

3、由于客户端有缓存,即使Eureka全部当掉,客户端还是可以定位服务地址。

springcloud限流:

漏铜算法。

令牌桶算法。

springcloud的核心组件:

1、Eureka。

2、Ribbon:基于Ribbon做负载均衡,从一个服务的多台机器中选择一台。

3、Feign:根据注解和选择的机器,拼接URL,发情请求。

4、Hystrix。

5、Zuul:网关,前端调用后端,统一从Zuul走,由Zuul转发请求到对应的服务。

Eureka的缺点:

某个服务不可用,需要1到3个心跳,Eureka client才能知道。

使用Hystrix的熔断降级可以缓解这个问题。

eureka的缓存机制:

第一层缓存:是一个JVM的只读缓存,主要是为了供客户端获取注册信息时使用,30秒更新一次。

第二层缓存:最终缓存,服务下线等,都会清除这个缓存。

每30秒执行一次定时任务,去服务端获取注册信息,获取之后,存入本地内存。

熔断原理,以及如何恢复?

服务健康状况 = 请求失败数 / 请求总数

熔断与否,是通过服务的健康状况和设定的阈值比较决定的。

熔断器能在一段时间后继续监测请求执行结果,提供恢复服务调用的可能。

服务雪崩:

因服务提供者不可用导致调用者不可用,并将不可用逐渐放大的过程。

多个消费者调用同一接口,eureka默认使用轮询策略分配流量。

springcloud实现服务注册发现的原理是什么?

服务发布时,指定服务名,将服务注册到注册中心。

调用方法时,传递服务名,通过服务注册中心获取可用实例,通过负载均衡(Ribbon和Feign)调用对应的服务。

断路器的3种状态:

1、完全打开:一定时间内,达到一定次数的无法调用,多次检测无法恢复,断路器就完全打开了。

2、半开:短时间有恢复迹象,断路器允许部分请求通行,当能正常调用时,断路器关闭。

3、关闭:服务一直可以正常调用,断路器关闭。

eureka和Zookeeper的区别:

1、zookeeper有leader和follower角色,eureka各节点平等。

2、Zookeeper采用半数存活原则、eureka采用自我保护机制,解决分区问题。

3、eureka是一个工程,而zookeeper是一个进程。

4、eureka保证AP,zookeeper保证CP。

服务网关的作用:

1、简化客户端调用复杂度,统一处理外部请求。

2、根据不同的接口,对数据加工后对外。

3、这对不同的客户端,提供不同的网关支持。

4、可以作为新老系统的中转组件。

5、统一处理调用过程中的安全、权限问题。

链路跟踪Sleuth:

每次链路请求都会添加一串追踪信息,格式是server-name, main-traceId, sub-spanId, boolean

1、server-name:服务节点名称。

2、main-traceId:一条链路的唯一ID。

3、sub-spanId:链路中每一环的ID。

4、boolean:是否将信息输出到Zipkin等服务收集和展示。

Sleuth的实现是基于HTTP的,为了不影响业务,会在每个请求的header上添加追踪需要的重要信息。

什么是spring cloud bus?

spring cloud bus提供了跨多个实例刷新配置的功能。

spring cloud conifg:集中配置管理工具,默认使用git来存储配置,可以支持客户端配置的刷新及加解密操作。

spring cloud stream:轻量级事件驱动微服务框架,可以使用简单的声明式模型来发送及接收消息,主要实现为Kafka及RabbitMQ。

微服务架构的优点:

1、独立开发。

2、独立部署。

3、故障隔离。

4、混合技术栈。

5、粒度缩小。

微服务的特点:

1、解耦。

2、组件化。

3、专注于单一功能。

4、持续交付。

5、分散治理。

6、敏捷。

微服务的缺点:

1、增加故障排除的难度。

2、网络延迟。

3、难以保持事务一致性。

Ribbon底层实现原理:

使用discoveryClient从注册中心读取目标服务信息。

对同一接口请求进行计数,取模获取目标服务。

使用@LoadBalanced注解开启客户端负载均衡。

Hystrix的四种防雪崩方式:

1、服务降级,调用失败就返回一个空。

2、服务熔断,调用失败就调用提前定义好的一个熔断方法,返回错误信息。

3、服务隔离。

4、服务监控,记录调用出现的问题的详细信息。

Ribbon和Feign的区别:

调用方式不同。

Ribbon需要自己构建http请求,然后通过RestTemplate发给服务。

Feign实在Ribbon基础上进行的一次改进,采用接口的形式调用。

什么是spring cloud bus?

spring cloud bus就像一个分布式执行器,用于扩展springboot的配置文件,也可以用作程序之间的通信通道。

spring cloud bus不能独立完成通信,需要配合MQ。

spirng cloud bus一般是配合spring cloud config做配置中心的。

spring cloud bus实时刷新也必须采用spring cloud bus消息总线。

什么是spring cloud config?

为分布式系统中的外部配置提供服务器和客户端支持。

可以方便地对微服务各个环境下的配置进行集中式管理。

分为Config Server和ConfigClient。

Server负责读取配置文件并暴露http接口。

Client通过调用Server的接口来读取配置文件。

有哪些分布式配置中心?

1、Apollo。

2、zookeeper。

3、spring cloud config。

spring cloud config实时刷新采用spring clooud bus消息总线。

什么是spring cloud gateway?

spring cloud gateway是官方推出的第二代网关框架,取代Zuul网关。

spring cloud consul用于实现分布式系统的服务发现与配置,是一站式方案,内置了服务注册与发现框架、分布式一致性协议实现、键值存储。

不再依赖zookeeper等其它工具。

kafka将消息以topic为单位进行归纳。

向kafka发送消息的一方称为生产者。

预定topic并获取消息的一方称为消费者。

kafka以集群的方式运行,每个服务叫做一个broker。

生产者通过网络将消息发送给kafka集群,集群向消费者提供消息。

数据传输的事务定义有3个级别:

1、最多一次,消息最多被传输一次,不会重复发送。

2、最少一次,消息不会漏发,最少被传输一次,也可能重复传输。

3、仅仅被传输一次。

kafka通过2个条件判定一个节点是否还活着:

1、节点必须可以维护和zookeeper的连接。

2、

3、节点如果是follower,,它必须能即使同步leader的写操作,不能延时太长。

生产者直接将数据发送给leader,不需要在多个几点进行分发。

kafka的磁盘消息格式:

消息由一个固定长度的头部和可变长度的字节数组构成。

1、消息长度,4字节。

2、版本号,1字节。

3、CRC校验码,4字节。

4、具体的消息,N字节。

kafka高效文件存储设计特点:

kafka把topic中一个分区大文件分成多个小文件段。

通过多个小文件段,就可以很容易地定期清除已消费完的文件,减少磁盘占用。

通过索引可以快速定位message和确定response的最大大小。

通过索引元数据全部映射到内存,可以避免segment file的磁盘IO。

通过索引文件稀疏存储,可以大幅降低索引文件元数据占用的空间。

kafka与传统消息系统之间的3个关键区别:

1、kafka持久化日志,这些日志可以被重复读取和无限期保留。

2、kafka是分布式系统,可以灵活伸缩,通过复制数据提升容错性和可用性。

3、kafka支持实时流的流式处理。

启动kafka集群之前,要设置好log.dirs参数,这个参数就是存放分区的目录。

这个参数可以指定多个目录,用逗号分隔。

kafka生产数据时,数据的分组策略:

1、生产者决定数据产生到集群的哪个分区中。

2、每一条消息都是键值对格式。

3、键是由生产者发送数据传入的。

4、生产者键决定了数据产生到集群的那个分区。

如何获取topic主题的列表:

bin/Kafka-topics.sh --list --zookeeper localhost:2181

zookeeper在kafka中,被用于提交偏移量,因此如果节点失败了,可以从之前提交的偏移量中获取。

kafka如何保证消息的顺序消费?

kafka分布式的单位是分区,同一个分区可以保证FIFO的顺序。

kafka如何不消费重复数据?

这个问题还是要结合具体情况。

比如拿到数据要写库,那么可以先到数据库中核对一下,如何已存在这条消息,则update,而不是insert。

什么是消费者组?

消费者组是kafka独有的。

每个kafka消费群体都由一个或多个共同消费一组订阅主题的消费者组成。

绕过zookeeper直接连接到kafka是不可能的。

kafka可以接收的最大消息大约1000000字节。

单点登录的运行机制:

当用户第一次访问应用系统1的时候,因为还没有登录,会被引导到认证系统中进行登录【1】

根据用户提供的登录信息,认证系统进行身份效验,如果通过效验,应该返回给用户一个认证的凭据ticket【2】

用户再访问别的应用的时候,就会将这个ticket带上,作为自己认证的凭据,应用系统接受到请求之后会把ticket送到认证系统进行效验,检查ticket的合法性

如果通过效验,用户就可以在不用再次登录的情况下访问其它应用系统

什么CSRF攻击?

跨站请求伪造。

什么是WebSocket?

WebSocket是一种计算机通信协议,通过单个TCP连接提供全双工通信信道。

1、WebSocket是双向的,服务端和客户端都可以发送消息。

2、WebSocket是全双工的,客户端和服务器通信是相互独立的。

3、初始连接使用HTTP,然后升级到基于套接字的连接,这个套接字用于所有未来的通信。

4、轻量级,与http相比,WebSocket消息交换要轻得多。

幂等性指的是:重复执行一项任务,但最终结果保持不变或类似。

幂等性主要用作数据源或远程服务,当它接收一组以上的指令时,它只处理一组指令。

from

on

join

where

group by

having

select

distinct

order by

limit

持续集成(CI)是团队成员提交版本控制更改时自动构建和测试代码的过程。

Elasticsearch数据索引的流程:

1、协调节点默认使用文档id做路由分配。

2、refresh,分片接收到协调节点发来的数据,会写入缓存,再每隔一秒写入文件系统缓存。

3、flush,写入文件系统缓存的同时,也会写入translog,以避免数据丢失,默认每30分钟(或translog太大)将数据写入磁盘后。

在flush的过程中,缓存会被清空,内容被写入一个新的段中,并刷新到磁盘,旧的translog会被删除并创建一个新的translog。

Elasticsearch数据查询的流程:

1、协调节点接收到查询请求,广播给其它分片节点。

2、每个分片在本地搜索并建立结果集。

3、协调节点取回全局结果集的一部分,返回给请求发起者。

===^^===

下面是介绍《榴芒客服系统》的博客,它是我们工作室开发的在线客服系统,欢迎下载试用:

《榴芒客服系统》https://blog.csdn.net/look4liming/article/details/164755808

相关推荐
孙启超2 小时前
【AI开发之Rust】第 3 课:字符串与复合类型 —— 数据怎么放
开发语言·人工智能·后端·rust·llm·transformer
t-think2 小时前
C++ string 类(上)—— string类初识与常用接口详解
开发语言·c++
cpp_learners2 小时前
C++ 实现责任链模式(Chain of Responsibility):从一堆 if-else 到可插拔的处理管道
开发语言·c++·责任链模式
2301_32241428042 小时前
活力孕康复APP 47737- 原创(免费领源码+部署教程+开发环境)
java·vue.js·spring boot·mysql·微信小程序·idea·微信开发者工具
君顾12 小时前
外卖CPS软件开发实战:从系统架构到部署全流程指南
java·开发语言·外卖
AIFQuant2 小时前
Python实时外汇行情接入实战:WebSocket与REST K线查询
开发语言·python·websocket
vx_Biye_Design3 小时前
springboot游泳馆系统93765-计算机课程设计、毕业设计
java·javascript·spring boot·后端·python·spring·课程设计
名字还没想好☜3 小时前
Java NIO ByteBuffer 实战:flip/clear/compact 三个绕晕人的方法与 position/limit 心智模型
java·开发语言·后端·spring·nio