您的位置:首页 > 编程语言 > Java开发

Spring面试题总结及答案

2020-01-13 10:09 162 查看

Spring
面试总结

Spring
是什么?

Spring
框架是一个
java
平台,提供全面基础设施支持开发
java
应用程序。

Spring
的主要模块有哪些?

  • Spring Code
    :基础模块,主要提供
    IOC
    DI
    功能。
  • Spring Aspects
    :该模块对与
    AspectJ
    集成提供支持。
  • Spring AOP
    :提供面向切面编程的实现。
  • Spring JDBC
    :提供
    java
    数据库连接。
  • Spring JMS
    java
    消息服务。【与远程调用机制以及REST接口类似】
  • Spring ORM
    :用于支持
    Hibernate
    ORM
    工具。
  • Spring Web
    :为创建
    Web
    应用程序提供支持。
  • Spring Test
    :提供了对
    JUnit
    TestNG
    测试支持。

Spring
的优点

低侵入式设计,代码污染低,低耦合,复用性高,对主流框架的集成支持

aop
的理解

aop
是面向切面编程,是面向对象的一种补充,用于将那些与业务无关,却对多个对象有影响的公共行为和逻辑,抽取并封装为一个可重用的公共模块,减少重复代码降低模块间的耦合度,提高系统的可维护性

代理模式

静态代理和动态代理

  • 静态代理

    AspectJ

    也称编译时增强,静态代理就是编译阶段生成代理类,将切面织入

    java
    字节码中,运行后就是增强之后的
    aop
    对象

  • 动态代理

    Spring Aop

    动态代理就是不去修改字节码,而是每次运行时在内存中为方法生成一个

    aop
    对象,这个对象包含了目标对象的全部方法,在特定的切点做了增强处理,并回调原对象的方法

    动态代理基于

    JDK
    动态代理和
    CJLIB
    动态代理

    JDK
    动态代理

    JDK
    动态代理只提供接口的代理,不支持类的代理

  • CJLIB
    动态代理

    CJLB
    时通过继承的方式做的动态代理,如果某个类被标记为
    final
    ,是无法使用
    CJLIB
    做动态代理

Spring AOP
默认是
JDK
动态代理。

  • 静态代理和动态代理的区别

    区别在于生成

    aop
    代理的时机不同,相对来说
    AspectJ
    的静态代理有更好的性能,但是
    AspectJ
    需要特定的编译器处理,而
    Spring Aop
    不需要特定的编译器处理

  • IOC
    的理解

    IOC
    控制反转,不是一种技术,而是一种设计思想。是创建对象的控制权和转移,以前创建对象的时机和主动权是由自己把控的,而现在是把这种权力转移到spring容器中,由容器根据配置文件去创建实例和管理各个实例间的依赖关系,对象与对象的松散耦合,也就是
    IOC
    让对象的创建不用去
    new
    了,由
    spring
    自动生产,利用
    java
    的反射机制,根据配置文件运行时动态的去创建对象和管理,并调用对象的方法

    • 使用
      java
      反射机制的几种方法 通过全限定类名
    • 获取构造器对象,通过构造器
      new
      出来
    • 通过
      class
      对象创建一个实例对象
    • 通过
      class
      对象获得一个属性对象
    • 通过
      class
      对象获得一个方法对象

    ioc
    控制反转理解:

    • 谁控制了谁,控制了什么:

      ioc
      控制了对象,控制了外部资源的获取
  • 什么是反转?

      传统的程序直接获取依赖对象,也就是正转。
    • 而反转就是
      ioc
      容器帮我们创建对象及注入依赖

    为何是反转?

    • 是因为容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象。

    DI
    依赖注入理解:

    形象的说,由容器动态的将某个依赖关系注入到组件中。

    • 谁依赖了谁: 应用程序依赖了
      ioc
      容器
  • 为什么要依赖:
      因为需要
      ioc
      容器来提供对象需要的外部资源
  • 谁注入了谁:
      ioc
      容器注入了应用程序某个对象,应用程序依赖的对象
  • 注入了什么:
      就是注入了某个对象所需要的外部资源(包括对象,资源,常量数据等)

    ioc
    为什么要和
    DI
    同时出现

    • 因为他们是同一概念不同角度的描述

    IOC
    的注入

    • 构造器注入
    • setter
      方法注入
    • 注解注入

    【构造器参数实现强制依赖】

    【setter方法实现可选依赖】

    Spring
    bean
    的作用域

    • singleton:
      唯一bean实例,Spring中的bean默认都是单例。
  • prototype
      每次请求都会创建一个新的
      bean
      实例。(多例)
  • request
      每次
      HTTP
      请求都会产生一个新的
      bean
      ,该
      bean
      仅在
      HTTP Request
      内有效。
  • session
      每次
      HTTP
      都会产生一个新的
      bean
      ,该
      bean
      仅在
      HTTP Session
      内有效。
  • global-session
      全局session作用域,仅仅在基于
      Portlet
      Web
      应用中才有意义,
      Spring5
      中已经没有了。

    BeanFactory
    AppplicationContext
    的区别?

    1. BeanFactory
      spring
      最底层的接口,包含了各种
      bean
      的定义,管理
      bean
      的加载,实例化,控制
      bean
      的生命周期,维护
      bean
      之间的关系,而
      ApplicationContext
      接口是
      BeanFactory
      的派生,除了有
      BeanFactory
      所有的功能外,还有更加完整的框架功能:
        ApplicationContext
        继承了
        MessageSource
      • 统一的文件访问方式
      • 可以在监听器中注册
        bean
        的事件
      • 同时加载多个配置文件
      • 载入多个有继承关系的上下文,让每一个上下文都专注与一个特定的层次
    2. BeanFactory
      是延迟加载的方式来注入
      bean
      ,如果有异常,只有在使用
      bean
      的时候,才会抛出,不能及时发现存在spring配置的问题。而
      ApplicationContext
      是容器启动时一次性创建所有
      bean
      ,如果有问题,在启动时我们就可以发现了,有利于检查所有依赖属性是否注入(
      ApplicationContext
      启动后预载入所有的单实例
      bean
    3. BeanFactory
      通常是以编程的方式进行创建,而
      ApplicationContext
      可以以声明的方式进行创建(如:
      ContextLoader
    4. BeanFactory
      ApplictionContext
      都支持
      BeanPostProcessor
      BeanFactoryPostProcessor
      的使用,但
      BeanFactory
      是手动注册,而
      ApplicationContext
      是自动注册

    Spring Bean
    的生命周期

    1. Bean容器找到配置文件中Spring Bean的定义
    2. Bean容器利用Java Reflection API创建一个Bean的实例
    3. 如果涉及到属性值,利用set()方法设置一些属性值
    4. 如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean名字
    5. 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象实例
    6. 如果Bean实现BeanFactoryAware接口,调用setBeanClassFactory()方法,传入ClassLoader对象实例。(如果实现了其他Aware接口,就调用相应的方法)
    7. 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessorBeforeInitialization()方法
    8. 如果Bean实现了InitializingBean接口, 执行afeterPropertiesSet()方法
    9. 如果Bean在配置文件中定义了包含init-method属性,执行指定的方法
    10. 如果有何加载这个Bean的Spring容器相关的BeanPostProcess对象,执行postProcessAfterInitialization()方法
    11. 当要销毁Bean的时候,如果Bean实现了DisposableBena接口,执行destroy()方法
    12. 当要销毁Bean的时候,如果Bean在配置文件中的定义包含destory-method属性,执行指定方法

    怎么重载
    Bean
    生命周期重要的方法?

    • init-method
      destroy-method
      属性,可以用他们来定制初始化方法和注销方法
    • 相应的注解:
      @PostConstuct
    • @PreDestroy

    Spring
    框架中的单例
    Bean
    是否线程安全

    大部分时候我们的系统中并没有使用多线程,所以很少去关注这个问题,单例

    Bean
    是存在线程问题的,主要是因为当多个线程对这个对象的非静态成员变量进行写操作时会存在线程安全问题。

    有常用的俩种解决方案:

    • Bean
      对象中尽量避免定义可变的成员变量。(并不现实)
    • 在类中定义一个
      ThreadLoad
      成员变量,把需要可变的成员变量保存在
      ThreadLoad
      中。(推荐的一种方式)

    Spring
    事务的管理方式

    • 编程式事务:在代码中硬编码。(不推荐使用)
    • 声明式事务:在配置文件中配置。(推荐使用) 基于
      XML
      的声明式事务。
    • 基于注解的声明式事务。

    Spring
    事务中的隔离级别有哪几种?

    TransactionDefinition
    接口中定义了五个表示隔离级别的常量

    • ISOLATION_DEFAULT
      :使用后端数据库默认的隔离级别,
      MySQL
      默认采用
      REPEATABLE_READ
      隔离级别,
      Oracle
      默认采用的
      READ_COMMITTED
      隔离级别。
    • ISOLATION_READ_UNCOMMITTED
      :最低级隔离级别,允许读取尚未提交的数据变更,可能会导致脏读,幻读,不可重复读。
    • ISOLATION_READ_COMMITTED
      :允许读取并发事务已提交的数据,可以阻止脏读,但是幻读,不可重复读仍有可能发生。
    • ISOLATION_REPEATABLE_READ
      :对同一个字段多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但是幻读仍有可能发生。
    • ISOLATION_SERIALIZABLE
      :最高的隔离级别,完全服从ACID的隔离级别。所有事务依次逐个执行,这样事务之间就完全不可能产生干扰。可阻止脏读,不可重复读,幻读。但是会严重影响程序的性能通常情况不会用到该级别。

    Spring事务中的传播行为

    TransactionDefiniton
    接口中定义了八个表示事务传播行为的常量

    支持当前事务的情况:

    • PROPAGATION_REQUIRED
      :如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务。
    • PROPAGATION_SUPPORTS
      :如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务的方式继续运行。
    • PROPAGATION_MANDATORY
      :如果当前存在事务,则加入该事务,如果当前没有事务,则抛出异常。(mandatory:强制性)

    不支持当前事务的情况:

    • PROPAGATION_REQUIRES_NEW
      :创建一个新的事务,如果当前存在事务,则把事务挂起。
    • PROPAGATION_NOT_SUPPORTED
      :以非事务的方式运行,如果当前存在事务,则把事务挂起。
    • PROPAGATION_NEVER
      :以非事务的方式运行,如果当前存在事务,则抛出异常。

    其他情况:

    • PROPAGATION_NESTED
      :如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行,如果当前没有事务,则取值等价于PROPAGATION_REQUIRED。

    Spring中用到了那些设计模式?

    • 工厂设计模式:

      Spring
      使用工厂代理模式通过
      BeanFactory
      ApplicationContext
      创建对象。

    • 代理设计模式:

      Spring AOP
      功能实现。

    • 单例设计模式:

      Spring
      中的
      Bean
      ,默认都是单例的。

    • 模板方法模式:

      Spring
      中的
      jdbcTempalte
      等以
      Template
      结尾的对数据库操作的类,就使用到了模板模式。

    • 包装器设计模式:当我们的项目需要连接多个数据库的时候,而且不同的客户在每次访问中会去访问不同的数据库,这种模式可以根据客户的需求动态的切换不同的数据源。

    • 观察者模式:

      Spring
      事件驱动模型就是观察者模式很经典的一个应用。

      什么是事件驱动模型?

      是一种对象间一对多的关系,就像交通信号灯,信号灯是目标(也就是一的一方),行人是多方,行人需要注意观察信号灯的变化,当信号灯变为绿色的时候(也就是目标发送了改变),行人就知道这时候该过马路了(也就是订阅者可以接受到改变)。观察者怎么处理,目标不会干涉,这就松散的他们之间的耦合。就像绿灯的时候行人怎么走,是直着走还是弯着走,是走得快还是走的慢,目标都不会管。

  • 适配器模式:

    Spring AOP
    的增强通知使用到了适配器模式,
    Spring MVC
    也用到了适配模式来适配
    Controller

  • 等等…

  • @Component
    @Bean
    的区别是什么?

    • 作用对象不同
      @Component
      作用与类。
    • @Bean
      作用与方法上。
  • 可以用
    @Component
    注解扫描来自动侦测和自动装配到
    Spring
    容器中。
      可以使用
      @ComponentScan
      来定义要扫描的路径。
  • @Bean
    注解通常实在标有该注解的方法中产生这个
    Bean
    ,告诉
    Spring
    容器,当我需要他的时候在给我。
  • @Bean
    @Component
    的自定义性强,很多地方只能用
    @Bean
    来注册
    Bean
    。比如当我们需要使用第三方类库的类的时候,就只能通过
    @Bean
    来实现。
  • 将一类声明为
    Spring
    Bean
    的注解有哪些?

    一般我们用

    @Autowired
    注解去自动装配
    Bean
    ,而想要把一个类标识为可以使用
    @Autowired
    注解自动装配的
    Bean
    ,可以使用如下注解:

    • @Component
      注解:通用注解,可以标注任意类。
    • @Repository
      注解:对应持久层,也就是
      dao
      层,主要用于数据库的相关操作。
    • @Service
      注解:对应服务层,也就是
      service
      层,主要涉及一些复杂的逻辑,需要用到
      dao
      层(
      @Autowired
      注入)
    • @Controller
      注解:对应控制层,也就是
      Controller
      层,主要用于接受用户请求并调用
      service
      层的方法返回数据给前端页面。

    什么是装配?

    装配(

    Bean
    装配)就是在
    Spring
    容器中把
    Bean
    组装到一起,前提是容器要知道
    Bean
    的依赖关系,如何通过依赖注入把他们装配到一起。

    什么是自动装配?

    Spring
    容器能够自动装配相互合作的
    Bean
    ,容器不需要使用
    <constructor-arg>
    <property>
    配置,能通过
    Bean
    工厂自动处理
    Bean
    之间的协作。

    不同方式的自动装配

    有五种:

    • no
      :默认不自动装配,可以通过ref属性来进行装配。
    • byName
      :通过参数名自动装配。
    • byType
      :通过参数类型自动装配。
    • construtor
      :这个方式类似于
      byType
      ,是需要提供给构造器参数。
    • autodetect
      :首先尝试使用
      construtor
      来自动装配,如果无法工作,则使用
      byType
      方式。

    自动装配的局限性

    • 重写:需要使和配置定义依赖,总要重写自动装配。
    • 基本数据类型:不能自动装配简单的属性,如基本数据类型,String还有类。
    • 模糊特性:自动装配不如显示装配精确,建议使用显示装配。

    可以在Spring中注入一个null和一个空字符串吗?

    答:可以。

    yType`,是需要提供给构造器参数。

    • autodetect
      :首先尝试使用
      construtor
      来自动装配,如果无法工作,则使用
      byType
      方式。

    自动装配的局限性

    • 重写:需要使和配置定义依赖,总要重写自动装配。
    • 基本数据类型:不能自动装配简单的属性,如基本数据类型,String还有类。
    • 模糊特性:自动装配不如显示装配精确,建议使用显示装配。

    可以在Spring中注入一个null和一个空字符串吗?

    答:可以。

    • 点赞
    • 收藏
    • 分享
    • 文章举报
    San_Chi 发布了7 篇原创文章 · 获赞 7 · 访问量 2448 私信 关注
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: