关于java:我想进大厂之Spring夺命连环10问

41次阅读

共计 3049 个字符,预计需要花费 8 分钟才能阅读完成。

1. 说说 Spring 里用到了哪些设计模式?

单例模式:Spring 中的 Bean 默认状况下都是单例的。无需多说。

工厂模式:工厂模式次要是通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象。

代理模式:最常见的 AOP 的实现形式就是通过代理来实现,Spring 次要是应用 JDK 动静代理和 CGLIB 代理。

模板办法模式:次要是一些对数据库操作的类用到,比方 JdbcTemplate、JpaTemplate,因为查询数据库的建设连贯、执行查问、敞开连贯几个过程,十分实用于模板办法。

2. 谈谈你对 IOC 和 AOP 的了解?他们的实现原理是什么?

IOC 叫做管制反转,指的是通过 Spring 来治理对象的创立、配置和生命周期,这样相当于把控制权交给了 Spring,不须要人工来治理对象之间简单的依赖关系,这样做的益处就是解耦。在 Spring 外面,次要提供了 BeanFactory 和 ApplicationContext 两种 IOC 容器,通过他们来实现对 Bean 的治理。

AOP 叫做面向切面编程,他是一个编程范式,目标就是进步代码的模块性。Srping AOP 基于动静代理的形式实现,如果是实现了接口的话就会应用 JDK 动静代理,反之则应用 CGLIB 代理,Spring 中 AOP 的利用次要体现在 事务、日志、异样解决等方面,通过在代码的前后做一些加强解决,能够实现对业务逻辑的隔离,进步代码的模块化能力,同时也是解耦。Spring 次要提供了 Aspect 切面、JoinPoint 连接点、PointCut 切入点、Advice 加强等实现形式。

3. JDK 动静代理和 CGLIB 代理有什么区别?

JDK 动静代理次要是针对类实现了某个接口,AOP 则会应用 JDK 动静代理。他基于反射的机制实现,生成一个实现同样接口的一个代理类,而后通过重写办法的形式,实现对代码的加强。

而如果某个类没有实现接口,AOP 则会应用 CGLIB 代理。他的底层原理是基于 asm 第三方框架,通过批改字节码生成成成一个子类,而后重写父类的办法,实现对代码的加强。

4. Spring AOP 和 AspectJ AOP 有什么区别?

Spring AOP 基于动静代理实现,属于运行时加强。

AspectJ 则属于编译时加强,次要有 3 种形式:

  1. 编译时织入:指的是加强的代码和源代码咱们都有,间接应用 AspectJ 编译器编译就行了,编译之后生成一个新的类,他也会作为一个失常的 Java 类装载到 JVM。
  2. 编译后织入:指的是代码曾经被编译成 class 文件或者曾经打成 jar 包,这时候要加强的话,就是编译后织入,比方你依赖了第三方的类库,又想对他加强的话,就能够通过这种形式。

  1. 加载时织入:指的是在 JVM 加载类的时候进行织入。

总结下来的话,就是 Spring AOP 只能在运行时织入,不须要独自编译,性能相比 AspectJ 编译织入的形式慢,而 AspectJ 只反对编译前后和类加载时织入,性能更好,性能更加弱小。

5. FactoryBean 和 BeanFactory 有什么区别?

BeanFactory 是 Bean 的工厂,ApplicationContext 的父类,IOC 容器的外围,负责生产和治理 Bean 对象。

FactoryBean 是 Bean,能够通过实现 FactoryBean 接口定制实例化 Bean 的逻辑,通过代理一个 Bean 对象,对办法前后做一些操作。

6.SpringBean 的生命周期说说?

SpringBean 生命周期简略概括为 4 个阶段:

  1. 实例化,创立一个 Bean 对象
  2. 填充属性,为属性赋值
  3. 初始化

    • 如果实现了 xxxAware 接口,通过不同类型的 Aware 接口拿到 Spring 容器的资源
    • 如果实现了 BeanPostProcessor 接口,则会回调该接口的 postProcessBeforeInitialzationpostProcessAfterInitialization办法
    • 如果配置了 init-method 办法,则会执行 init-method 配置的办法
  4. 销毁

    • 容器敞开后,如果 Bean 实现了 DisposableBean 接口,则会回调该接口的 destroy 办法
    • 如果配置了 destroy-method 办法,则会执行 destroy-method 配置的办法

7.Spring 是怎么解决循环依赖的?

首先,Spring 解决循环依赖有两个前提条件:

  1. 不全是结构器形式的循环依赖
  2. 必须是单例

基于下面的问题,咱们晓得 Bean 的生命周期,实质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化的对象。

第一级缓存:用来保留实例化、初始化都实现的对象

第二级缓存:用来保留实例化实现,然而未初始化实现的对象

第三级缓存:用来保留一个对象工厂,提供一个匿名外部类,用于创立二级缓存中的对象

假如一个简略的循环依赖场景,A、B 相互依赖。

A 对象的创立过程:

  1. 创建对象 A,实例化的时候把 A 对象工厂放入三级缓存

  1. A 注入属性时,发现依赖 B,转而去实例化 B
  2. 同样创建对象 B,注入属性时发现依赖 A,一次从一级到三级缓存查问 A,从三级缓存通过对象工厂拿到 A,把 A 放入二级缓存,同时删除三级缓存中的 A,此时,B 曾经实例化并且初始化实现,把 B 放入一级缓存。

  1. 接着持续创立 A,顺利从一级缓存拿到实例化且初始化实现的 B 对象,A 对象创立也实现,删除二级缓存中的 A,同时把 A 放入一级缓存
  2. 最初,一级缓存中保留着实例化、初始化都实现的 A、B 对象

因而,因为把实例化和初始化的流程离开了,所以如果都是用结构器的话,就没法拆散这个操作,所以都是结构器的话就无奈解决循环依赖的问题了。

8. 为什么要三级缓存?二级不行吗?

不能够,次要是为了生成代理对象。

因为三级缓存中放的是生成具体对象的匿名外部类,他能够生成代理对象,也能够是一般的实例对象。

应用三级缓存次要是为了保障不论什么时候应用的都是一个对象。

假如只有二级缓存的状况,往二级缓存中放的显示一个一般的 Bean 对象,BeanPostProcessor去生成代理对象之后,笼罩掉二级缓存中的一般 Bean 对象,那么多线程环境下可能取到的对象就不统一了。

9.Spring 事务流传机制有哪些?

  1. PROPAGATION_REQUIRED:如果以后没有事务,就创立一个新事务,如果以后存在事务,就退出该事务,这也是通常咱们的默认抉择。
  2. PROPAGATION_REQUIRES_NEW:创立新事务,无论以后存不存在事务,都创立新事务。
  3. PROPAGATION_NESTED:如果以后存在事务,则在嵌套事务内执行。如果以后没有事务,则按 REQUIRED 属性执行。
  4. PROPAGATION_NOT_SUPPORTED:以非事务形式执行操作,如果以后存在事务,就把以后事务挂起。
  5. PROPAGATION_NEVER:以非事务形式执行,如果以后存在事务,则抛出异样。
  6. PROPAGATION_MANDATORY:反对以后事务,如果以后存在事务,就退出该事务,如果以后不存在事务,就抛出异样。
  7. PROPAGATION_SUPPORTS:反对以后事务,如果以后存在事务,就退出该事务,如果以后不存在事务,就以非事务执行。‘

10. 最初,说说 Spring Boot 启动流程吧?

这个流程,网上一搜根本都是这张图了,我也不想再画一遍了。那其实次要的流程就几个步骤:

  1. 筹备环境,依据不同的环境创立不同的 Environment
  2. 筹备、加载上下文,为不同的环境抉择不同的 Spring Context,而后加载资源,配置 Bean
  3. 初始化,这个阶段刷新 Spring Context,启动利用
  4. 最初完结流程

正文完
 0