Java中级:面试题-1

Java中级面试题

  • 序列化
  • 注解
  • 反射
    • 选择题
    • 填空题
    • 简答题
      • 反射机制
  • 数组
    • 选择题
    • 填空题
    • 简答题
    • 编程题
  • 集合
    • 选择题
    • 填空题
    • 简答题
      • ArrayList. LinkedList. Vector的底层实现和区别
      • HashMap和HashTable的底层实现和区别. 两者和ConcurrentHashMap的区别
      • Collection包结构. 与Collections的区别
      • Map. Set. List. Queue. Stack的特点与用法
      • Java基础之集合List-ArrayList. LinkedList. Vector的底层实现和区别
    • 编程题
  • IO流
    • 选择题
    • 填空题
    • 简答题
    • 编程题
  • Spring
    • 选择题
    • 填空题
    • 简答题
      • Spring是什么
      • SpringAOP,IOC实现原理
      • 解释一下Spring AOP里面的几个名词
      • Spring通知有哪些类型
      • 讲讲Spring事务的传播属性
      • Spring如何管理事务的
      • Spring事务的实现方式和实现原理
      • BeanFactory和ApplicationContext有什么区别?
      • 请解释Spring Bean的生命周期
      • 解释Spring支持的几种bean的作用域
      • Spring框架中的单例Beans是线程安全的么
      • Spring如何处理线程并发问题
      • Spring的自动装配
      • Spring 框架中都用到了哪些设计模式
      • Spring框架中有哪些不同类型的事件
      • spring、springMvc、springBoot和springCloud的联系与区别
    • 编程题
  • SpringBoot
    • 选择题
    • 填空题
    • 简答题
      • springboot启动机制
      • SpringBoot的优点
    • 编程题
  • SpringCloud
    • 选择题
    • 填空题
    • 简答题
    • 编程题
  • Mybatis
    • 选择题
    • 填空题
    • 简答题
    • 编程题
  • SpringMVC
    • 选择题
    • 填空题
    • 简答题
      • SpringMvc的工作原理
      • Springmvc中DispatcherServlet初始化过程
      • springmvc用到的注解. 作用是什么. 原理
      • spring的controller是单例还是多例. 怎么保证并发的安全
      • SpirngMVC的生命周期 和 SpringBean的生命周期
    • 编程题

序列化

注解

反射

选择题

填空题

简答题

反射机制

JAVA反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性; 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.

主要作用有三:

  1. 运行时取得类的方法和字段的相关信息。
  2. 创建某个类的新实例(.newInstance())
  3. 取得字段引用直接获取和设置对象字段. 无论访问修饰符是什么。

用处如下:

  1. 观察或操作应用程序的运行时行为。
  2. 调试或测试程序. 因为可以直接访问方法. 构造函数和成员字段。
  3. 通过名字调用不知道的方法并使用该信息来创建对象和调用方法。

数组

选择题

  • 执行完以下代码int [ ] x = new int[10];后. 以下哪项说明是正确的( A )
    A.x[9]为0
    B.x[9]未定义
    C.x[10]为0
    D.x[0]为空

  • 下面哪个语句(初始化数组)是不正确的:( B )
    A: int x[] = {1,2,3};
    B: int x[3] = {1,2,3};
    C: int[] x = {1,2,3};
    D: int x[] = new int[]{1,2,3};

  • 给出下面代码:

  public class Person{ 
    static int arr[] = new int[10];
    public static void main(String a[]) 
    { 
     System.out.println(arr[1]); 
    } 
  } 

  那个语句是正确的? ( C )
  A. 编译时将产生错误;
  B. 编译时正确. 运行时将产生错误;
  C . 输出零;
  D. 输出空。

  • 下面哪条语句定义了5个元素的数组( A )
    A. int [] a={22,23,24,25,12};
    B. int a []=new int(5);
    C. int [5] array;
    D. int [] arr;

  • 下面表达式中. 用来访问数组中第一个值的是( C )
    A. intArray[1]
    B. intArray.1
    C.intArray[0]
    D. intArray.0

填空题

  • ______是相同类型的数据按顺序组成的一种复合数据类型。数组
  • 数组是一组相同类型变量的集合,其下标是从 0 开始算的。
  • Java中定义数组后通过____加数组下标,来使用数组中的数据。数组名
  • Java中声明数组包括数组的名字. 数组包含的元素的___。数据类型
  • __仅仅是给出了数组名字和元素的数据类型,要想真正的使用数组还必须为它分配内存空间。声明数组
  • 数组声明后,必须使用____运算符分配内存空间。new
  • 声明数组仅仅是给出了数组名字和元素的数据类型,要想真正地使用数组还必须为它___。分配内存空间
  • 维数组通过下标符访问自己的元素,需要注意的是下标从___开始。**0 **
  • 创建数组后,系统会给每一个数组元素一个默认的值,如float型是__。0.0

简答题

编程题

集合

选择题

  • 下面哪个不是Collection接口的方法?( D )
    A. iterator
    B. isEmpty
    C. toArray
    D. setText
  • 欲构造ArrayList类的一个实例. 此类继承了List接口. 下列哪个方法是正确的 ( B )
    A. ArrayList myList=new Object();
    B. List myList=new ArrayList();
    C. ArrayList myList=new List();
    D. List myList=new List();

填空题

简答题

ArrayList. LinkedList. Vector的底层实现和区别

从同步性来看. ArrayList和LinkedList是不同步的. 而Vector是的。所以线程安全的话. 可以使用ArrayList或LinkedList. 可以节省为同步而耗费的开销。但在多线程下. 有时候就不得不使用Vector了。当然. 也可以通过一些办法包装ArrayList. LinkedList. 使我们也达到同步. 但效率可能会有所降低。

从内部实现机制来讲ArrayList和Vector都是使用Object的数组形式来存储的。当你向这两种类型中增加元素的时候. 如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度. Vector缺省情况下自动增长原来一倍的数组长度. ArrayList是原来的50%. 所以最后你获得的这个集合所占的空间总是比你实际需要的要大。如果你要在集合中保存大量的数据. 那么使用Vector有一些优势. 因为你可以通过设置集合的初始化大小来避免不必要的资源开销。

ArrayList和Vector中. 从指定的位置(用index)检索一个对象. 或在集合的末尾插入. 删除一个对象的时间是一样的. 可表示为O(1)。但是. 如果在集合的其他位置增加或者删除元素那么花费的时间会呈线性增长O(n-i). 其中n代表集合中元素的个数. i代表元素增加或移除元素的索引位置. 因为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行(n-i)个对象的位移操作。LinkedList底层是由双向循环链表实现的. LinkedList在插入. 删除集合中任何位置的元素所花费的时间都是一样的O(1). 但它在索引一个元素的时候比较慢. 为O(i). 其中i是索引的位置. 如果只是查找特定位置的元素或只在集合的末端增加. 移除元素. 那么使用Vector或ArrayList都可以。如果是对其它指定位置的插入. 删除操作. 最好选择LinkedList。

HashMap和HashTable的底层实现和区别. 两者和ConcurrentHashMap的区别

HashTable线程安全则是依靠方法简单粗暴的sychronized修饰. HashMap则没有相关的线程安全问题考虑。。

在以前的版本貌似ConcurrentHashMap引入了一个“分段锁”的概念. 具体可以理解为把一个大的Map拆分成N个小的HashTable. 根据key.hashCode()来决定把key放到哪个HashTable中。在ConcurrentHashMap中. 就是把Map分成了N个Segment. put和get的时候. 都是现根据key.hashCode()算出放到哪个Segment中。

通过把整个Map分为N个Segment(类似HashTable). 可以提供相同的线程安全. 但是效率提升N倍。

Collection包结构. 与Collections的区别

Collection是一个接口. 它是Set. List等容器的父接口;Collections是一个工具类. 提供了一系列的静态方法来辅助容器操作. 这些方法包括对容器的搜索. 排序. 线程安全化等等。

Map. Set. List. Queue. Stack的特点与用法

Collection 是对象集合. Collection 有两个子接口 List 和 Set

List 可以通过下标 (1,2…) 来取得值. 值可以重复

而 Set 只能通过游标来取值. 并且值是不能重复的

ArrayList . Vector . LinkedList 是 List 的实现类

ArrayList 是线程不安全的. Vector 是线程安全的. 这两个类底层都是由数组实现的

LinkedList 是线程不安全的. 底层是由链表实现的

Map 是键值对集合

HashTable 和 HashMap 是 Map 的实现类
HashTable 是线程安全的. 不能存储 null 值
HashMap 不是线程安全的. 可以存储 null 值

Stack类:继承自Vector. 实现一个后进先出的栈。提供了几个基本方法. push. pop. peak. empty. search等。

Queue接口:提供了几个基本方法. offer. poll. peek等。已知实现类有LinkedList. PriorityQueue等。

Java基础之集合List-ArrayList. LinkedList. Vector的底层实现和区别

ArrayList底层实际是采用数组实现的(并且该数组的类型是Object类型的)

如果jdk6,采用Array.copyOf()方法来生成一个新的数组. 如果是jdk5. 采用的是System.arraycopy()方法(当添加的数据量大于数组的长度的时候)

List list = new ArrayList()时. 底层会生成一个长度为10的数组来存放对象
ArrayList. Vector底部都是采用数组实现的
对于ArrayList. 方法都不是同步的. 对于Vector. 大部分public方法都是同步的
LinkedList采用双向循环列表

对于ArrayList. 查询速度很快. 增加和删除(非最后一个节点)操作非常慢(本质上由数组的特性决定的)

对于LinkedList. 查询速度非常慢. 增加和删除操作非常快(本质上是由双向循环列表决定的)

编程题

IO流

选择题

  • 要从文件" file.dat"文件中读出第10个字节到变量C中,下列哪个方法适合? ( A )
    A. FileInputStream in=new FileInputStream(“file.dat”); in.skip(9); int c=in.read();
    B. FileInputStream in=new FileInputStream(“file.dat”); in.skip(10); int c=in.read();
    C. FileInputStream in=new FileInputStream(“file.dat”); int c=in.read();
    D. RandomAccessFile in=new RandomAccessFile(“file.dat”); in.skip(9); int c=in.readByte();

填空题

  • 根据流的运行方向. 流分为输入流和 输出流 。
  • java.io 包提供了处理输入/输出任务的类。
  • Java中的数据流包括字节流和 字符 流两种。
  • 在java.io包中有4个基本类:InputStream、OutputStream、Reader及 Writer 类。
  • 在io类库中. InputStream和 OutputStream 是处理字节数据的基本输入/输出类。
  • java.io类库中. 处理字符数据的基本输入/输出的类是 Reader 和 Writer 。
  • 用于字符流读写缓冲存储的类是BufferedReader和BufferedWriter 。
  • 对于文件输入流. 要实现读取数据的操作. 需使用 read() 方法。
  • 用于字符文件的输入/输出的类是 FileReader 和FileWriter。
  • 对于文件输出流. 使用 write() 方法把数据发送到输出流通道。
  • 要实现对数据的 读写 操作. 需要读方法和写方法来完成。
  • 从输入流中按行读取字符的方法是 readLine() 。
  • 为了将尚未填满的缓冲区的数据送往输出流通道. 使用 flash() 方法来实现。
  • 数据的读写操作完毕后. 应用 close() 方法来关闭流并释放资源。
  • 数据流类分为DataInputStream和 DataOutputStream 。
  • 允许程序按机器无关的格式读取Java原始数据的输入流类是DataInputStream 。
  • Java可以将对象作为一个整体通过OutputStream 流进行传输和存储。
  • 通常把描述对象状态的数值写入字节流的过程称为 串行化 。

简答题

编程题

Spring

选择题

填空题

简答题

Spring是什么

Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架. 目的是用于简化企业应用程序的开发. 它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置。

主要由以下几个模块组成:
Spring Core:核心类库. 提供IOC服务;
Spring Context:提供框架式的Bean访问方式. 以及企业级功能(JNDI、定时任务等);
Spring AOP:AOP服务;
Spring DAO:对JDBC的抽象. 简化了数据访问异常的处理;
Spring ORM:对现有的ORM框架的支持;
Spring Web:提供了基本的面向Web的综合特性. 例如多方文件上传;
Spring MVC:提供面向Web应用的Model-View-Controller实现。
Spring5框架图
Java中级:面试题-1_第1张图片

Spring5 系统架构-详解

SpringAOP,IOC实现原理

(1)AOP

AOP思想的实现一般都是基于代理模式 . 在JAVA中一般采用JDK动态代理模式. 但是我们都知道. JDK动态代理模式只能代理接口而不能代理类。因此. Spring AOP 会这样子来进行切换. 因为Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理。

  1. 如果目标对象的实现类实现了接口. Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
  2. 如果目标对象的实现类没有实现接口. Spring AOP 将会采用 CGLIB 来生成 AOP 代理类——不过这个选择过程对开发者完全透明、开发者也无需关心。

AspectJ是一个AOP框架. 它能够对java代码进行AOP编译(一般在编译期进行). 让java代码具有AspectJ的AOP功能(当然需要特殊的编译器). 可以这样说AspectJ是目前实现AOP框架中最成熟. 功能最丰富的语言. 更幸运的是. AspectJ与java程序完全兼容. 几乎是无缝关联. 因此对于有java编程基础的工程师. 上手和使用都非常容易。

Spring注意到AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器). 因此Spring很机智回避了这点. 转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入). 这是与AspectJ(静态织入)最根本的区别。

(2)IOC

IOC是Inversion of Control的缩写. 多数书籍翻译成“控制反转”. 还有些书籍翻译成为“控制反向”或者“控制倒置”。
Java中级:面试题-1_第2张图片

IOC解耦过程

解释一下Spring AOP里面的几个名词

(1)切面(Aspect):被抽取的公共模块. 可能会横切多个对象。 在Spring AOP中. 切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。

(2)连接点(Join point):指方法. 在Spring AOP中. 一个连接点 总是 代表一个方法的执行。

(3)通知(Advice):在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型. 其中包括“around”、“before”和“after”等通知。许多AOP框架. 包括Spring. 都是以拦截器做通知模型. 并维护一个以连接点为中心的拦截器链。

(4)切入点(Pointcut):切入点是指 我们要对哪些Join point进行拦截的定义。通过切入点表达式. 指定拦截的方法. 比如指定拦截add、search。

(5)引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如. 你可以使用一个引入来使bean实现 IsModified 接口. 以便简化缓存机制。

(6)目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的. 这个对象永远是一个 被代理(proxied) 对象。

(7)织入(Weaving):指把增强应用到目标对象来创建新的代理对象的过程。Spring是在运行时完成织入。

切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键. 这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如. 一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。

Spring通知有哪些类型

(1)前置通知(Before advice):在某连接点(join point)之前执行的通知. 但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

(2)返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如. 一个方法没有抛出任何异常. 正常返回。

(3)抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。

(4)后通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

(5)环绕通知(Around Advice):包围一个连接点(join point)的通知. 如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架. 例如Nanning和JBoss4. 都只提供环绕通知。

同一个aspect. 不同advice的执行顺序:

①没有异常情况下的执行顺序:

around before advice
before advice
target method 执行
around after advice
after advice
afterReturning

②有异常情况下的执行顺序:

around before advice
before advice
target method 执行
around after advice
after advice
afterThrowing:异常发生
java.lang.RuntimeException: 异常发生

讲讲Spring事务的传播属性

propagation(传播行为)
spring事务的传播行为有7种。

  1. propagation_required 当前没有事务变创建一个事务. 如有有则使用
  2. propagation_supports 支持当前事务. 有则使用. 没有则不使用
  3. propagation_mandatory 支持当前事务. 有则使用. 没有则抛出异常
  4. propagation_requires_new 无论有没有. 都创建新事务
  5. propagation_not_supported 非事务方式提交. 有则挂起该事务
  6. propagation_never 非事务提交. 有则抛出异常
  7. propagation_nested 存在事务. 在嵌套事务内执行. 没有. 则创建一个事务

Spring如何管理事务的

1)PlatformTransactionManager:事务管理器–主要用于平台相关事务的管理

主要有三个方法:

  1. commit 事务提交;
  2. rollback 事务回滚;
  3. getTransaction 获取事务状态。

2)TransactionDefinition:事务定义信息–用来定义事务相关的属性. 给事务管理器PlatformTransactionManager使用

这个接口有下面四个主要方法:

  1. getIsolationLevel:获取隔离级别;
  2. getPropagationBehavior:获取传播行为;
  3. getTimeout:获取超时时间;
  4. isReadOnly:是否只读(保存、更新、删除时属性变为false–可读写. 查询时为true–只读)

事务管理器能够根据这个返回值进行优化. 这些事务的配置信息. 都可以通过配置文件进行配置。

3)TransactionStatus:事务具体运行状态–事务管理过程中. 每个时间点事务的状态信息。

例如它的几个方法:

  1. hasSavepoint():返回这个事务内部是否包含一个保存点.
  2. isCompleted():返回该事务是否已完成. 也就是说. 是否已经提交或回滚

Spring事务的实现方式和实现原理

Spring事务的本质其实就是数据库对事务的支持. 没有数据库的事务支持. spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。

(1)Spring事务的种类:

spring支持编程式事务管理和声明式事务管理两种方式:

①编程式事务管理使用TransactionTemplate。

②声明式事务管理建立在AOP之上的。其本质是通过AOP功能. 对方法前后进行拦截. 将事务处理的功能编织到拦截的方法中. 也就是在目标方法开始之前加入一个事务. 在执行完目标方法之后根据执行情况提交或者回滚事务。

声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码. 只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式. 便可以将事务规则应用到业务逻辑中。

声明式事务管理要优于编程式事务管理. 这正是spring倡导的非侵入式的开发方式. 使业务代码不受污染. 只要加上注解就可以获得完全的事务支持。唯一不足地方是. 最细粒度只能作用到方法级别. 无法做到像编程式事务那样可以作用到代码块级别。

(2)spring的事务传播行为:

spring事务的传播行为说的是. 当多个事务同时存在的时候. spring如何处理这些事务的行为。

① PROPAGATION_REQUIRED:如果当前没有事务. 就创建一个新事务. 如果当前存在事务. 就加入该事务. 该设置是最常用的设置。

② PROPAGATION_SUPPORTS:支持当前事务. 如果当前存在事务. 就加入该事务. 如果当前不存在事务. 就以非事务执行。‘

③ PROPAGATION_MANDATORY:支持当前事务. 如果当前存在事务. 就加入该事务. 如果当前不存在事务. 就抛出异常。

④ PROPAGATION_REQUIRES_NEW:创建新事务. 无论当前存不存在事务. 都创建新事务。

⑤ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作. 如果当前存在事务. 就把当前事务挂起。

⑥ PROPAGATION_NEVER:以非事务方式执行. 如果当前存在事务. 则抛出异常。

⑦ PROPAGATION_NESTED:如果当前存在事务. 则在嵌套事务内执行。如果当前没有事务. 则按REQUIRED属性执行。

(3)Spring中的隔离级别:

① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别. 使用数据库默认的事务隔离级别。

② ISOLATION_READ_UNCOMMITTED:读未提交. 允许另外一个事务可以看到这个事务未提交的数据。

③ ISOLATION_READ_COMMITTED:读已提交. 保证一个事务修改的数据提交后才能被另一事务读取. 而且能看到该事务对已有记录的更新。

④ ISOLATION_REPEATABLE_READ:可重复读. 保证一个事务修改的数据提交后才能被另一事务读取. 但是不能看到该事务对已有记录的更新。

⑤ ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。

BeanFactory和ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口. 都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

1、BeanFactory:是Spring里面最底层的接口. 包含了各种Bean的定义. 读取bean配置文档. 管理bean的加载、实例化. 控制bean的生命周期. 维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生. 除了提供BeanFactory所具有的功能外. 还提供了更完整的框架功能:

  • 继承MessageSource. 因此支持国际化。
  • 统一的资源文件访问方式。
  • 提供在监听器中注册bean的事件。
  • 同时加载多个配置文件。
  • 载入多个(有继承关系)上下文 . 使得每一个上下文都专注于一个特定的层次. 比如应用的web层。

2、BeanFactroy采用的是延迟加载形式来注入Bean的. 即只有在使用到某个Bean时(调用getBean()). 才对该Bean进行加载实例化。这样. 我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入. BeanFacotry加载后. 直至第一次使用调用getBean方法才会抛出异常。

ApplicationContext. 它是在容器启动时. 一次性创建了所有的Bean。这样. 在容器启动时. 我们就可以发现Spring中存在的配置错误. 这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean. 通过预载入单实例bean ,确保当你需要的时候. 你就不用等待. 因为它们已经创建好了。

相对于基本的BeanFactory. ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时. 程序启动较慢。

3、BeanFactory通常以编程的方式被创建. ApplicationContext还能以声明的方式创建. 如使用ContextLoader。

4、BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用. 但两者之间的区别是:BeanFactory需要手动注册. 而ApplicationContext则是自动注册。

请解释Spring Bean的生命周期

首先说一下Servlet的生命周期:实例化. 初始init. 接收请求service. 销毁destroy;

Spring上下文中的Bean生命周期也类似. 如下:
Java中级:面试题-1_第3张图片
(1)实例化Bean:

对于BeanFactory容器. 当客户向容器请求一个尚未初始化的bean时. 或初始化bean的时候需要注入另一个尚未初始化的依赖时. 容器就会调用createBean进行实例化。对于ApplicationContext容器. 当容器启动结束后. 通过获取BeanDefinition对象中的信息. 实例化所有的bean。

(2)设置对象属性(依赖注入):

实例化后的对象被封装在BeanWrapper对象中. 紧接着. Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

(3)处理Aware接口:

接着. Spring会检测该对象是否实现了xxxAware接口. 并将相关的xxxAware实例注入给Bean:

①如果这个Bean已经实现了BeanNameAware接口. 会调用它实现的setBeanName(String beanId)方法. 此处传递的就是Spring配置文件中Bean的id值;

②如果这个Bean已经实现了BeanFactoryAware接口. 会调用它实现的setBeanFactory()方法. 传递的是Spring工厂自身。

③如果这个Bean已经实现了ApplicationContextAware接口. 会调用setApplicationContext(ApplicationContext)方法. 传入Spring上下文;

(4)BeanPostProcessor:

如果想对Bean进行一些自定义的处理. 那么可以让Bean实现了BeanPostProcessor接口. 那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 与 init-method:

如果Bean在Spring配置文件中配置了 init-method 属性. 则会自动调用其配置的初始化方法。

(6)如果这个Bean实现了BeanPostProcessor接口. 将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的. 所以可以被应用于内存或缓存技术;

以上几个步骤完成后. Bean就已经被正确创建了. 之后就可以使用这个Bean了。

(7)DisposableBean:

当Bean不再需要时. 会经过清理阶段. 如果Bean实现了DisposableBean这个接口. 会调用其实现的destroy()方法;

(8)destroy-method:

最后. 如果这个Bean的Spring配置中配置了destroy-method属性. 会自动调用其配置的销毁方法。

解释Spring支持的几种bean的作用域

Spring容器中的bean可以分为5个范围:

(1)singleton:默认. 每个容器中只有一个bean的实例. 单例的模式由BeanFactory自身来维护。

(2)prototype:为每一个bean请求提供一个实例。

(3)request:为每一个网络请求创建一个实例. 在请求完成以后. bean会失效并被垃圾回收器回收。

(4)session:与request范围类似. 确保每个session中有一个bean的实例. 在session过期后. bean会随之失效。

(5)global-session:全局作用域. global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时. 它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话. 那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。

Spring框架中的单例Beans是线程安全的么

Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上. 大部分的Spring bean并没有可变的状态(比如Serview类和DAO类). 所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象). 就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

Spring如何处理线程并发问题

在一般情况下. 只有无状态的Bean才可以在多线程环境下共享. 在Spring中. 绝大部分Bean都可以声明为singleton作用域. 因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理. 解决线程安全问题。

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式. 仅提供一份变量. 不同的线程在访问前需要获取锁. 没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。

ThreadLocal会为每一个线程提供一个独立的变量副本. 从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本. 从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象. 在编写多线程代码时. 可以把不安全的变量封装进ThreadLocal。

Spring的自动装配

在spring中. 对象无需自己查找或创建与其关联的其他对象. 由容器负责把需要相互协作的对象引用赋予各个对象. 使用autowire来配置自动装载模式。

在Spring框架xml配置中共有5种自动装配:

(1)no:默认的方式是不进行自动装配的. 通过手工设置ref属性来进行装配bean。

(2)byName:通过bean的名称进行自动装配. 如果一个bean的 property 与另一bean 的name 相同. 就进行自动装配。

(3)byType:通过参数的数据类型进行自动装配。

(4)constructor:利用构造函数进行装配. 并且构造函数的参数通过byType进行装配。

(5)autodetect:自动探测. 如果有构造方法. 通过 construct的方式自动装配. 否则使用 byType的方式自动装配。

基于注解的方式:

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置. 。在启动spring IoC时. 容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器. 当容器扫描到@Autowied、@Resource或@Inject时. 就会在IoC容器自动查找需要的bean. 并装配给该对象的属性。在使用@Autowired时. 首先在容器中查询对应类型的bean:

如果查询结果刚好为一个. 就将该bean装配给@Autowired指定的数据;

如果查询的结果不止一个. 那么@Autowired会根据名称来查找;

如果上述查找的结果为空. 那么会抛出异常。解决方法时. 使用required=false。

@Autowired可用于:构造函数、成员变量、Setter方法

注:@Autowired和@Resource之间的区别

(1) @Autowired默认是按照类型装配注入的. 默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

(2) @Resource默认是按照名称来装配注入的. 只有当找不到与名称匹配的bean才会按照类型来装配注入。

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

(1)工厂模式:BeanFactory就是简单工厂模式的体现. 用来创建对象的实例;

(2)单例模式:Bean默认为单例模式。

(3)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;

(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。

(5)观察者模式:定义对象键一种一对多的依赖关系. 当一个对象的状态发生改变时. 所有依赖于它的对象都会得到通知被制动更新. 如Spring中listener的实现–ApplicationListener。

Spring框架中有哪些不同类型的事件

Spring 提供了以下5种标准的事件:

(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。

(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时. 其管理的所有单例Bean都被销毁。

(5)请求处理事件(RequestHandledEvent):在Web应用中. 当一个http请求(request)结束触发该事件。

如果一个bean实现了ApplicationListener接口. 当一个ApplicationEvent 被发布以后. bean会自动被通知。

spring、springMvc、springBoot和springCloud的联系与区别

spring和springMvc:

  1. spring是一个一站式的轻量级的java开发框架. 核心是控制反转(IOC)和面向切面(AOP). 针对于开发的WEB层(springMvc)、业务层(Ioc)、持久层(jdbcTemplate)等都提供了多种配置解决方案;
  2. springMvc是spring基础之上的一个MVC框架. 主要处理web开发的路径映射和视图渲染. 属于spring框架中WEB层开发的一部分;

springMvc和springBoot:

  1. springMvc属于一个企业WEB开发的MVC框架. 涵盖面包括前端视图开发、文件配置、后台接口逻辑开发等. XML、config等配置相对比较繁琐复杂;
  2. springBoot框架相对于springMvc框架来说. 更专注于开发微服务后台接口. 不开发前端视图. 同时遵循默认优于配置. 简化了插件配置流程. 不需要配置xml. 相对springmvc. 大大简化了配置流程;

springBoot和springCloud:

  1. spring boot使用了默认大于配置的理念. 集成了快速开发的spring多个插件. 同时自动过滤不需要配置的多余的插件. 简化了项目的开发配置流程. 一定程度上取消xml配置. 是一套快速配置开发的脚手架. 能快速开发单个微服务;
  2. spring cloud大部分的功能插件都是基于springBoot去实现的. springCloud关注于全局的微服务整合和管理. 将多个springBoot单体微服务进行整合以及管理; springCloud依赖于springBoot开发. 而springBoot可以独立开发;

总结:

  1. Spring 框架就像一个家族. 有众多衍生产品例如 boot、security、jpa等等。但他们的基础都是Spring的ioc、aop等. ioc 提供了依赖注入的容器. aop解决了面向横切面编程. 然后在此两者的基础上实现了其他延伸产品的高级功能;
  2. springMvc是基于Servlet 的一个MVC框架主要解决WEB开发的问题. 因为Spring的配置非常复杂. 各种XML、JavaConfig、servlet处理起来比较繁琐;
  3. 为了简化开发者的使用. 从而创造性地推出了springBoot框架. 默认优于配置. 简化了springMvc的配置流程;但区别于springMvc的是. springBoot专注于微服务方面的接口开发. 和前端解耦. 虽然springBoot也可以做成springMvc前后台一起开发. 但是这就有点不符合springBoot框架的初衷了;
  4. 对于springCloud框架来说. 它和springBoot一样. 注重的是微服务的开发. 但是springCloud更关注的是全局微服务的整合和管理. 相当于管理多个springBoot框架的单体微服务;

编程题

SpringBoot

选择题

填空题

简答题

springboot启动机制

Spring的ApplicationContext容器内部中的所有事件类型均继承自org.springframework.context.AppliationEvent. 容器中的所有监听器都实现org.springframework.context.ApplicationListener接口. 并且以bean的形式注册在容器中。一旦在容器内发布ApplicationEvent及其子类型的事件. 注册到容器的ApplicationListener就会对这些事件进行处理。

  1. SpringBoot整个启动流程分为两个步骤:初始化一个SpringApplication对象、执行该对象的run方法。
  2. 通过SpringFactoriesLoader查找并加载所有的SpringApplicationRunListeners. 通过调用starting()方法通知所有的SpringApplicationRunListeners:应用开始启动了。

SpringBoot的优点

  1. 快速构建项目. 极大的提高了开发、部署效率。
  2. 对主流开发框架的无配置集成。
  3. 项目可独立运行. 无须外部依赖Servlet容器。
  4. 提供运行时的应用监控。

编程题

SpringCloud

选择题

填空题

简答题

编程题

Mybatis

选择题

填空题

简答题

编程题

SpringMVC

选择题

填空题

简答题

SpringMvc的工作原理

Java中级:面试题-1_第4张图片
SpringMVC的具体工作原理

1、客户端用户发送请求至前端控制器DispatcherServlet。

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 HandlerMapping处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找). 生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、DispatcherServlet调用HandlerAdapter处理器适配器. HandlerAdapter经过适配调用具体的处理器(Controller. 也叫后端控制器)。

5、Controller控制器执行完成返回ModelAndView. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

6、 DispatcherServlet前端控制器将ModelAndView传给ViewReslover视图解析器。

7、 ViewReslover解析后返回具体View。

8、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中). 并返回给客户端用户。

SpringMVC框架组件说明:

以下组件通常使用框架提供实现:

DispatcherServlet:作为前端控制器. 整个流程控制的中心. 控制其它组件执行. 统一调度. 降低组件之间的耦合性. 提高每个组件的扩展性。

HandlerMapping:通过扩展处理器映射器实现不同的映射方式. 例如:配置文件方式. 实现接口方式. 注解方式等。

HandlAdapter:通过扩展处理器适配器. 支持更多类型的处理器。

ViewResolver:通过扩展视图解析器. 支持更多类型的视图解析. 例如:jsp、freemarker、pdf、excel等。

各个组件的具体作用:

1、前端控制器DispatcherServlet(不需要工程师开发),由框架提供

作用:接收请求. 响应结果. 相当于转发器. 中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。

用户请求到达前端控制器. 它就相当于mvc模式中的c. dispatcherServlet是整个流程控制的中心. 由它调用其它组件处理用户的请求. dispatcherServlet的存在降低了组件之间的耦合性。

2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供

作用:根据请求的url查找Handler

HandlerMapping负责根据用户请求找到Handler即处理器. springmvc提供了不同的映射器实现不同的映射方式. 例如:配置文件方式. 实现接口方式. 注解方式等。

3、处理器适配器HandlerAdapter

作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler

通过HandlerAdapter对处理器进行执行. 这是适配器模式的应用. 通过扩展适配器可以对更多类型的处理器进行执行。

4、处理器Handler(需要工程师开发)

注意:编写Handler时按照HandlerAdapter的要求去做. 这样适配器才可以去正确执行Handler

Handler 是继DispatcherServlet前端控制器的后端控制器. 在DispatcherServlet的控制下Handler对具体的用户请求进行处理。

由于Handler涉及到具体的用户业务请求. 所以一般情况需要工程师根据业务需求开发Handler。

5、视图解析器View resolver(不需要工程师开发),由框架提供

作用:进行视图解析. 根据逻辑视图名解析成真正的视图(view)

View Resolver负责将处理结果生成View视图. View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址. 再生成View视图对象. 最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型. 包括:jstlView、freemarkerView、pdfView等。

一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户. 需要由工程师根据业务需求开发具体的页面。

6、视图View(需要工程师开发页面渲染)

View是一个接口. 实现类支持不同的View类型(jsp、freemarker、pdf…)

简单了解下MVC:常说的 MVC 是一种设计模式. 并不是SpringMVC框架(只是该框架支持这种MVC模式)

MVC的原理图:
Java中级:面试题-1_第5张图片
MVC的具体指向:

M-Model 模型(完成业务逻辑:有javaBean构成. service+dao+entity)

V-View 视图(做界面的展示 jsp. html……)

C-Controller 控制器(接收请求—>调用模型—>根据结果派发页面)

SpringMVC是什么:

SpringMVC是一个MVC的开源框架. springMVC就相当于是Struts2与Sring框架的整合. 但是这里有一个疑惑就是. SpringMVC和Spring是什么样的关系呢?这个在百度百科上有一个很好的解释:意思是说. SpringMVC是Spring框架的一个后续产品(一个模块). 其实就是Spring在原有基础上. 又提供了web应用的MVC模块. 可以简单的把SpringMVC理解为是Spring的一个模块(类似AOP. IOC这样的模块). 网络上经常会说SpringMVC和Spring无缝集成. 其实SpringMVC就是Spring的一个子模块. 所以根本不需要同spring进行整合。

Springmvc中DispatcherServlet初始化过程

了解DispatcherServlet的初始化过程. 来看一下他的initStrategies()方法

protected void initStrategies(ApplicationContext context) { 

	initMultipartResolver(context); 	
	initLocaleResolver(context);     
	initThemeResolver(context); 
	initHandlerMappings(context); 
	initHandlerAdapters(context); 
	initHandlerExceptionResolvers(context); 
	initRequestToViewNameTranslator(context);  
	initViewResolvers(context); 
	initFlashMapManager(context);
}
  1. initMultipartResolver(context); 初始化文件上传服务。
  2. initLocaleResolver(context); 初始化用于处理国际化. 本地化策略
  3. initThemeResolver(context); 用于定义主题
  4. initHandlerMappings(context);初始化HandlerMapping
  5. initHandlerAdapters(context); 初始化HandlerAdapters
  6. initHandlerExceptionResolvers(context); 当handler出错时. 会将错误记录在log文件上
  7. initRequestToViewNameTranslator(context); 将指定的ViewName按照Translator替换成想要的格式
  8. initViewResolvers(context); 初始化视图解析器
  9. initFlashMapManager(context);用于生成flashMap管理器

springmvc用到的注解. 作用是什么. 原理

1.@Controller 负责处理DispatcherServlet分发的请求

2.@RequestMapping 处理请求地址映射. 作用于类和方法上

3.@Autowired 根据类型注入

4.@Qualifier 当一个接口存在多个实现类时. 可以根据名称注入

5.@ResponseBody 用于异步请求返沪json数据

6.@PathVariable 在使用Resultful风格开发时. 可使用该注解配上对应url中参数的名称来获取参数的值

7.@RequestParam 两个属性value、required. value用来指定参数名称. required用来确定参数是否必须传入。

8.@RequestHeader 可以把request请求header部分的值绑定到参数上

9.@CookieValue 把request请求header中的cookie绑定到参数上

10.@RequestBody 可指定请求数据格式application/json, application/xml

11.@ModelAttribute 为请求绑定需要从后台获取的值

spring的controller是单例还是多例. 怎么保证并发的安全

Java里有个API叫做ThreadLocal. spring单例模式下用它来切换不同线程之间的参数。用ThreadLocal是为了保证线程安全. 实际上ThreadLoacal的key就是当前线程的Thread实例。单例模式下. spring把每个线程可能存在线程安全问题的参数值放进了ThreadLocal。这样虽然是一个实例在操作. 但是不同线程下的数据互相之间都是隔离的. 因为运行时创建和销毁的bean大大减少了. 所以大多数场景下这种方式对内存资源的消耗较少. 而且并发越高优势越明显。

SpirngMVC的生命周期 和 SpringBean的生命周期

1、SpirngMVC的生命周期 :

A. DispatcherSerlvet(前端控制器)

B. -》 HandlerMapping(处理器映射器). 根据xml注解查找对应的Hander -》 返回Handler

C. -》处理器适配器去执行Handler

D. -》Handler执行完成后给处理器适配器返回ModelAndView

E. -》前端控制器请求视图解析器去执行视图解析. 根据逻辑视图名解析成真正的视图JSP. 向前端控制器返回view

F. -》前端控制器进行视图渲染. 将模型数据放到request-》返回给用户

2、SpringBean的生命周期:

Instance实例化-》设置属性值-》调用BeanNameAware的setBeanName方法-》调用BeanPostProsessor的预初始化方法-》调用InitializationBean的afterPropertiesSet()的方法-》调用定制的初始化方法callCustom的init-method-》调用BeanPostProsessor的后初始化方法-》Bean可以使用了 -》 容器关闭-》 调用DisposableBean的destroy方法-》调用定制的销毁方法CallCustom的destroy-method。

编程题

你可能感兴趣的:(Java体系,java,面试,jvm)