Java面试题

228 阅读35分钟

1.面向对象有哪些特性,以及对这些特性的理解

封装:

数据和对数据的操作绑定起来,对数据的访问只能通过已经定义好的接口。面向对象的本质就是将现实世界描绘成完全自治,封闭的对象。在类中编写的方法就是对显示细节的一种封装。编写的就是对数据和数据操作的一种封装。

继承:

已有的类得到继承信息创建新类的过程。提供继承信息的类称为父类。得到继承信息的类称为子类。继承让变化中的软件具有了一定的延续性。

多态:

不同子类型的对象对同一消息做出不同的响应,也就是同样的对象引用调用同样的方法做了不同的事情。

  • 编译时多态:

    方法重载就是编译时多态

  • 运行时多态:

    方法重写就是运行时多态

抽象:

将一类对象的共同特征总结出来构造类的过程。包括数据抽象行为抽象。抽象只关注这些对象的属性和行为,并不关注这些行为的细节是什么。

2.访问权限修饰符pubilc pravite protected 以及不写时的区别

image.png

3.java有没有语句

goto是java中的保留字,有这个关键字,但是目前无法使用,所以称之为保留字。

4.&和&&的区别

  • &:
    • 按位与;
    • 逻辑与;
  • &&:
    • 短路与:

二者都要求运算符左右两端的布尔值都是true,整个表达式的值才为true;

当&&左边的值为false时,右边的表达式会直接被短路掉,不会进行运算。

5.在java中如何跳出当前的多重循环

break跳出多种循环;continue继续执行;应该避免使用。

6.两个对象的值相同(x.equals(y)==true),但是却有不同的hashcode,这句话对不对

不对,如果两个对象的值相同(x.equals(y)==true),那么他们肯定有相同的哈希值, 对于equals和hashcode方法是这样规定的:

  • 如果两个对象相同equals为true,那么他们的hashcode一定要相同;
  • 如果两个对象的hashcode相同,他们不一样相同;

7.是否可以继承String类

不能,String类是final的,不能被继承;

8.当一个对象被当作参数传递到一个方法之后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

值传递,java的语法调用只支持参数的值传递,当一个对象的实例被当作参数传递到方法中时,参数的值就是该对象的引用,对象的属性可以在被调用的过程中被改变,但对对象的引用的改变是不会影响调用者的。

9.重载(overload)和重写(overload)的区别?重载的方法是否根据返回类型进行区别?

方法的重载和重写都是实现多态的方式。

区别:

  • 前者实现的是编译时多态性;
  • 后者实现的是运行时多态性

重载发生在同一个类当中,同名的方法如果有不同的参数列表(参数类型不同,参数个数不同,或者二者都不同),则视为重载;

重写发生在子类和父类之间,重写要求子类被重写方法与父类被重写的方法有相同的参数类型,比父类被重写的方法更好访问。

重载对返回类型没有要求。

方法重载的规则:

  • 方法名一致,参数列表中参数的顺序,类型,个数不同。
  • 重载与方法的返回值无关,存在与父类和子类,同类中。
  • 可以抛出不同的异常,可以有不同的修饰符。

方法重写的规则:

  • 参数列表和返回值类型必须与被重写的方法一致。
  • 构造方法,声明为final,static的方法不能被重写,但是能够被再次声明。
  • 访问权限不能比父类中被重写的访问权限更低。
  • 重写的方法能够抛出任何非强制异常。

10.抽象类和接口有什么异同

抽象类:

  • 可以定义构造器
  • 可以有抽象方法和具体方法
  • 接口中的全部成员全是public的
  • 可以定义成员变量
  • 有抽象方法的类必须声明为抽象类,而抽象类未必有抽象方法
  • 抽象类中可以包含静态方法
  • 一个类只能继承一个抽象类

接口:

  • 不能定义构造器
  • 方法全部都是抽象方法
  • 抽象类中的成员可以是pubilc protected private 默认
  • 接口中的定义的成员变量实际上都是常量
  • 接口中不能有静态方法
  • 一个类可以实现多个接口

相同:

  • 不能够实例化
  • 可以将抽象类和接口类型作为引用类型
  • 一个类如果继承了某个抽象类或者实现某个接口则都需要对其中的抽象方法进行全部实现,否则该类仍然需要被声明为抽象类。

11.静态变量和实例变量的区别?

静态变量: 被static所修饰,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;

实例变量: 必须依存于某一个实例,需要先创建对象,然后通过对象才能访问它,静态变量可以实现让多个对象共享内存。

12.==和equals的区别?

==:
  • 如果比较的对象是基本数据类型,则比较的是数值是否相等;
  • 如果比较的是引用数据类型,则比较的是对象的地址值是否是否相等;
equals():
  • 用来比较方法两个对象的内容是否相等;

注意: equals不能用于基本数据类型的对象,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址。

13.String s = "hello";s = s + "world!";这两行代码执行后,原始的String对象中的内容有没有改变?

没有, 因为String被设计为不可变类(immutable),所有它所有的对象都是不可变对象

14.java中实现多态的机制是什么?

靠的是父类或接口定义的引用变量可以指向子类或具体实现类的对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

15.Java中的异常分为哪几类?

按异常需要处理的时机分类:

  • 编译时异常(CheckedException)

    若没有处理该异常,则程序在编译时就会发生错误无法编译 处理方法有两种:

    • 当前方法知道如何处理该异常,则使用try...catch块来处理异常;
    • 当前方法不知道如何处理,则在定义该方法时声明抛出该异常;
  • 运行时异常

16.在既有try catch finally 的代码块中,最终执行的结果是finally中的代码块

17.error和exception的区别是什么?

他们二者的父类都是Throwable类 区别如下:

  • error一般是指与虚拟机相关的问题,比如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢出;
  • excpetion表示程序可以处理的异常,可以捕获且可能恢复; 举例几个运行时异常:
  • 空指针异常:该异常出现的原因是调用了未初始化的对象或不存在的对象;
  • 指定的类找不到:出现的原因是因为类的名称或者路径加载错误;
  • 字符串转化为数字异常:出现的原因是因为字符型数据中包含非数字字符;
  • 数组下标越界异常:常监狱操作数组对象时发异常;
  • 放啊传递参数异常;
  • 数据类型转换异常;
  • SQL异常:常见于操作数据库语句错误;

18.throw和throws的区别:

throw:

  • throw语句用在方法体内,表示抛出异常,由方法体内的语句处理;
  • throe是具体向外抛出异常的动作,所以它抛出的是一个异常的实例执行throw一定是抛出了某种异常。 throws
  • 该语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常处理;
  • 主要是声明这个方法会抛出某种类型的异常,让他的使用者要知道需要捕获的异常的类型;
  • 表示出现异常的一种可能性,并不一定会发生这种异常。

19.final和finally和finalize的区别?

  • nal用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,被其修饰的类不能被继承;
  • finally 异常处理结构的一部分,表示总是执行;
  • Object类的一个方法,在垃圾回收器执行的时候会执行此方法,可以覆盖此方法提供垃圾收集时的其他资源的回收,例如文件关闭,

20.String. StringBuilder. StringBuffer的区别?

java提供了两种类型的字符串:String 和 StringBuffer/StringBuilder;

  • 可变不可变:
    • String:字符串常量,在修改时时不会改变自身;若修改,等于重新生成新的字符串对象。
    • StringBuffer:在修改是改变对象自身,每次操作都是对StringBuffer对象本身进行修改, 不是生成新的对象;使用场景,对字符串经常改变的情况下,主要方法,append(),insert();
  • 线程是否安全:
    • String: 对象定义之后不可改变,线程安全;
    • StringBuffer: 线程安全,对调用方法加入了同步锁,执行效率慢,适用于多线程下操作字符串缓冲大量数据;
    • StringBuilder:是线程不安全的,适用于单线程下操作字符串缓冲大量数据。
  • 共同点
    • StringBuilder和StringBuffer有公共父类AbstractStringBuilder(抽象类)

区别如下:

  • String是只读字符串,也就意味着String引用的字符串内容是不能被改变的
String str = "abc";
str = "bcd";

这样的话,str改变了嘛,并没有被改变,str仅仅只是一个引用对象,它指向一个字符串对象“abc”,第二行的代码的含义是让str重新指向一个新的字符串"bcd",而“abc”对象并没有任何改变,只不过该对象已成为一个不可及对象罢了。

  • StringBuffer和StringBuilder表示字符串对象可以直接进行修改;
  • StringBuilder是Java5中引入的,他和StringBuffer的方法完全相同,区别在于他是在单线程的环境下使用的,因为他的所有方法都没有被synchronized修饰,所以他的效率比StringBuffer要高;

21.java中的基本数据类型

image.png

22.String是基本数据类型嘛?

String是引用数据类型,底层是char数组实现的;

23.int和Integer有什么区别?

int的包装类就是Integer,从java5开始引入了自动装箱拆箱规则,二者可以相互转换;

image.png

24.Java中有几种类型的流 IO 

  • 按照流的方向:
    • 输入流:InputStream
    • 输出流:OutputStream
  • 按照实现功能分:
    • 节点流:可以从或向一个特定的方向(节点)读写数据,如FileReader,
    • 处理流:对一个已经存在的流的链接或者封装,通过所封装的流的功能调用实现数据读写。
  • 按照处理数据的单位:
    • 字节流:继承于InputStream和OutputStream
    • 字符流:继承于InputStreamReader和OutputStreamWriter.

image.png

image.png

25.字节流如何转为字符流

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

26.如何将一个java对象序列化到文件里面

在Java中能够被序列化的类必须先实现Serializable接口,该接口没有任何抽象方法只是起到一个标记作用。

27.字节流和字符流的区别

字节流读取的时候,读到一个字节就返回一个字节;

字符流使用了字节流读到一个或多个字节时,先去查指定的编码表,将查到的字符返回,字节流可以处理所有类型数据。

28.原生JDBC操作数据库流程

  • 第一步:Class.forName()加载数据库链接驱动;、
  • 第二部:DriverManager.getConnection获取数据链接对象;
  • 第三部:根据SQL获取sql会话对象,有2种方式,Statement,PreparedStatement;
  • 第四步:执行SQL处理结果集,执行SQL前,如果有参数就设置参数值;
  • 第五步:关闭结果集,关闭会话,关闭连接;

29.http常见的状态码有哪些?

  • 200:客户端请求成功
  • 301:请求的URL已经被移走
  • 302:重定向
  • 400:客户端请求有语法错误,不能被服务器所理解
  • 401:请求未经授权
  • 403:服务器收到请求,但是拒绝提供服务
  • 404:请求的资源不存在 比如输入流错误的URL
  • 500:服务器发生了不可预期的错误
  • 503:服务器当前不能处理客户端请求,一段时间后可能恢复正常

30.get和post的区别?

从表面现象上看get和pos的区别;

  • get请求的数据会附在url之后(就是把数据放置在url中的请求头中,用?分割url和传输数据),参数之间用&相连;post请求是把提交的数据放在HTTP包的包体中。
  • GET方式提交的数据最多只能是1024个字节,理论上POST没有限制,可传输大量的数据,但是这种说法是错误的,不准确;
  • GET是向服务器发索取数据的请求,而POST是向服务器提交数据的请求,在form中,METHOD默认为GET,实质上,GET和POST只是发送的机制不同,并不是一个取一个发。

31.请求转发和重定向的区别?

本质区别:转发是服务器的行为,重定向是客户端的行为;

  • 重定向特点:两次请求,浏览器地址发生变化,可以访问自己web之外的资源,传输的数据不会丢失。
  • 请求转发的特点:一次请求,浏览器地址不变,访问的是自己本身的web资源,传输的数据不会丢失。

32.cookie和session的区别?

  • Cookie是服务器发给浏览器的一块信息,浏览器会在本地的一个文件中给每个web服务器存储cookie,以后浏览器再给特定的web服务器发送请求的时候,同时会发送所有为该服务器存储的cookie;
  • Session是存储在web服务器端的一块信息,session对象存储的特定用户会话所需要的属性及配置信息,当用户在应用程序的web页面之间跳转的时候,存储在session对象的变量将不会丢失,而是在整个用户的会话中一直存下去;

Cookie和Session的不同点:

  • 无论客户端做怎么样的设置,session能够正常工作,当客户端禁用session时将无法使用cookie;
  • 在存储的数据量的方面,session能够存储任意的Java对象,cookie只能存储String类型的对象;

33.在单点登录中,如果cookie被禁用了怎么办?

单点登录的原理是后端生成一个session ID ,然后设置到cookie,后面的所有请求浏览器都会带上cooike,然后服务器从cookie里面获取sessionID,再查询到用户信息,所以,保持登录的关键不在于cookie,而是通过Cookie保存和传输的sessionID,其本质是能够获取用户信息的数据,除了cookie,还通常使用HTTP请求头来传输,但是这个请求头浏览器不会像cookie一样自动携带,需要手工处理。

34.常用的Linux命令

  • 列出文件列表:ls 参数(-a -l)
  • 创建目录和移除目录:mkdir rmdir
  • 用于显示文件后几行内容:tail
  • 打包:tar -xvf
  • 打包并压缩:tar -zcvf
  • 显示当前所在目录:pwd
  • 编辑器:vim vi
  • 查找字符串:grep
  • 创建空文件:touch

35.Linux中如何查看日志?

动态打印日志信息:tail -f 日志文件

36.Linux如何关闭进程?

  • 通常用ps查看进程PID,用kill命令终止进程
  • ps命令用于查看当前正在运行的容器
  • grep是搜索
  • 例如:ps -ef|grep java 表示查看所有进程里CMD是Java的进程信息
  • ps -aux|grep java
  • -aux是显示所有状态
  • kill命令用于终止进程
  • 例如:kill -9 [PID] -9表示强迫进程停止

37.SQL的select语句的完整执行过程

from子句组装来自不同数据源的数据 where子句基于指定的条件对记录进行筛选 group by子句将数据划分为多个分组 使用聚集函数进行计算 使用having子句筛选分组 计算所有的表达式 select的字段 使用order by对结果进行排序

38.SQL之聚集函数

聚集函数是对一组值进行计算并返回单一的值的函数,它经常与select语句中的group by 子句一同使用。

  • avg():返回的是指定组中的平均值,空值被忽略
  • count():返回的的是指定组中的项目个数
  • max():返回指定数据中的最大值
  • min():返回的是指定数据中的最小值
  • sun():返回的指定数据的和,只能用于数字列,空值忽略
  • group by():对数据进行分组,对执行完group by之后的组进行聚集函数的运算,计算每一组的值。最后用having去掉不符合条件的组,having子句中的每一个元素必须出现在select列表中。

39.SQL之连接查询(左连接和右连接的区别)

  • 外连接:
    • 左连接:以左表作为基准进行查询,左表数据会全部显示出来,右表如果和左表匹配的数据则显示相应字段的数据,如果不匹配则显示为null;
    • 右连接:以右表作为基准进行查询,右表的数据会全部显示出来,左表如果和右表匹配的数据则显示相应的字段的数据,如果不匹配则显示为null;
    • 全连接:先以左表进行左外连接,再以右表进行右外连接;
  • 内连接:
    • 显示表之间有连接匹配的所有行;

40.Mysql性能优化

  • 当只需要一行数据时使用limit 1
    • 查询时如果已经知道会得到一条数据,这种情况下加上limit 1会增加性能,因为mysql数据库引擎会在找到一条结果停止搜索,而不是继续查询下一条是否符合标准直到所有记录查询完毕。
  • 选择正确的数据库引擎
    • MyISAM 适用于一些大量查询的应用,但对于大量写的功能时的应用不是很好;
    • InnoDB的趋势回事一个非常负责的存储引擎,支持行锁,所以在写操作的时候会比较优秀,支持很多高级应用,比如事务;
  • 用not exists代替not in
    • not exits用到了连接能够发挥已经建立好的索引的作用,not in不能使用索引,not in 是最慢的方式要同每条记录比较,在数据量比较大的操作不建议使用这种方式。
  • 对操作符的优化,尽量不采用不利于索引的操作符
    • 比如 in ,not in ,is null, is not null, <>等,某个字段总要拿来索引,为其建立索引:mysql中可以利用alter table语句来为表中的字段添加索引,语法为:alter table 表名 add index(字段名)

41.事务的四大特征是什么?

数据库事务正确执行的四个基本要素,原子性,一致性,隔离性,持久性。

  • 原子性:整个事务中的操作,要么全部完成,要么全部不完成,不可能停滞到中间某一个环节,事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性:在事务开始之前和事务结束之后,数据库的完整性约束没有被破坏
  • 隔离性:隔离状态执行事务,使他们好像是系统在给定时间内执行的唯一的操作,如果有两个事务,运行在相同的时间内,执行,相同的功能,事务的隔离性将确保每一个事务在系统中认为只有该事务在使用系统,这种属性有时被称为串行化,为了防止事务操作见的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一个资源。
  • 持久性:在事务执行完之后,该事务所对数据库所作的更改边持久的保存在数据库中,并不会被回滚。

42.MySQL中四种隔离级别是什么?

Mybatis的核心对象以及编程步骤是什么

image.png 核心对象:

  • SqlSessionFactoryBuilder:SqlSession工厂的构建者对象,使用构造者模式创建SqlSession工厂对象
  • SqlSessionFactory:SqlSession工厂,使用工厂模式创建SqlSession对象
  • SqlSession:该对象可以操作数据库,也可以使用动态代理模式创建持久层接口的代理对象操纵数据库
  • Mapper:持久层接口的代理对象,它具体实现了持久层接口,用来操作数据库

工作流程

  1. 创建SqlSessionFactoryBuilder对象
  2. SqlSessionFactoryBuilder对象构建了SqlSessionFactory对象:构造者模式
  3. SqlSesionFactory对象生产了SqlSesion对象:工厂模式
  4. SqlSession对象创建了持久层接口的代理对象:动态代理模式
  5. 代理对象操作数据库

映射文件注意事项

  • 映射文件要和接口名称相同
  • 映射文件要和接口目录结构相同
  • 映射文件中的namespace属性要写接口接口全名
  • 映射文件中标签的id属性是接口方法的全名
  • 映射文件中的resultType属性是接口方法的返回值类型
  • 映射文件中的标签的parameterType属性是接口方法的参数类型
  • 映射文件中resultType.parameterTpye属性要写全类名

mybatis动态代理方式

  • SqlSession的getMapper方法,最终是调用的是JDK动态代理方法,生成一个代理对象,类型就是传入的接口类型。
  • MapperProxy对象通过调用MapperMethod的execute方法定义了代理方式,该方法的底层调用的是SqlSession的方法

Mybatis中#和$的区别?

  • #表示sql模板的占位符,$表示将字符串拼接到sql模板中。
  • #可以防止sql注入,一般能用#就不用$。
  • ${}内部的参数名必须写value。

主键回填

<insert id="add"parameterType="com.itbaizhan.user.User">
   <!-- keyProperty:主键属性名,keyColumn:主键列名,resultType:主键类型,order:执行时机 -->
   <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
      SELECT LAST_INSERT_ID();
   </selectKey>
  insert into user(username,sex,address) values(#{username},#{sex},#{address})
</insert>

SELECT LAST_INSERT_ID():查询刚刚插入的记录的主键值,只适用于自增主键,且必须和insert语句一起执行。

mybatis中一级缓存与二级缓存

如何判断两次sql是相同的

  • 查询的sql语句是相同的
  • 传递的参数值相同的
  • 对结果集的要求相同
  • 预编译的模板id相同

一级缓存

  • 一级缓存也就本地缓存。SqlSession对象中包含一个Executor对象,Executor对象中包含一个PerpetualCache对象,在该对象存放缓存数据。
  • 由于一级缓存是在SqlSession对象中,所以只有使用同一个SqlSession对象操作数据库时才能共享一级数据。
  • 一级缓存默认是开启的,不需要任何配置。

二级缓存

  • 二级缓存也叫做全局缓存,数据存放在SqlSessionFactory中,只要是同一个工厂对象创建的SqlSession,在进行查询时都能共享数据。一般项目中只有一个SqlSessionFactory对象,所以二级缓存的数据是全项目共享的。
  • 一级缓存存放的是对象,二级缓存存放的是对象的数据,所以要求二级缓存存放的POJO必须是可序列化的,也就是要实现Serializable接口。
  • 二级缓存默认不开启,手动开启后数据先存放在一级缓存中。只有一级缓存数据清空后,数据才会到二级缓存中。SqlSession 调用 clearCache() 无法将数据存到二级缓存中。 可以使用注解@CacheNamespace开启二级缓存

自定义映射关系,POJO属性名和数据库列明不一致时

此时使用@Results定义并使用自定义映射惯

谈谈你对spring的理解

spring是一个开源框架,为简化企业级开发而生,它以IOC(控制反转)和AOP(面向切面)为思想内核,提供了控制层springMVC和数据层springData服务层事务管理等众多技术,并可以整合众多第三方框架。spring将很多复杂的代码变得二优雅简洁,有效的降低了代码的耦合度,极大的方便项目的后期维护,升级和扩展。

Spring容器的主要核心是:

控制反转(IOC):传统的java开发模式中,当现需要一个对象时,我们会在自己使用new创建一个对象,而在sspring开发模式中,spring容器使用了工厂模式为我们创建了所需要的对象,不需要我们自己创建了,直接调用spring提供的对象就可以了,这就是控制反转的思想 面向切面编程(AOP):在面向对象思想中,我们将事务抽成一个个的对象,而在面向切面编程中,我们就将一个个的对象某些类似的问题横向抽成一个切面,对这个切面进行一些比如权限控制,事务管理,记录日志等公用操作处理的过程就是面向切面的编程思想。AOP底层是动态代理,如果是 接口采用的是JDK动态代理,如果是类CGLIB方式实现动态代理。

依赖注入 DI

依赖注入是spring控制反转思想的具体实现。控制反转将对象的创建交给spring,但是对象中可能会依赖于其他对象,简单来说,控制反转是创建对象,依赖注入是为对象的属性赋值。

依赖注入方式 setter注入 构造方法注入 自动注入

spring中的设计模式

单例模式————spring中两种代理模式,若目标对象实现了若干接口,spring使用JDK的代理,若目标对象没有实现任何接口,spring使用CGLIB库生成目标类的子类 前端控制器模式————spring提供了前端控制器DispatherServlet来对请求进行分发 工厂模式————在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个接口来指定新创建的对象,spring使用beanFactory来创建对象实例。

spring的常用注解

  • @Component
    • 作用:用于创建对象,放入spring容器中
    • 位置:类上方
  • @Repository @Service @Controller
    • 作用:和@Component作用一样,使用他们只是为了区分该类属于什么层
  • @Scope
    • 作用:用于指定bean的创建策略
    • 位置:类上方
    • 取值:singleton prototype request session globalsession
  • @Autowired
    • 作用:从容器中查找符合属性类型的对象自动注入属性中,用于代替bean中的依赖注入配置
    • 位置:属性上方 setter方法上方 构造方法上方
    • 注意:
      • 该注解写在属性上方进行起来注入时,可以省略setter方法
      • 容器中没有对应类型的对象会报错
      • 容器中有多个对象匹配类型时,会找beanld等于属性名的对象,找不到会报错。
  • @Qualifier
    • 作用:在按照类型注入的基础上,再按照bean的id注入
    • 位置:属性上方
    • 注意:该注解必须和@Autowired一起使用
  • @Value
    • 作用:注入String类型和基本数据类型的属性值
    • 位置:属性上方
  • @Configuration
    • 添加该注解在在类上方,表示该类是一个配置类
  • @Bean
    • 作用:将方法的返回值对象放入spring容器中,如果想将第三方类的对象放入容器,可以使用该注解。
  • @Import
    • 作用:如果配置类过多,该注解可以为主配置类导入其他配置类
    • 位置:主配置类上方

springAOP

即面向切面编程,是实现功能通一的维护的一种技术,将业务逻辑的各个部分进行隔离,使开发人员在编写业务逻辑的时候可以专心于核心业务,从而提高开发效率,AOP在不修改源码的基础上,对已有的方法进行增强

image.png

AOP相关术语

AspectJ是一个基于Java语言的AOP框架,在spring建议使用AspectJ实现AOP image.png

  • Joinpoint连接点:指的是能被拦截的点,在spring中只有方法能被拦截
  • Pointcut切点:指要对哪些连接点进行拦截,也就是被增强的方法
  • Advice通知:值得是拦截之后需要做的事情,即切点被拦截之后要做的事情
  • Aspect切面:切点+通知称为切面
  • Target目标:指的是被代理的对象
  • Proxy代理:代理对象
  • Weaving织入:生成代理对象的过程

AOP通知类型以及注解

在通知类上发加入注解 @Aspect

  • 前置通知:在方法执行前添加功能 @Before
  • 后置通知:在方法执行后添加功能 @AfterReturning
  • 异常通知:在方法抛出异常之后执行该通知 @AfterThrowing
  • 最终通知:无论方法是否抛出异常,都会执行该通知 @After
  • 环绕通知:在方法执行前后添加功能 @Around

spring事务

事务:指的是不可分割的原子操作,即一系列的操作要么同时成功,要么通知失败,开发过程中,事务管理一般在service层,业务层中可能会操作多次数据库,这些操作是不可分割的,否则程序报错误的时候,可能会造成数据库异常。

事务管理方案

在spring管理下不允许手动提交和回滚事务,此时我们需要使用sspring的事务管理方案,在spring框架中提供了两种事务管理方案:

  • 编程式事务:通过编写代码实现事务管理 很少用
  • 声明式事务:基于AOP技术实现事务管理 学习这个

使用AOP技术为service方法添加如下通知

image.png

spring bean的生命周期?

IOC对象的创建策略

spring通知配置bean中的scope属性设置对象的创建策略,共有5种创建策略:

  • singleton:单例,默认策略,整个项目只会创建一个对象
  • prototype:多例,每次从容器中获取时都会创建对象
  • request:每次请求都会创建一个对象 只有web环境有效
  • session:每次会话创建一个对象,只有在web环境下有效
  • gloabal-session:一次集群环境的会话创建一个对象,只有在web环境有效

spring框架中的单例bean是线程安全的嘛

不是线程安全的

spring能帮我们做什么

  • spring能帮我们根据配置文件创建及组装对象之间的依赖关系、
  • spring面向切面编程能帮我们无耦合的实现日志记录,性能统计,安全控制
  • spring能非常简单的帮我们管理数据库的事务
  • spring还能与第三方数据库访问框架无缝集成,而且自己也提供了一套JDBC访问模板,来方便数据库访问
  • spring能方便的与JavaEE整合,还能与更多的技术整合,比如缓存框架。 image.png

springMVC的组件

image.png

  • DispatcherServlet:前端控制器,接受所有的请求,调用其他的组件
  • HandlerMappering:处理器映射器,根据配置找到方法的执行链
  • HandlerAdapter:处理器适配器,根据方法的类型找到对应的处理器
  • ViewResolver:视图解析器,找到指定的视图

springMVC的工作原理

springMVC是一个基于MVC模式的轻量级的web框架,是spring框架的一个模块,和spring可以直接整合使用,springMVC代替了servlet技术,它通过一套注解,让一个简单的java类成为处理请求的控制器,而无需实现任何的接口。

  1. 客户端将请求发送给前端控制器
  2. 前端控制器将请求发送给处理器映射器,处理器映射器根据路径找到方法的执行链,返回给前端控制器
  3. 前端控制器将方法的执行链发送给处理器适配器,处理器适配器根据方法类型找到对应的处理器
  4. 处理器执行方法,将结果返回给前端控制器
  5. 前端控制器将结果发送给视图解析器,视图解析器找到视图文件的位置
  6. 视图渲染数据并将结果显示到客户端

springMVC常用的注解有哪些

  • @Controller
    • 作用:标记控制器,将控制器交给spring管理
    • 位置:类上方
  • @RequestMapping
    • 作用:给控制器方法设置请求路径
    • 位置:方法或者类上方,用于类上方,表示类中的所有控制器方法都是以该地址作为父路径
  • @ResponseBody
    • 作用:将方法返回的对象转换为JSON格式,并将JSON数据直接写入到输出流中,使用该注解之后不会再经过视图解析器,使用该注解可以处理AJAX请求
    • 位置:方法上方
  • @RequestBody
    • 作用:将请求中的JSON格式的参数转换为JAVA对象
    • 位置:写在方法参数前
  • @RestController
    • 如果一个控制器类下的所有控制器方法都返回JSON格式数据且不进行跳转,可以使用该注解代替@Controller,此时每个方法上的@ResponBody都可以省略
  • @RequestParam
    • 作用:在控制器方法中获取请求参数
    • 位置:方法参数前
    • 属性:
      • name:指定请求参数名称
      • defaultValue:为参数设置默认值
      • required:设置是否是必须要传入的参数
  • @RequestHeader
    • 作用:在控制器方法中获取请求头的数据
    • 位置:方法参数前
  • @CookieValue
    • 作用:在控制器方法中获取Cookie数据
    • 位置:方法参数前
  • @SessionAttributes
    • 作用:将Model模型的数据存入到Session域中
    • 位置:类上方
  • @ModelAtribute
    • 作用1:设置指定方法在控制器其他方法前执行
    • 位置:类上方
    • 作用2:从Model模型中获取数据给参数赋值
    • 位置:方法参数前
  • @PathVariable
    • 作用:在RESTful风格中的URL中获取占位符的值
    • 位置:方法参数前
    • 属性:
      • value:获取哪个占位符的值作为参数值,如果占位符和参数名相同,可以省略该属性。
  • @PostMapping. @GetMapping. @PutMapping. @DeleteMapping
    • 作用:简化该设置请求方式的@RequestMapping写法
    • 位置:方法上方

RESTful风格支持

RESTful风格是一种URL路径的上设计风格。在restful风格的URL路径中,网络上的任意数据都可以看成是一个资源,它可以是一段文本,一张图片,也可以是一个java对象,而每一个资源都会占据一个网路路径,无论是对资源进行增删改查,访问的路径都是一致的。优点:结构清晰,符合标准,易于理解,扩展方便

如何区分对该资源是哪一种操作,通过请求方式的不同,判断进行什么操作。

RESTful风格的的URL一共有四种请求方式:

  • GET请求:查询操作
  • POST请求:新增操作
  • DELETE请求:删除操作
  • PUT请求:修改操作

如何开启注解处理器和适配器

如何解决GET和POST乱码问题

  • 解决post请求乱码
    • 在web.xml中配置一个CharactEnodingFilter过滤器,设置为utf-8.
<!--SpringMVC中提供的字符编码过滤器,放在所有过滤器的最上方-->
<filter>
   <filter-name>encFilter</filter-name>
   <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
   <init-param>
       <param-name>encoding</param-name>
       <param-value>utf-8</param-value>
   </init-param>
</filter>
<filter-mapping>
   <filter-name>encFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
  • get请求中文参数的的乱码问题
    • 修改tomcat配置文件添加编码与工程编码一致
    • 对参数进行重新的编码。

单个控制器异常处理

在系统中,Dao Service Controller中代码都有可能抛出异常,如果哪里产生哪里处理,会降低开发效率,所以一般情况下,为我们会让异常向上抛出,最终到达DispatcherServlet中,此时pringMVC提供了异常处理器进行异常处理,这样可以提高开发效率

image.png 在方法上方添加注解 @ExceptionHandler ,属性为处理的异常类

全局异常处理

全局异常处理类需要在类上方添加注解 @ControllerAdvice,然后在方法上方添加注解 @ExceptionHandler

自定义异常处理器

自定义异常处理器需要实现HandlerExceptionResolver接口,并放入spring容器中。

拦截器以及拦截器和过滤器的区别

springMVC的拦截器也是AOP思想的一种实现,与serlvet的过滤器功能类似,主要用于拦截用户的请求并做相应额处理,通常使用在权限验证,记录i请求信息的日志,判断用户是否登录等功能上。

创建拦截器类需要实现HandlerInterceptor接口,需要重写三个方法

  • preHandler:请求到达控制器前执行的方法,返回值为true通过拦截器,返回值为false被拦截器拦截
  • postHandler:跳转到JSP前执行的方法
  • afterHandler:跳转到JSP之后执行的方法

拦截器和过滤器的区别

  • 拦截器是springMVC的组件,过滤器是servlet的组件
  • 拦截器不依赖web容器,而过滤器依赖web容器
  • 拦截器只能对控制器请求起作用,而过滤器可以对所有请求起作用
  • 拦截器可以直接获取IOC容器中的对象,而过滤器就不太方便获取

跨域请求

浏览器的安全功能是同源策略,同源指的是两个URL的协议,域名,端口相同,浏览器出于安全考虑,不同源的客户端脚本在没有明确授权的情况下不能读写对方资源。

跨域指的是协议,域名,端口三者中任意一个与当前页面URL不同时即为跨域。

sspringMVC提供了注解@CrossOrigin解决跨域问题,可以添加在类上方或者方法上方

谈谈你对redis的理解

Redis是C语言编写的,包含多种数据结构,支持网络,基于内存,可选持久性的键值对存储数据库。 特性:

  • 基于内存运行,性能高效
  • 支持分布式,理论上可以无限扩展
  • key-value存储系统

redis是多线程还单线程?

因为redis是基于内存的操作,CPU不是redis的瓶颈,Redis的瓶颈最有可能的是机器内存的大小或者网路带宽,既然但线程容易实现。而且CPU不会成为瓶颈,那就顺理成章的采用单线程的方案了。

Redis的数据类型

  • String
    • 简介:是redis的基本数据类型,一个key对应一个value,String是二进制安全的,意味着String可以包含任何数据,String最多可以放512M的数据。
    • 使用场景:计数器,统计多单位的数量,粉丝数,对象缓存存储,分布式锁
  • List
    • 简介:是最简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边),底层是一个双向链表,对两端操作性能极高,通过索引操作中间节点性能较差。
    • 使用场景:消息队列,排行榜,最新列表
  • Set
    • 简介:与List类似是一个列表功能,但set自动排重,当需要存储一个列表的数据,又不希望出现重复的元素的时候,该数据类型是一个很好的选择。Set是String类型的无需集合,他底层其实是一个value为null的hash表,所以添加,删除,查找的时间复杂度都是O(1).
    • 使用场景:黑白名单,随机展示,好友,关注人,粉丝,感兴趣的人的集合
  • Hash
    • 简介:Hash是一个键值对的集合,Hash是一个String类型的字段和值的映射表,hash特别适合于存储对象
    • Hash存储结构优化
      • 如果字段数少,存储结构优化为类数组类型
      • 如果字段较多,存储结构使用HashMap结构
      • 如果哈希表不存在,一个新的哈希表被创建并进行HSET操作
      • 如果字段已经存在与哈希表,旧值将被重写
    • 使用场景:购物车,存储对象
  • Zset
    • 简介:与set十分相似,是一个没有重复元素的String集合,不同之处在于Zset的每个元素都关联了一个分数,这个分数被用来按照从低到高的方式排序集合中的元素,集合的元素是唯一的,但分数可以重复。
    • 使用场景:延时队列 排行榜 限流
  • Bitmaps
    • 简介:用二进制作为存储信息的基本单位,一个字节等于8位。
    • 使用场景:活跃天数,打卡天数,登录天数,用户签到,统计活跃用户,统计用户是否在线
  • Geospatia
    • 简介:该类型就是元素的二维坐标,在地图上就是经纬度。
    • 使用场景:附近的电影院 附近的好友 离最近的火锅店

Redis数据安全持久化

由于Redi的数据都放在内存中,如果没有配置持久化,Redis重启后数据就全部消失了,于是需要开启Redi的持久化功能,将数据保存在磁盘上,当Redis重启后,可以从磁盘中恢复数据了。

Redis提供了两种不同形式的数据持久化机制

  • RDB
  • AOF

RDB

RDB也就是在指定的时间间隔内将内存的数据集快照写入磁盘,也就行话讲的快照,它恢复时是将快照文件直接读到内存里

image.png 注意:这种格式是经过压缩的二进制文件

触发机制

  • 配置新的保存规则:给redis.conf添加新的快照策略,多少秒内如果有多少次key的变化,则触发快照。配置修改之后,需要重启Redis服务。
  • flushall:执行flush命令,也会触发rdb规则
  • save与bgsave
    • 手动触发Redis进行RDB持久化的命令有两种:
      • save
        • 该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他问题,直到RDB过程完成为止,不建议使用。
      • bgsave
        • 执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求

优势:

  • 适合大规模的数据恢复
  • 对数据完整性和一致性要求不高更适合使用
  • 节省磁盘空间
  • 恢复速度快

劣势:

  • 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。

AOF

image.png AOF是以日志的形式来记录每个写操作,将Redishi执行过的所有写指令记录下来

image.png AOF默认不开启

优势

  • 备份机制更稳健,丢失数据概率更低。
  • 可读的日志文本,通过操作AOF稳健,可以处理误操作。 劣势
  • 比起RDB占用更多的磁盘空间。
  • 恢复备份速度要慢。
  • 每次读写都同步的话,有一定的性能压力。