0
点赞
收藏
分享

微信扫一扫

面试部分难点梳理 - Spring+SpringBoot自动装配

梦幻之云 2022-04-01 阅读 97
spring

SpringIOC
Spring事务
SpringMVC
感觉MVC随便看看就行,最主要的还是那张大图要记住。

随看随记

ApplicationContext和BeanFactory的区别

  • BeanFactory是访问spring容器的根接口,里面只是提供了某些基本方法的约束和规范,为了满足更多的需求,ApplicationContext实现了此接口,并在此接口的基础之上做了某些打展功能,提供了更加丰富的api调用。一般我们在使用的时候用applicationContext更多

BeanFactory 和 FactoryBean

  • BeanFactory是个bean 工厂,是一个工厂类(接口), 它负责生产和管理bean的一个工厂,是ioc 容器最底层的接口,是个ioc容器,是spring用来管理和装配普通bean的ioc容器(这些bean成为普通bean)。
  • FactoryBean是个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理后,生产的对象是由getObject()方法决定的。

各种注解之间的区别

@Configuration
public class AppConfig {    
	@Bean
	public TransferService transferService() {
		return new TransferServiceImpl();    
	}
}

@Component
public class ServiceImpl implements AService {   
	....
}

@Bean
public OneService getService(status) {
	case (status)  {
		when 1:return new serviceImpl1();
		when 2:return new serviceImpl2();
		when 3:return new serviceImpl3();    
	}
}

@Configuration
public class AppConfig {
    @Beanpublic MyBean myBean() {
    // instantiate, configure and return bean ...    
    }
}
  • 在这里插入图片描述

SpringIOC

Spring程序是如何启动的

  • 整体流程(除去各种PostProcessor的细节) :

    1. 获取从外部文件或注解中得到的信息,并封装到BeanDefinition中。其中存有bean的定义信息。
    2. 根据BeanDefinition,创建beanFactory工厂。
    3. 得到bean的对象(全是空),将这个初始化对象进行初始化。
    4. 得到完整的可用对象,并使用。
  • 能够进行AOP切片的位置

    1. 从BeanDefinition到BeanFactory。
    2. 从实例化对象到初始化对象。
    3. 初始化对象到得到完整的可用对象。
  • 在这里插入图片描述

  • 在这里插入图片描述

  • 在上述的图中,从BeanDefinitionReader得到的BeanDefinition还是会有占位符,不会替换。在invokeBeanFactoryPostProcessor中会将占位符,替换成我们配置信息。

  • 在这里插入图片描述

  • 在实例化对象前(3.5步骤),会准备beanPostProcesspr,准备监听器,事件和广播器。(观察者模式)

aware接口的作用

  • aware的目的是得到SpringIOC容器创建好的对象的相应属性

如何加载配置文件到应用程序

  • 文档
  • 大概的流程:
    1. 通过I/O流得到xml的内容到内存;
    2. 将内存中流转化成document(sax解析器);
    3. 根据不同的命名空间,找到对应的Handler;
    4. 遍历每一个子元素;
    5. 对不同的元素进行解析;
    6. 得到BeanDefinition。
  • 在这里插入图片描述

循环依赖

  • A对象的属性有B,B对象的属性有A,由于Spring创建对象默认是单例模式,因此,对导致A和B之间会循环引用,无休无止。
  • 对于构造器注入的方式是无法打破循环依赖的,只有通过set注入的方式才可以打破循环依赖。
  • 创建Bean的函数调用链:
  • getBean -> doGetBean ->createBean -> doCreateBean ->createBeanInstance ->populateBean
  • 循环依赖图示:
    1. 创造A对象
    2. 实例化A对象
    3. set()填充A对象,如果有A对象则直接填充,如果没有则创建B对象。
    4. 实例化B对象
    5. set()填充B对象,如果有B对象则直接填充,如果没有则创建A对象。
  • 这样反复调用创建A和B对象,导致产生循环,出现问题。
  • 在这里插入图片描述
  • 因此三级缓存的作用就在于,将实例化但未完成初始化的对象进行临时储存。从而在B找不到A对象处进行处理,返回未完成创建的A对象。
  • 在这里插入图片描述

三级缓存

  • 如果要自己debug,从preInstantiateSingletons()方法开始debug。

  • Bean对象成为成品的流程是:

    1. 未经过Aop增强的半成品(三级缓存),存储的是lambda表达式而不是对象。
    2. 经过Aop增强的半成品(二级缓存)
    3. 完全实例化和初始化的成品(一级缓存)
  • 在这里插入图片描述

  • 一级缓存是singletonObjects,用于存放完成实例化和初始化的bean对象。(成品)

  • 二级缓存是earlySingletonObjects,用于存放完成实例化但未完成初始化的bean对象。(经过AOP增强过半成品)

  • 三级缓存是singletonFactories,用于存放需要进行AOP增强,但还未进行增强的半成品。(未经过AOP增强的半成品)

  • 三级缓存的流程:

    1. A实例化对象。
    2. 将A存入三级缓存中
    3. 注入A的属性,尝试获取B对象
    4. B对象为空,同时一级缓存和二级中也没有,创建B对象
    5. B实例化对象
    6. 将B存入三级缓存中
    7. 注入B的属性,尝试获取A对象
    8. 没有A对象,但是发现A对象处于正在创建的状态
    9. 从三级缓存中拿出A对象,经过AOP增强后,放到A的二级缓存中,同时删除A的三级缓存。并返回。
    10. 将A对象填充给B对象,同时删除A的二级缓存中和B的三级缓存,经过AOP增强后,将B对象(成品)放到一级缓存中。
    11. 一直返回到,填充A对象的B属性,发现B对象在一级缓存中,使用一级缓存的B对象填充给A。
    12. 删除B三级对象和A的二级对象。
  • 在这里插入图片描述

  • 如果没有循环依赖的话,直接在将属性填充以后,直接调用三级缓存,进行AOP增强,放到一级缓存,不会使用二级缓存。

三级缓存面试问题

  • 仅仅使用一级缓存行不行?
  • 仅仅使用二级缓存行不行?
  • 三级缓存做了什么事情?

谈谈Spring IOC的理解,原理与实现?

  • 总:
  • 分:
  • 结:

谈一下springIOC的底层实现

  1. 首先通过createBean()方法创建一个bean工厂(defaultListableBeanFactory)
  2. 然后循环创建bean对象,因为Spring创建Bean默认是单例的,因此通过调用getBean方法和doGetBean方法
  3. 如果没有get到就创建对象,调用createBean()和doCreateBean()方法,通过反射的方式得到对象的构造器,然后通过反射的getInstance方法得到实例化的bean对象。
  4. 调用populationBean()方法对这个bean进行填充属性
  5. 进行其他初始化操作。
  • 在这里插入图片描述

描述一下bean的生命周期?

  • 在这里插入图片描述
  1. 首先BeanFactory会通过反射的方法实例化bean对象。
  2. 然后调用populateBean()方法,填充bean的属性。
  3. 如果实现了Aware接口相关的方法,调用Aware接口的相关方法,依次完成对BeanName,BeanFactory和BeanClassLoader,ApplicationContext对象的属性设置。
  4. 如果实现了BeanPostProcessor,就调用BeanPostProcessor的前置增强方法。
  5. 调用Initmethod()方法,如果实现了==initializingBean()==方法或init_method属性中声明了初始化方法,则调用该方法afterPropertiesSet()。
  6. BeanPostProcessor的后置增强方法。
  7. 获得完整的Bean对象,可以通过getBean方式获得该对象。
  8. 最后销毁,如果该对象实现==DisposableBean()==方法,先调用这个方法,然后调用destory()方法。

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

  • 三级缓存,提前暴露对象,aop
  • 什么是循环依赖:
  • 总:
  • 分:

缓存放置时间和删除时间

三级缓存: createBeanInstance之后: addSingletonFactory
二级缓存:第一次从三级缓存确定对象是代理对象还是普通对象的时候,同时删除三级缓存getSingleton
-级缓存:生成完整对象之后放到一级缓存,删除二三级缓存:addSingletonFactory

  • 在这里插入图片描述

BeanFactory与FactoryBean有什么区别

  • 在这里插入图片描述
  • 这两个都是用来创建对象的。
  • BeanFactory是整个SpringIOC的管理者,所有IOC中管理的bean都继承自BeanFactory。如果继承了BeanFactory就需要按照Spring要求的生命周期进行实现,
  • FactoryBean是一个bean,被BeanFactory管理。是一个实现了工厂模式的bean,我们可以通过FactoryBean创建自己需要的bean,同时被SpringIOC管理。FactoryBean方法可以让我们获得我们需要的对象等。

SpringAOP

  • SpringAOP的功能有哪些:事务,权限验证,异常处理,log记录

  • Aspect:切面 = join point + pointcut + advice;

  • joinpoint:连接点,需要被增强的每一个方法

  • pointcut:切点,一堆连接点的集合,指出需要被增强的范围。

  • advice:通知,包括增强逻辑和增强位置(Before,AfterReturning ,AfterThrowing,Around)。

  • weaving:织入,实现增强的过程(静态增强,动态增强)

  • TargetObject:需要被代理的对象

  • proxy:代理以后生成的代理对象

  • 下图所示

  • @Aspect 表示这是一个切面,切面也是一个bean,因此用@component装填到IOC容器中。

  • @advice表示的方法内部表示的是增强逻辑,@before和@After表示的是增强时机。

  • @pointcut表示要增强的范围,execution(~)的内容

  • 在(~)中的每一个方法就是joincut。
    在这里插入图片描述在这里插入图片描述

  • 在这里插入图片描述

  • 在这里插入图片描述

  • 代码可以插入的位置,(advice能够插入的位置):

    1. before:前面
    2. after:后面
    3. around:环绕 = before + after
    4. afterReturning:当切入的方法成功返回时
    5. afterThrowing:当切入的方法抛出异常时
  • 在这里插入图片描述

  • 在这里插入图片描述

  • 当有多个通知时,需要有一套责任链来排序advice执行的顺序。
    在这里插入图片描述

  • Spring中每一个advice都要实现MethodInterceptor接口,CGLIB动态代理中CallBack()接口需要传入的内容。

SpringAop的执行过程

  • SpringAop的执行链:有点难理解自己看视频吧
    在这里插入图片描述
    在这里插入图片描述
    为什么每次都回到链上,可以让我们可以在当前的链结构中拿到最新的排好序的下一个结构的数据
  • 在这里插入图片描述

Spring中用到的设计模式?

  • 单例模式(节省内存):在IOC容器中生成的bean默认都是单例模式的。
  • 抽象工厂、简单工厂(实现创建对象和使用对象相分离):BeanFactory是抽象工厂,Spring中所有的Bean都实现了BeanFactory。简单工厂主要是FactoryBean,这也是一个具有工厂模式的Bean,也是实现了BeaFactory,其可以通过这个方法来制造我们相想要的bean。
  • 模板方法(模板方法可以):Spring中的 jdbcTemplate中就是使用了模板方法
  • 动态代理:SpringAOP大量使用了动态代理,来对切点,切面,连接点进行通知操作。通过JDK动态代理和CGLIB两种方式实行了动态代理
  • 回调模式:在CGLIB中Enchancer.create()中就需要传递CallBack方法,在AOP中一般是通过继承了MethodeInterceptor,来实现回调。
  • 适配器模式:在SpringMVC中用的很多,通过在DispatchServlet得到Handler调用链以后,会调用HandlerAdaptor,进行适配操作,再调用相关的controller,来获取modelAndView。

在这里插入图片描述

Spring的AOP的底层实现原理?

  • AOP是面向切面编程,它主要使用在增加打印日志,进行进行事务处理等功能。是通过动态地理的方式实现的。
  • 在IOC容器中,当bean被实例化和初始化之后,会询问是否实现了BeanPostProcessor,如果实现了,就会调用其后置增强方法,Spring就是在这个方法中实现了AOP。
    1. 当Bean对象创建过程中会获取bean相关的,切面,切点,连接点,通知的时间和通知的内容,并将这个对象作为目标对象。
    2. 然后会通过JDK或者CGLIB的方式进行动态代理,生成代理类。
    3. 在执行到方法调用时,因为动态代理本身就是直接操作字节码文件的,会从字节码文件中找到DynamicAdvisoredInterceptor类中的Intercept()方法,从这个方法开始执行通知内容。
    4. 如果有多个通知的话,还会根据定义好的通知生成拦截器链,按照拓扑排序的顺序进行方法增强。
  • 在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Spring事务

在这里插入图片描述
在这里插入图片描述

Spring事务的三大基础

  • PlatformTransctionManager:(由持久层框架帮我们实现),声明式事务还是编程式事务都是这个起了作用。
  • TransctionDefinition:定义了事务的5种状态.
  • TransctionStatus:

PlatformTransctionManager

  • 定义了基本的事务处理的方法,包括获取事务的TransctionStatus
  • 事务的提交 和 回滚。
public interface PlatformTransactionManager {
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition);
	void commit(TransactionStatus status) throws TransactionException;
	void rollback(TransactionStatus status) throws TransactionException;
}

TransactionDefinition

  1. 传播性
  2. 隔离性
  3. 超时时间
  4. 是否只读
  5. 回滚规则

在这里插入图片描述

编程式事务

  • 在这里插入图片描述

声明式事务

  • 在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

事务的传播性

  • 除了第一个以外 别的都是看内事务失败会不会影响到外事务,或者说外事务是否对内事务的失败进行了处理
    在这里插入图片描述

Required(最多只有一个事务)

  • 默认是Requred
  • 内事务方法默认是一定在事务中执行
  • 如果两个都是Requred 两个会并入一个事务中执行,会导致整体回滚或提交。
  • 就算是在外事务中出现了bug,内事务依旧会回滚

Requires_New(多个事务并行)

  • Required(外) + Requires_New(内)
  • 可能会同时存在多个事务
  • 外bug 外回滚 内有独立事务 内不回滚
  • 内bug看情况 内bug无法处理 抛异常给外 则外回滚 如果内异常处理好了 则外不回滚

Nested(事务嵌套)

  • 相当于外部事务的子事务,外部事务回滚内是要回滚的,Requires_New不同的是Requires_New是独立的事务,外回滚 内是不需要回滚的
  • 内bug看情况 内bug无法处理 抛异常给外 则外回滚 如果内异常处理好了 则外不回滚

Supports(无所谓)

  • 外有事务加入事务 , 没事务就非事务

Not_Supports(非事务)

  • 外有事务 挂起事务 没事务就没事务

Mandatory(强制加入事务)

  • 外有事务加入事务 没有事务 抛出异常

Never(强制非事务)

  • 外有事务抛出异常 没事务就没事务

事务回滚规则

  • 默认是 运行时异常会回滚,检查型异常是不会回滚的
  • 运行时异常指的是1/0,检查型异常指的是IOException等以检查为主的异常。
  • 可以通过roolBackFor来扩大异常回滚的范围 或 notroolBackFor来缩小异常的回滚范围

只读事务(select)

  • 开启只读事务,多个Sql会合并到一个事务中,多个sql获取相同的结果

事务仅在public上生效

同类中无事务方法调用有事务方法会失效(AOP)

  • 仅仅会从外部动态代理生成的类中调用,自己内部是不会调用动态代理生成的对象的。
    在这里插入图片描述

Spring的事务是如何回滚的?

  • 总:

  • 分:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

谈一下spring事务传播?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Spring核心

在这里插入图片描述

Spring事务隔离级别

在这里插入图片描述

SpringMVC

  • 两种定义方式,一个是继承类加@bean,但是这种方法一个类仅能定义一个controller,在SpringMVC中,在mapHandler中存储的对象名。
  • 对于注解方法来说,一个controller可以直接定义在方法上,存储在HandlerMethod的是方法名。HandlerMethod
  • 两个Handler解析器,HandlerMapping : mapHandler 和 HandlerMethod。
  • 三个controller适配器,HandlerAdapter
  • HandlerMapping 返回的是一个执行链。

SpringMVC的执行流程

在这里插入图片描述

  • SpringMVC的执行核心是DispatchServlet前端控制器,通过HandlerMapping去查找Handler,HandlerAdaptor的适配和viewResolver的解析三大步骤。
  1. 用户发送前端请求到DispatchServlet;
  2. DispatchServlet收到请求后,发送请求到HandlerMapping处理器。
  3. HandlerMapping处理后会生成执行链,返回给DispatchServlet。
  4. DispatchServlet请求HandlerAdapter适配器。
  5. HandlerAdapter适配器寻找到合适的Controller,对请求进行处理。
  6. Controller会返回ModelAndView对象给HandlerAdapter
  7. HandlerAdapter将ModelAndView对象DispatchServlet
  8. DispatchServlet将得到的ModelAndView对象传给viewResolver,对ModelAndView进行解析。
  9. viewResolver返回View对象给DispatchServlet
  10. DispatchServlet处理View信息,并渲染视图。
  11. 传给前端展示,目前更多的是返回Json字符串给前端显示数据。
  • 在这里插入图片描述

SpringBoot自动装配

  • SpringBoot解决了开发者需要大量配置文件的问题,虽然在使用注解的形式在一定程度上缓解了配置地狱的情况,但是需要配置的内容依旧很多。Spring Boot 通过约定大于配置的思想,减少配置。
  1. 在主启动类中有@SpringBootApplication,这个注解表明了这个类是Spring Boot的启动类,其中的@EnableAutoConfigration是实现自动装配的核心注解,其中的使用@import引入了AutoConfigurationImportSelector类,这个类是Spring Boot实现自动装配核心。
  2. AutoConfigurationImportSelector中继承了selectImports()方法,这个方法用于获取所有符合条件的全限定类名,并加载到IOC容器中。
  3. 通过getAutoConfigurationEntry()方法,先把所有的META-INF/SpringFactories中以AutoConfigration为后缀的配置文件全部加载进来,然后根据@CondiOn注解来判断是否将该配置文件注入IOC容器中。
  4. 这样实现了SpringBoot自动装配
举报

相关推荐

0 条评论