Java面试(根据自己经验总结,持续更新)

1、Java基础

面向对象的特征:

封装:就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

继承:继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

多态:指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。

Java基本数据类型:

byte short int long double float char boolean

JDK、JRE、JVM区别:

JDK是java核心、开发工具包,JRE是运行java必须的环境集合,JVM是java虚拟机,运行以java语言写作的程序

**重载和重写的区别:**重载是在一个类中,方法名相同,参数类型不同、个数和顺序不同,重写是在父子类中,参数列表必须相同

==和equals的区别:
== 基本类型:比较值是否相同 引用类型:比较地址值是否相同,属于数值比较
equals:引用类型默认比较地址值,两个字符串内容,属于内容比较

String、StringBuffer、StringBuilder三者之间的区别
String对象不可变,线程安全
StringBuffer对方法加了同步锁,线程安全
StringBuilder并没有对方法加同步锁,所以非安全

什么是单例模式?有几种?
单例模式就是某个类实例在多线程环境下只会被创建一次出来
单例模式有饿汉式和懒汉式一级双检锁三种
饿汉式:线程安全,一开始就初始化
懒汉式:非线程安全,延迟初始化
双检锁:线程安全,延迟初始化

List、Map、Set的区别

List中存储的数据是有序,值允许重复

Map存储的数据是无序的,键不允许重复,值允许重复

Set存储的数据是无序的,并且不允许重复

List、Map、Set实现类

List:ArrayList底层数据结构是数组,查询快,增删慢,LinkedList底层数据结构是链表,查询慢,增删快

Map:HashMap接口实现,支持空的键值,线程不安全,HashTable线程安全不支持null键值

Set:HashSet底层是哈希表,LinkedHashSet底层是链表和哈希表由链表保证有序由哈希表保证元素唯一

List 和 Set,Map 的区别

List 以索引来存取元素,有序的,元素是允许重复的,可以插入多个null。

Set 不能存放重复元素,无序的,只允许一个null

Map 保存键值对映射,映射关系可以一对一、多对一

List 有基于数组、链表实现两种方式

Set、Map 容器有基于哈希存储和红黑树两种方式实现

Set 基于 Map 实现,Set 里的元素值就是 Map的键值

map遍历的方式有几种

1、使用for循环遍历map

2、使用迭代遍历map

3、使用keyset遍历map

4、使用entrySet遍历map

Array 和 ArrayList 有何区别?

定义一个 Array 时,必须指定数组的数据类型及数组长度,即数组中存放的元素个数固定并且类型相同。

ArrayList 是动态数组,长度动态可变,会自动扩容。不使用泛型的时候,可以添加不同类型元素。

HashMap原理,java8做了什么改变

HashMap是以键值对存储数据的集合容器

HashMap是非线性安全的。

HashMap底层数据结构:数组+(链表、红黑树),jdk8之前是用数组+链表的方式实现,jdk8引进了红黑树

Hashmap数组的默认初始长度是16,key和value都允许null的存在

HashMap底层实现是什么?
底层实现:数组+链表实现
允许key和value为null
Jdk8开始链表高度到8、数组长度超过64,链表就会转变红黑树

ArrayList扩容机制

就是计算出新的扩容数组的size后实例化,并将原有数组内容复制到新数组中去,默认情况下,新容量是原容量1.5倍

创建线程的几种方式

继承thred类重写run方法,但不可以继承其他类

实现Runnable接口重写run方法,避免单继承局限性

实现Callable接口重写call方法,可以获取线程执行结果返回值可以抛出异常

Thread类中,调用start和run的区别

run不开启线程,但是对象调用方法

start开启线程,并让jvm调用run方法在开启的线程中执行

线程有哪几种状态

新建状态:在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态

就绪状态:调用了线程对象的start方法后,该线程就进入了就绪状态,但是线程调度还没把该线程作为当前线程

运行状态:线程处于就绪状态时设置为运行状态,开始run函数当中的代码

阻塞状态:是线程因为某种原因放弃cpu使用权,暂时停止运行,直到线程再次进入就绪状态

死亡状态:线程执行完了或者异常退出run方法,线程结束生命周期

什么是连接池

将与数据库的连接放入一个容器,当程序需要使用连接时向容器申请而不是向数据库建立连接,释放时也是将连接放回到容器中,而不是关闭连接

并发、并行、串行的区别
串行在时间上不可能发生重叠,上个任务没搞定,下个任务只能等着

并行在时间上是重叠的,两个任务在同一时刻互不干扰的同时执行

并发允许两个任务彼此干扰,统一时间点、只有一个任务运行,交替执行

深拷贝和浅拷贝的区别

浅拷贝是对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝;

而深拷贝是对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容。

ArrayList和LinkedList区别?
他们的底层数据结构不同,ArrayList底层是数组实现,LinkedList底层是基于双链表实现的,适用场景不同,

线程、进程的区别

简而言之,进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程.

进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高.

线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位.同一进程中的多个线程之间可以并发执行

Java创建对象有哪几种方式

1、new对象

2、通过反射

3、采用clone机制

4、通过序列化机制

什么是反射

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;

如何获取反射中的class对象

1、class.forname

2、类名.class

3、对象名.getClass()

泛型
泛型就是将类型参数化,其在编译时才确定具体的参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法

Java序列化与反序列化是什么?
序列化:序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。核心作用是对象状态的保存与重建。我们都知道,Java对象是保存在JVM的堆内存中的,也就是说,如果JVM堆不存在了,那么对象也就跟着消失了。

而序列化提供了一种方案,可以让你在即使JVM停机的情况下也能把对象保存下来的方案。就像我们平时用的U盘一样。把Java对象序列化成可存储或传输的形式(如二进制流),比如保存在文件中。这样,当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化出对象。

反序列化:客户端从文件中或网络上获得序列化后的对象字节流,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。

为什么需要序列化与反序列化?
对内存中的对象进行持久化或网络传输, 这个时候都需要序列化和反序列化

Error和Exception区别是什么
Exception :程序本身可以处理的异常,可以通过 catch 来进行捕获,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。Exception 又可以分为运行时异常(RuntimeException, 又叫非受检查异常)和非运行时异常(又叫受检查异常) 。
ErrorError 属于程序无法处理的错误 ,我们没办法通过 catch 来进行捕获 。例如,系统崩溃,内存不足,堆栈溢出等,编译器不会对这类错误进行检测,一旦这类错误发生,通常应用程序会被终止,仅靠应用程序本身无法恢复。

throw 和 throws 的区别是什么?

  • throw 关键字用在方法内部,只能用于抛出一种异常,用来抛出方法或代码块中的异常,受查异常和非受查异常都可以被抛出。
  • throws 关键字用在方法声明上,可以抛出多个异常,用来标识该方法可能抛出的异常列表。一个方法用 throws 标识了可能抛出的异常列表,调用该方法的方法中必须包含可处理异常的代码,否则也要在方法签名中用 throws 关键字声明相应的异常。

包装类型是什么?基本类型和包装类型有什么区别?

  • 包装类型可以为 null,而基本类型不可以。它使得包装类型可以应用于 POJO 中,而基本类型则不行。那为什么 POJO 的属性必须要用包装类型呢?《阿里巴巴 Java 开发手册》上有详细的说明, 数据库的查询结果可能是 null,如果使用基本类型的话,因为要自动拆箱(将包装类型转为基本类型,比如说把 Integer 对象转换成 int 值),就会抛出 NullPointerException 的异常。

  • 包装类型可用于泛型,而基本类型不可以。泛型不能使用基本类型,因为使用基本类型时会编译出错。

    因为泛型在编译时会进行类型擦除,最后只保留原始类型,而原始类型只能是 Object 类及其子类——基本类型是个特例。

  • 基本类型比包装类型更高效。基本类型在栈中直接存储的具体数值,而包装类型则存储的是堆中的引用。 很显然,相比较于基本类型而言,包装类型需要占用更多的内存空间。

Java的IO 流分为几种?

  • 按照流的方向:输入流(inputStream)和输出流(outputStream);
  • 按照实现功能分:节点流(可以从或向一个特定的地方读写数据,如 FileReader)和处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写, BufferedReader);
  • 按照处理数据的单位: 字节流和字符流。分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。Java中其他多种多样变化的流均是由它们派生出来的。

字节流如何转为字符流?

字节输入流转字符输入流通过 InputStreamReader 实现,该类的构造函数可以传入 InputStream 对象。

字节输出流转字符输出流通过 OutputStreamWriter 实现,该类的构造函数可以传入 OutputStream 对象。

字符流与字节流的区别?

  • 读写的时候字节流是按字节读写,字符流按字符读写。
  • 字节流适合所有类型文件的数据传输,因为计算机字节(Byte)是电脑中表示信息含义的最小单位。字符流只能够处理纯文本数据,其他类型数据不行,但是字符流处理文本要比字节流处理文本要方便。
  • 在读写文件需要对内容按行处理,比如比较特定字符,处理某一行数据的时候一般会选择字符流。
  • 只是读写文件,和文件内容无关时,一般选择字节流。

2、MySQL

连接查询

左外链接:以左表为基准进行查询,左表数据会全部显示出来

右外链接

聚合函数

提供用来统计COUNT、求和SUN、最大MAX最小值MIN、平均AVG

SQL关键字

分页:limit

分组:group by

去重:distinct

数据库三范式

  • 第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。
  • 第二范式:要求实体的属性完全依赖于主关键字。所谓完全 依赖是指不能存在仅依赖主关键字一部分的属性。
  • 第三范式:任何非主属性不依赖于其它非主属性。

数据库事务

原子性:不可分割性,要么全部执行成功、要么全部不执行

一致性:事务的执行使数据库从一种正确状态转换成另一种正确状态

隔离性:在事务正式提交之前,不允许把该事务对数据的任何改变给其他事务

持久性:事务正确提交后,结果将永远保存在数据库中,如果提交后有其他故障,结果也会保存

数据库隔离级别

读未提交:事务读取到别的事务中未提交的数据,会产生脏读

读已提交:事务只能看见已经提交事务所做的改变,避免脏读问题,但是会产生不可重复读和幻读

可重复读:确保了一个事务中多个实例在并发读取数据时会读取到一样的数据,这就会导致另一个棘手的问题,幻读(指当用户读取某一范围的数据行时,另一个事物又在该范围内插入了新行,所以当该用户在读该范围的数据时,就发现新的幻影行)

可串行化:事务的最高级别,通过强制事务排序,使之不可能相互冲突,从而解决幻读问题,简言之,它是在每个读的数据行上加上共享锁,在这个级别,可能导致大量的超时现象和锁竞争,一般为了提升程序的吞吐量不会采用这个

索引是什么

保证每行数据唯一性、加快数据的检索速度、加速表和表之间的连接

索引的分类

普通索引:最基本的索引,没有任何限制

唯一索引:与普通索引类似,不同的就是索引列的值必须唯一,允许有空值

主键索引:用唯一标识某条记录,不允许空值

联合索引:多个字段上建立索引,加速复合查询

为什么要枷锁

多用户环境下保证数据库完整性和一致性。

数据库锁

行锁:锁定整行数据,防止并发错误

表锁:锁定整表数据,防止并发错误

悲观锁:每次拿数据的时候认为别人会修改,所以每次拿数据时(操作之前)都会上锁

乐观锁:每次拿数据的时候认为不会被修改,所以不会上锁,更新的时候会判断在此期间有没有更新这个数据,可以使用版本号等机制

建表约束条件有哪些

  • 主键约束(Primay Key Coustraint) 唯一性,非空性
  • 唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个
  • 检查约束 (Check Counstraint) 对该列数据的范围、格式的限制
  • 默认约束 (Default Counstraint) 该数据的默认值
  • 外键约束 (Foreign Key Counstraint) 需要建立两表间的关系并引用主表的列

大表数据查询,怎么优化

  • 优化shema、sql语句+索引;
  • 第二加缓存,memcached, redis;
  • 主从复制,读写分离;
  • 垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
  • 水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key, 为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;

如何优化关联查询

  • 确定ON或者USING子句中是否有索引。
  • 确保GROUP BY和ORDER BY只有一个表中的列,这样MySQL才有可能使用索引。

大表怎么优化

  • 限定数据的范围: 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
  • 读/写分离: 经典的数据库拆分方案,主库负责写,从库负责读;
  • 缓存: 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑;
  • 通过分库分表的方式进行优化,主要有垂直分表和水平分表。

3、Mybatis

在 mybatis 中,${} 和 #{} 的区别是什么?(必会)

#{}是占位符,${}是字符串替换

在 mybatis 中,resultType 和 ResultMap 的区别是什么?

列名和属性名完全一致用type,不一致用map

Mybatis为什么是ORM半映射工具,与全自动的区别在哪

Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。

而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。

什么是mybatis

是一个半ORM(对象关系映射)框架,它内部封装了JDBC,加载驱动、创建连接、创建statement等繁杂的过程,开发者开发时只需要关注如何编写SQL语句,可以严格控制sql执行性能,灵活度高

mybatis编程步骤

1、创建SqlSessionFactory
2、通过SqlSessionFactory创建SqlSession
3、 通过sqlsession执行数据库操作
4、 调用session.commit()提交事务
5、 调用session.close()关闭会话

在mapper中如何传递多个参数

1、若Dao层函数有多个参数,那么其对应的xml中,#{0}代表接收的是Dao层中的第一个参数,#{1}代表Dao中的第二个参数,以此类推。

2、使用@Param注解:在Dao层的参数中前加@Param注解,注解内的参数名为传递到Mapper中的参数名。

3、多个参数封装成Map,以HashMap的形式传递到Mapper中。

mybatis动态sql有什么用
传统jdbc方法中,在写组合的多表复杂sql语句时,需要去拼接sql语句,稍不注意少写一个空格或“”,就会导致报错。
这个Mybatis动态sql的功能,就拥有有效的解决了这个问题,Mybatis动态sql语言可以被用在任意的sql语句映射中。完成逻辑判断并动态拼接 sql 的功能。

Mybatis提供了9种动态sql标签:trim、where、set、foreach、if、choose、when、otherwise、bind

mybatis一级、二级缓存

一级缓存

一级缓存在 Mybatis 中默认是开启并生效的。

一级缓存存在两种作用范围:

SESSION(默认)
在同一个 SqlSession 中多次执行同一个查询,除第一次走数据库,剩下的都走缓存
STATEMENT
每执行完一个 Mapper 中的语句后都会将一级缓存清除。

二级缓存

二级缓存在 Mybatis 中默认是不开启。准确的来讲应该是二级缓存的全局配置开关是默认开启的但是想要二级缓存生效,还需要进行配置。

二级缓存的作用范围是同一个 namespace 下的mapper 映射文件内容。多个 SqlSession 之间可以共享缓存内容。

Spring 整合 Mybatis 之后,二级缓存照常生效,但是一级缓存有了改变。如果不是在同一个事务中每一次 Mapper 方法的调用,都会生成一个新的 Sqlsession,这时候一级缓存就不会命中。

什么是hibernate

是一个完全的ORM框架,能够将对象映射成数据库表,简化开发

通过设置lazy进行设置是否需要懒加载,通过配置文件中的many-to-one,one-to-many实现类之间关联关系

4、Spring

Spring 框架中都用到了哪些设计模式?

工厂模式、单例模式、代理模式、模板方法模式、包装器设计模式、观察者模式、适配器模式

对spring的理解

它的两大核心理念是IOC和AOP,它可以根据配置文件创建及组装对象之间的依赖关系,能非常简单的管理数据库,自己提供了一套JDBC方便访问数据库以及一套SpringMVC框架方便Web层搭建

Spring的两大核心是什么?谈一谈你对IOC的理解? 谈一谈你对DI的理解?

1.Spring的两大核心是:IOC(控制反转)和AOP(面向切面编程)DI(依赖注入)
2.IOC的意思是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。最直观的表达就是,IOC让对象的创建不用去new了,可以由spring根据我们提供的配置文件自动生产,我们需要对象的时候,直接从Spring容器中获取即可.
Spring的配置文件中配置了类的字节码位置及信息,容器生成的时候加载配置文件识别字节码信息,通过反射创建类的对象.
Spring的IOC有三种注入方式:构造器注入,setter方法注入,根据注解注入。
3.DI的意思是依赖注入,和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖Ioc容器来动态注入对象需要的外部资源。

4.AOP,一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关, 但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被 命名为“切面”(Aspect). SpringAOP 使用的动态代理,所谓的动态代理就是说 AOP 框 架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个 AOP 对象,这个 AOP 对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。 5. Spring AOP 中的动态代理主要有两种方式,JDK 动态代理和 CGLIB 动态代理: (1)JDK 动态代理只提供接口代理,不支持类代理,核心 InvocationHandler 接口和 Proxy 类,InvocationHandler 通过 invoke()方法反射来调用目标类中的代码,动态地将 横切逻辑和业务编织在一起,Proxy 利用 InvocationHandler 动态创建一个符合某一接口 的的实例, 生成目标类的代理对象。 (2) 如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库, 可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从 而实现 AOP。CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final, 那么它是无法使用 CGLIB 做动态代理的。
spring提供了那些配置方式

1、xml

2、注解配置

将一个类声明为spring的bean的注解有哪些

@Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用@Component 注解标注。
@Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
@Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

Spring 的常用注解(必会)
1.@Component(任何层) @Controller @Service @Repository(dao): 用于 实例化对象
2. @Scope : 设置 Spring 对象的作用域
3. @PostConstruct @PreDestroy : 用于设置 Spring 创建对象在对象创建之后和销 毁之前要执行的方法
4. @Value: 简单属性的依赖注入
5. @Autowired: 对象属性的依赖注入
6. @Qualifier: 要和@Autowired 联合使用,代表在按照类型匹配的基础上,再按照 名称匹配。
7. @Resource 按照属性名称依赖注入
8. @ComponentScan: 组件扫描
9. @Bean: 表在方法上,用于将方法的返回值对象放入容器
10. @PropertySource: 用于引入其它的 properties 配置文件
11. @Import: 在一个配置类中导入其它配置类的内容
12. @Configuration: 被此注解标注的类,会被 Spring 认为是配置类。Spring 在启动 的时候会自动扫描并加载所有配置类,然后将配置 类中 bean 放入容器

Spring的生命周期
1.实例化一个 Bean,也就是我们通常说的 new
2. 按照 Spring 上下文对实例化的 Bean 进行配置,也就是 IOC 注入
3. 如果这个 Bean 实现 dao 了 BeanNameAware 接口,会调用它实现的 setBeanName(String beanId)方法,此处传递的是 Spring 配置文件中 Bean 的 ID
4. 如果这个 Bean 实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory(), 传递的是 Spring 工厂本身(可以用这个方法获取到其他 Bean)
5. 如果这个 Bean 实现了 ApplicationContextAware 接口,会调用 setApplicationContext(ApplicationContext)方法,传入 Spring 上下文,该方式同样可 以实现步骤 4,但比 4 更好,以为 ApplicationContext 是 BeanFactory 的子接口,有更多 的实现方法
6. 如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用 postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 经常被 用作是 Bean 内容的更改,并且由于这个是在 Bean 初始化结束时调用 After 方法,也可用 于内存或缓存技术
7. 如果这个 Bean在 Spring 配置文件中配置了 init-method 属性会自动调用其配置的初始 化方法 8. 如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用 postAfterInitialization(Object obj, String s)方法

RestController和Controller有什么区别

@RestController 注解,在 @Controller 基础上,增加了 @ResponseBody 注解,更加适合目前前后端分离的架构下,提供 Restful API ,返回例如 JSON 数据格式。

5、SpringMVC

谈一下你对 SpringMVC 框架的理解
SpringMVC 是一个基于 Java 的实现了 MVC 设计模式的请求驱动类型的轻量级 Web 框架,通过把 Model,View,Controller 分离,将 web 层进行职责解耦,把复杂的 web 应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。 在我看来,SpringMVC 就是将我们原来开发在 servlet 中的代码拆分了,一部分由 SpringMVC 完成,一部分由我们自己完成

SpringMVC 的常用注解

RequestMapping、ResponseBody、RequestBody

SpringMVC常用注解RequestBody、RequestMapping、ResponseBody

@RequestBody:接收前端传递给后端的json字符串中的数据的

@ResponseBody:将java对象转为json格式的数据。

@RequestMapping:映射请求,通过它置顶控制器处理那些URL请求

SpringMVC底层实现原理
(1)客户端(浏览器)发送请求,直接请求到DispatcherServlet(调度器)。
(2)DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。
(3)解析到对应的Handler后,开始由HandlerAdapter适配器处理。
(4)HandlerAdapter会根据Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
(5)处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View。
(6)ViewResolver会根据逻辑View查找实际的View。
(7)DispaterServlet把返回的Model传给View。
(8)通过View返回给请求者(浏览器)

什么是springMVC

通过把Model,View,Controller分离,把较为复杂的web应用分成逻辑清晰的几部分,是为了简化开发,减少出错

springmvc怎么设定重定向和请求转发

请求转发:在返回值前面加"forward:"。

重定向:在返回值前面加"redirect:"。

在 SpringMVC 中文件上传的使用步骤是什么样的? 前台三要素是什 么?
文件上传步骤:
1.加入文件上传需要的 commons-fileupload 包
2.配置文件上传解析器,springmvc 的配置文件的文件上传解析器的 id 属性必须为 multipartResolver
3.后端对应的接收文件的方法参数类型必须为 MultipartFile,参数名称必须与前端 的 name 属性保持一致

文件上传前端三要素:
1.form 表单的提交方式必须为 post
2.enctype 属性需要修改为:multipart/form-data
3.必须有一个 type 属性为 file 的 input 标签,其中需要有一个 name 属性;如果需要 上传多个文件需要添加 multiple 属性

6、SpringCloud

SpringCloud是什么
SpringCloud 是一系列框架的集合,集成 SpringBoot,提供很多优秀服务:服务发现 和注册,统一配置中心, 负载均衡,网关, 熔断器等的一个微服务治理框架.

SpringCloud 有哪些核心组件?

Eureka:注册中心,服务注册和发现

Ribbon:负载均衡,服务调用,用在消费方的,通过某种算法去分配要连接的机器,默认是轮训策略

Hystrix:熔断器,为了解决无法正常访问服务时提供的方案,一种是服务降级一种是服务熔断

Feign:远程调用,服务和服务之间的调用

Zuul:网关

Config:配置中心,服务数量多,对配置文件统一管理

(1)Eureka
提供服务注册和发现, 是注册中心. 有两个组件: Eureka 服务端和 Eureka 客户端
Eureka 服务端: 作为服务的注册中心, 用来提供服务注册, 支持集群部署. Eureka 客户端: 是一个 java 客户端, 将服务注册到服务端, 同事将服务端的信息缓存 到本地, 客户端和服务端定时交互.
Eureka-Server:就是服务注册中心(可以是一个集群),对外暴露自己的地址
提供者:启动后向 Eureka 注册自己信息(地址,服务名称等),并且定期进行服务续 约
消费者:服务调用方,会定期去 Eureka 拉取服务列表,然后使用负载均衡算法选出一 个服务进行调用。
心跳(续约):提供者定期通过 http 方式向 Eureka 刷新自己的状态

(2)Ribbon
. 给客户端提供负载均衡, 也就是说 Ribbon 是作用在消费者方的.
简单来说, 它是一个客户端负载均衡器, 它会自动通过某种算法去分配你要连接的机 器.
Ribbon 默认负责均衡策略是轮询策略.

(3)Hystrix 熔断器
有时候可能是网络问题, 一些其它问题, 导致代码无法正常运行, 这是服务就挂了, 崩 溃了. 熔断器就是为了解决无法正常访问服务的时, 提供的一种解决方案.
Hystrix 提供了两种功能, 一种是服务降级, 一种是服务熔断

  1. 服务降级原理
    Hystrix 为每个服务分配了小的线程池, 当用户发请求过来, 会通过线程池创建线 程来执行任务, 当创建的线程池已满或者请求超时(这里和多线程线程池不一样,不 存在任务队列), 则启动服务降级功能.

降级指的请求故障时, 不会阻塞, 会返回一个友好提示(可以自定义, 例如网站维 护中请稍后重试), 也就是说不会影响其他服务的运行

  1. 服务熔断原理
    Closed:关闭状态(断路器关闭),所有请求都正常访问。

Open:打开状态(断路器打开),所有请求都会被降级。Hystix 会对请求情况计数, 当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全关闭。默认失败比 例的阈值是 50%,请求次数最少不低于 20 次。

Half Open:半开状态,open 状态不是永久的,打开后会进入休眠时间(默认是 5S)。 随后断路器会自动进入半开状态。此时会释放 1 次请求通过,若这个请求是健康的, 则会关闭断路器,否则继续保持打开,再次进行 5 秒休眠计时。

(4)Feign:远程调用组件
后台系统中, 微服务和微服务之间的调用可以通过Feign 组件来完成.

Feign 组件集成了 Ribbon 负载均衡策略(默认开启的, 使用轮询机制), Hystrix 熔断器 (默认关闭的, 需要通过配置文件进行设置开启)

被调用的微服务需要提供一个接口, 加上@@FeignClient(“url”)注解
调用方需要在启动类上加上@EnableFeignClients, 开启 Feign 组件功能.

(5)Gateway: 路由/网关
对于项目后台的微服务系统, 每一个微服务都不会直接暴露给用户来调用的, 但是如果 用户知道了某一个服务的 ip:端口号:url:访问参数, 就能直接访问你. 如果再是恶意访问, 恶意攻击, 就会击垮后台微服务系统.因此, 需要一个看大门的大 boss, 来保护我们的 后台系统.

(6)Spring Cloud Config
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所 以需要分布式配置中心组件。在 Spring Cloud 中,有分布式配置中心组件 spring Cloud Config

什么是微服务

微服务讲究的是专注某个功能的实现,比如登录系统只专注于用户登录方面功能的实现,就是使用springboot 开发的一个小的模块,处理单一专业的业务逻辑,一个模块只做一个事情

什么是熔断?什么是服务降级

服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。

服务降级是对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。

什么是微服务架构

就是 对微服务进行管理整合应用的。微服务架构 依赖于 微服务,是在微服务基础之上的。

Springboot和Springcloud区别

SpringBoot专注于快速方便的开发单个个体微服务。

SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务SpringBoot可以离开SpringCloud独立使用开发项目, 但是SpringCloud离不开SpringBoot ,属于依赖的关系SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。

SpringBoot 是为了解决 Spring 配置文件冗余问题, 简化开发的框架.

SpringCloud 是为了解决微服务之间的协调和配置问题, 还有服务之间的通信, 熔断, 负载均衡远程调度任务框架.

SpringCloud 需要依赖 SpringBoot 搭建微服务, SpringBoot 使用了默认大于配 置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,SpringCloud 很大的一部分是基于 SpringBoot 来实现。

SpringBoot 不需要依赖 SpringCloud 就可以独立开发. SpringBoot 也可以集成 Dubbo 进行开发

Springcloud有几种调用接口方式

feign、resttamplate

什么是gateway

取代zuul网关,功能有路由转发、权限校验、限流控制等作用,创建路由后可以添加断言和过滤器,用来对请求做各种判断和修改

什么是feign

不需要自己构建http请求,直接调用接口进行服务之间的远程调用

什么是ribbon

提供客户端的负载均衡算法,如链接超时、重试等,在配置文件中列出后面所有机器,ribbon会自动帮助你基于某种规则(默认是轮训)去链接这些机器,也可以自定义负载均衡算法

7、SpringBoot

什么是springboot

是 Spring 的子项目,主要简化 Spring 开发难度,去掉了繁重配置,提供各种启动器,可以 让程序员很快上手,节省开发时间

springboot核心注解是哪个?

启动类是springbootapplication

运行 SpringBoot 项目的方式
可以打包
可以使用 Maven 插件直接运行.
直接运行 main 方法.

SpringBoot 的启动器 starter
starter 启动器,可以通过启动器集成其他的技术,比如说: web, mybatis, redis 等等.可 以提供对应技术的开发和运行环境. 比如: pom 中引入 spring-boot-starter-web, 就可以进行 web 开发.

SpringBoot 中的配置文件
(1)有哪些配置文件?
application.yml 或 application.properties
bootstrap.yml 或 bootstrap.properties

(2)上面两种配置文件有什么区别?
1.bootstrap 由父 ApplicationContext 加载, 比 application 配置文件优先被加 载.
2.bootstarp 里的属性不能被覆盖.
3. application: springboot 项目中的自动化配置.
4. bootstrap: 使用 spring cloud config 配置中心时, 需要加载连接配置中心的配置属性的, 就 可以使用 bootstrap 来完成. 加载不能被覆盖的属性. 加载一些加密/解密的数据

SpringBoot 常用注解
@SpringBootApplication: 它封装了核心的 @SpringBootConfiguration +@EnableAutoConfiguration +@ComponentScan 这三个类,大大节省了程序员配 置时间,这就是 SpringBoot 的核心设计思想.

@EnableScheduling 是通过@Import 将 Spring 调度框架相关的 bean 定义都加载到 IoC 容器

@MapperScan:spring-boot支持mybatis组件的一个注解,通过此注解指定mybatis 接口类的路径,即可完成对 mybatis 接口的扫描

@RestController 是 @Controller 和 @ResponseBody 的 结 合 , 一 个 类 被 加 上 @RestController 注解,数据接口中就不再需要添加

@ResponseBody,更加简洁。 @RequestMapping,我们都需要明确请求的路径. @GetMappping,@PostMapping, @PutMapping,@DeleteMapping 结 合 @RequestMapping 使用, 是 Rest 风格的, 指定更明确的子路径.

@PathVariable:路径变量注解,用{}来定义 url 部分的变量名.

@Service 这个注解用来标记业务层的组件,我们会将业务逻辑处理的类都会加上这个 注解交给 spring 容器。事务的切面也会配置在这一层。当让 这个注解不是一定要用。 有个泛指组件的注解,当我们不能确定具体作用的时候 可以用泛指组件的注解托付给 spring 容器

@Component 和 spring 的注解功能一样, 注入到 IOC 容器中.

@ControllerAdvice 和 @ExceptionHandler 配合完成统一异常拦截处理.

8、Redis

Redis是什么

Redis本质上是一个Key-Value类型的内存数据库,整个数据库加载在内存当中操作,定期通过异步操作把数据库中的数据flush到硬盘上进行保存。

为什么要用redis做缓存

从高并发上来说:

  • 直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。

从高性能上来说:

  • 用户第一次访问数据库中的某些数据。 因为是从硬盘上读取的所以这个过程会比较慢。将该用户访问的数据存在缓存中,下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据。

Redis的存储结构有哪些

String,Hash,List,Set

为什么要用Redis

高性能高并发

Redis缓存问题

缓存雪崩:

缓存同一时间大面积失效,这时候又来一波请求

如何解决?1、互斥锁 2、搭建redis集群

缓存击穿:

故意请求缓存中不存在的数据,导致所有请求都到数据库上

如何解决?1、互斥锁 2、采用异步更新

Redis持久化

为了能够重用Redis数据,或者防止系统故障,我们需要将Redis中的数据写入到磁盘空间中,即持久化。

RDB:在不同时间点,将redis存储的数据生成快照并存储到磁盘

AOF:将redis执行过的所有写指令记录下来,下次redis重新启动时,把这些写指令全部在执行一遍,就能实现数据恢复

Redis主从复制、哨兵

主从复制:主机会自动将数据同步到从机,进行读写分离

哨兵:监控主从服务器是否正常运行,主服务器出现故障自动将从服务器转换为主服务器

Redis分片是什么

能够将数据量分散到若干主机的redis实例上,进而减轻单台redis实例的压力。

9、消息中间件

RabbitMQ

RabbitMQ是什么

RabbitMQ是一款开源的消息中间件;
最大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦
可以用它来:解耦、异步、削峰。

消息如何分发?

若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消息并进行确认)。通过路由可实现多消费的功能

消息怎么路由?

消息提供方->路由->一至多个队列消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。通过队列路由键,可以把队列绑定到交换器上。消息到达交换器后,RabbitMQ 会将消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则);

消息基于什么传输?

由于 TCP 连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ 使用信道的方式来传输数据。信道是建立在真实的 TCP 连接内的虚拟连接,且每条 TCP 连接上的信道数量没有限制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值