面试:Spring全家桶

本文深入探讨了Spring框架的核心组件,包括Bean的生命周期、作用域、单例bean的线程安全性,以及IoC和DI的概念。此外,详细阐述了AOP的实现方式、通知类型及其在Spring AOP中的应用,还有事务管理的实现原理、传播行为和隔离级别。文章还讨论了Spring如何解决循环依赖问题,解释了Spring MVC的工作流程,Spring Boot的自动装配原理,@Autowired和@Resource的区别,以及BeanFactory与ApplicationContext的差异。最后,文章提到了Spring中运用的设计模式,如工厂模式、代理模式、单例模式等。
摘要由CSDN通过智能技术生成

主要内容出自:Java知识体系最强总结(2020版)

一、Spring Beans

1、容器中bean的生命周期

在这里插入图片描述

2、bean的作用域

Spring框架支持以下五种bean的作用域:

  • singleton : bean在每个Spring ioc 容器中只有一个实例。
  • prototype:一个bean的定义可以有多个实例。
  • request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
  • session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
  • global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。

注意: 缺省的Spring bean 的作用域是Singleton。使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。

3、Spring框架中的单例bean是线程安全的吗?

不是

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

二、IOC与DI

IOC 控制反转

“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器

IOC作用:

  • 由容器管理对象的创建和整个生命周期,并进行依赖关系的维护。对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系需要程序猿来维护的话,那是相当头疼的
  • 解耦,由容器去维护具体的对象

IOC的实现方式:依赖注入(DI)和依赖查找

依赖注入(DI)

让容器全权负责依赖查询,受管组件只需要暴露JavaBean的setter方法或者带参数的构造器或者接口,使容器可以在初始化时组装对象的依赖关系。

依赖注入与依赖查找方式相比,主要优势为:

  • 查找定位操作与应用代码完全无关。
  • 不依赖于容器的API,可以很容易地在任何容器以外使用应用对象。
  • 不需要特殊的接口,绝大多数对象可以做到完全不必依赖容器。

IOC实现原理:

  1. 加载配置文件,解析成 BeanDefinition 放在 Map 里。
  2. 调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法 —— 完成依赖注入。

三、AOP

用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。
在这里插入图片描述

1、AOP 有哪些实现方式?Spring AOP 和 AspectJ AOP 有什么区别?

AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

  1. AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

  2. Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

2、JDK动态代理和CGLIB动态代理的区别

Spring AOP中的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理

  • JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。

  • 如果代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

  • 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。

3、AOP中特定名词

  • 切面(Aspect):切面是通知和切点的结合。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。

  • 连接点(Join point):指方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。

  • 通知(Advice):在AOP术语中,切面的工作被称为通知。

  • 切点(Pointcut):切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。

  • 引入(Introduction):引入允许我们向现有类添加新方法或属性。

  • 目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。它通常是一个代理对象。

  • 织入(Weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。

编译期:切面在目标类编译时被织入。AspectJ的织入编译器是以这种方式织入切面的。

类加载期:切面在目标类加载到JVM时被织入。需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入就支持以这种方式织入切面。

运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面。

4、Spring AOP的通知类型

  • 前置通知(Before):在目标方法被调用之前调用通知功能;
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
  • 返回通知(After-returning ):在目标方法成功执行之后调用通知;
  • 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  • 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。

注意:环绕通知,最后不要忘了把结果return出去

同一个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: 

5、Spring AOP内部调用失效问题

一个需要进行AOP增强的类,外部调用methodA()且该方法中调用methodB(),调用methodB()不会执行AOP的增强逻辑。

原因:真正执行methodA()的是目标对象,那么methodA()中调用的methodB()是目标对象的方法,而不是代理对象的。也就自然不会执行AOP的增强逻辑

/**
 * 目标对象类
 */
@Service
public class TestAopService {
   

    public void methodA() {
   
        System.out.println("method A run"
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值