必知必会系列-Spring技术原理

系列文章

引言

随着技术的不断演进,在不同时间阶段都会有不同的技术产物,那么如何快速的学习和掌握新的技术对于技术同学而言是非常重要的,如果我们能够带着问题去学习了解一门技术为什么存在,解决什么问题?如果不使用对我们的影响是什么?然后针对每一个技术最小化模型是什么,思考如果自己做会怎么做,可能会面临哪些问题,然后带着问题去学习每一门是如何解决的。下面是我在学习过程中涉及Spring的一些关键问题,大家可以尝试下解答下,下面有针对每一个提问有对应的解答提示。也欢迎沟通交流反馈你在学习过程中所遇到的问题。

  • 谈谈对Spring IOC和AOP的理解
  • Spring IOC容器具体是如何工作的呢?
  • Spring AOP核心原理是什么呢?
  • JDK和CGLIB动态代理区别?
  • 动态代理在什么情况下会不生效?
  • Spring AOP和AspectJ AOP有什么区别?
  • Spring是如何解决循环依赖问题?
  • 二级缓存能不能解决循环依赖问题?
  • Spring常用的设计模式及其应用场景?
  • FactoryBean和BeanFactory的区别是什么?

1. 谈谈对Spring IOC和AOP的理解

IOC(全称:Inversion of Control): 控制反转,意思就是将创建对象的控制权从自己硬编码new的一个对象反转到了Spring容器上,将对象的生命周期管理交由Spring来管理,由Spring完成对象创建、对象属性的填充、对象销毁,核心目的为了帮助我们解耦各种有复杂系统中有依赖关系的业务对象之间的绑定关系。

AOP(全称:Aspect Oriented Programming):面向切面编程,面向切面的程序设计,是一种程序设计思想,旨在将横切关注点与业务主体进行进一步分离,以提高程序代码的模块化程度。举个栗子:比如在访问数据对象之前都需要做一步预处理,即我们的关注点是预处理,而不需要在数据对象侧进行处理,降低数据数据对象的复杂度,我们只需要在访问数据对象的切面里面完成我们需要的统一业务逻辑处理即可。
在这里插入图片描述

2. Spring IOC容器具体是如何工作的呢?

Spring在初始化整体流程主要包含容器配置加载、Bean的实例化、Bean的依赖注入阶段,本文只就一些关键的流程讲述Spring容器初始化的流程,完整的逻辑细节处理较多本文不做赘述。

2.1 IOC容器配置加载

为什么IOC容器要加载配置呢? 并不是我们使用了Spring容器之后所有的Bean就自动实例化、自动依赖注入,我们仍然需要告诉Spring容器我们期望初始化哪些Bean,通过单例模式还是多例模式,哪些Bean的属性需要通过Spring完成自动注入。

可以通过哪些方式完成容器要初始化Bean的配置呢? 早些时候更多的是通过XML模式来配置Spring的Bean的定义,而当前阶段更多的是通过注解的形式来完成相关配置。无论配置信息在哪里,Spring容器在启动的过程中会去找到XML或是注解相关的配置,解析Bean的定义及其依赖关系的定义,然后转换为内存中的对象结构即BeanDefinition

2.2 Bean的实例化

根据容器的上一个步骤将开发者需要使用的对象的定义信息和依赖关系都通过BeanDefinition加载进来了,其次便是根据定义的信息完成相关对象的实例化工作,由于容器并强感知对象的类型,所以在这一步是通过反射来完成需要对象的创建的,创建完成的对象放在BeanFactory中。

2.3 Bean的属性填充

对象创建完成还没有完成,还需要按照依赖关系的注入。 需要进一步的查看Bean对象中是否有@Resource注解或是@Autowire注解,如果还有依赖其它的Bean还需要进行下一步的依赖注入,在没有特殊逻辑的情况下只需要通过BeanFactory中获取到相关的依赖的Bean,然后通过反射便可以填充到Bean对象中。

2.4 核心的接口、类和拓展点

  • Resource:用于解决IoC容器中的内容从哪里来的问题,也就是配置文件从哪里读取、配置文件如何读取的 问题
  • BeanDefinition:用于解决Bean的具体定义问题,包括Bean的名字是什么、它的类型是什么,它的属性赋 予了哪些值或者引用,也就是 如何在 IoC 容器中定义一个 Bean,使得 IoC 容器可以根据这个定义来生成实例 的问题。
  • BeanFactoy:用于解决IoC容器在已经获取Bean的定义的情况下,如何装配、获取Bean实例的问题。
  • ApplcationContext:对上述的内容进行了功能的封装,解决根据地址获取IoC容器并使用的问题。
  • BeanFactoryPostProcess:Spring提供的容器扩展机制,允许我们在bean实例化之前修改bean的定义信息即BeanDefinition的信息
  • BeanPostProcessor:也是Spring提供的容器扩展机制,不同于BeanFactoryPostProcessor的是,BeanPostProcessor在bean实例化后 修改bean或替换bean。BeanPostProcessor是后面实现AOP的关键。

3. Spring AOP核心原理是什么呢?

Spring AOP的实现原理核心基于动态代理来实现,通过代理的方式实现在执行具体业务逻辑前做一些前置处理或是在业务逻辑处理之后做一些逻辑处理。 你接触过哪些技术或组件使用了AOP来实现? Spring事务处理器、限流降级框架等等。 如何来实现动态代理? 可以通过JDK动态代理及其CGLIB来实现动态代理。

4. JDK和CGLIB动态代理区别?

  • JDK动态代理主要针对那些实现类是有接口的,Spring则会使用JDK的动态代理,通过继承同一个接口然后对目标类的功能进行增强
  • 而针对目标类没有实现某个接口的,Spring AOP则通过CGLIB来实现动态代理,通过修改字节码来对目标代理类进行功能的增强

5. 动态代理在什么情况下会不生效?

在同一个类自己调用自己的时候即this.method() 由于代理对象的创建是基于对象级别而不是方法级别,所以方法内部调用不经过代理对象,所以无法正常执行代理前后的方法即代理无法生效。

@Component
public class BeanA {

    public void a() {
        System.out.println("a method invoke!");
        // this调用不经过代理对象
        this.b();
    }
    
    public void b() {
        System.out.println("b method invoke!");
    }
}

那如何解决动态代理不生效的问题呢?在此先分享一种解法。

@Component
public class BeanA {

	@Autowired
    private BeanA self;  

    public void a() {
        System.out.println("a method invoke!");
        // 通过代理对象调用
        self.b();
    }
    
    public void b() {
        System.out.println("b method invoke!");
    }
}

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

Spring AOP是基于运行时增强,基于动态代理;而Aspect AOP是基于编译时增强,基于字节码操作。 AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对更加简单,如果切面比较少,两者性能差别不大。 但是当切面较多的话,最好选择AspectJ性能更好。

7. Spring是如何解决循环依赖问题?

Spring解决了循环依赖问题,核心原理通过提前曝光尚未初始化完成的Bean来完成存在循环依赖的Bean的初始化工作,在Spring内部通过三级缓存来解决循环依赖问题。 具体分析晚些画图补充。

8. 二级缓存能不能解决循环依赖问题?

  • 一级缓存:根据自己手写IOC容器的经历,如果仅仅是为了解决循环依赖无法初始化的问题,一级缓存便可以Bean初始化死循环进而栈溢出的问题,只需要将实例化的Bean且尚未完成的属性填充的Bean放入缓存便可以,但是只使用一级缓存面临一个问题是并发情况下,如果仅使用一级缓存会出现获取到不完成的Bean的调用。
  • 二级缓存:Spring通过引入二级缓存存储循环依赖过程中“尚未初始化完成Bean”,而一级缓存存储的为完全初始化完成的Bean,通过引入二级缓存避免了未初始化完成的Bean放入被正常的Bean使用。 同时通过双重检查锁的机制保障Spring容器的初始化死锁问题。 如果仅仅只是解决循环依赖,则二级缓存已经可以解决循环依赖的问题。
  • 三级缓存:什么情况下会使用到三级缓存呢? 主要原因为针对动态代理类的情况,正常情况下动态代理是在Bean实例化、初始化完成之后创建动态代理,但是针对循环依赖的Bean需要特殊处理提前进行动态代理创建,那么如何知道哪些Bean是循环依赖呢? 其实通过在二级缓存里面的Bean即为存在循环依赖的Bean。 那什么情况下会使用到三级缓存呢? 主要针对多重循环依赖的Bean,即A依赖B、B依赖C、C依赖A的情况,如果不引入三级缓存将会导致被多重依赖的Bean被重复创建动态代理类,通过三级缓存将已经创建了动态代理的Bean缓存起来,在多次创建Bean的代理类时提前检查代理类是否已经创建完成。

9. Spring常用的设计模式及其应用场景?

  • 工厂模式:BeanFactory。Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。
  • 单例模式:Spring容器中的Bean默认情况下一般都是单例Bean,即全局维护一个对象实例
  • 代理模式:Spring AOP底层实现原理即使用的是动态代理设计模式
  • 模板方法模式:Spring对JDBC的抽象,提供了JDBCTemplate的模板方法使得使用JDBC更加的方便简单

10. FactoryBean和BeanFactory的区别是什么?

  • BeanFactory是Bean的工厂接口,Spring IOC容器核心的接口定义,主要实现类为ApplicationContext,负责管理Bean的完整生命周期
  • FactoryBean也是接口,为IOC容器中Bean的创建提供了更加灵活的方式,通过代理真实的Bean对象,在对象创建前后进行一些自定义操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒲春伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值