美文网首页
面试官:讲一下spring的ioc和aop

面试官:讲一下spring的ioc和aop

作者: M_lear | 来源:发表于2022-02-19 09:38 被阅读0次

IOC

ioc:让spring帮我们

  1. 创建对象(工厂模式)
  2. 并管理对象之间的依赖关系。(DI:依赖注入)

ioc可以理解为实现了依赖注入的工厂模式。


任何交给spring管理的对象都可以叫spring bean。
而java bean则是符合一定规范的java类:

  1. 字段都是私有的。
  2. 为所有字段提供setter、getter方法。
  3. 提供一个无参构造函数。
  4. 可序列化。

POJO(普通java对象):PO(持久对象)、DTO、VO都是POJO

  1. 有一些私有属性以及对应的setter、getter
  2. 没有业务逻辑

循环依赖:
【原型bean不支持循环依赖】,会直接抛异常(BeanCurrentlyInCreationException )。如果不抛异常,会一直循环创建,直到stackoverflow或oom。

【单例bean基于构造器注入,也不支持循环依赖。】因为基于构造器注入,意味着当前实例还没创建出来,别人就要依赖。

只有,基于属性注入的单例bean,才支持循环依赖。
Spring使用三级缓存,通过提前暴露实例化中的bean来解决循环依赖问题。

过程如果忘记了,看这个图解:https://juejin.cn/post/6844904122160775176

A和B循环依赖:(getSingleton、doCreateBean、populateBean、addSingleton)

  1. 走A的get流程(三级缓存中都没get到)
    先实例化A,并把A的工厂添加到第三级缓存,填充A发现依赖B。

  2. 走B的get流程(三级缓存中都没get到)
    先实例化B,并把B的工厂添加到第三级缓存,填充B发现依赖A。

  3. 又走A的get流程
    这时候在第三级缓存get到了。从A的工厂获取A的实例,放到第二级缓存中,根据beanName删除三级缓存,并返回A的实例。

  4. 回到B的get流程,B拿到A的实例并完成创建,然后把自己放到第一级缓存中,根据beanName删除二三级缓存,并返回B的实例。

  5. 回到A的get流程,A拿到B的实例并完成创建,然后把自己放到第一级缓存中,根据beanName删除二三级缓存,并返回A的实例(这时候A已经完全创建好了)。


spring提供两种容器:

  1. BeanFactory
  2. ApplicationContext(不仅提供了BeanFactory的所有功能,还添加了对国际化、资源访问、事件传播等方面的支持。)

BeanFactory是一个Bean工厂,使用简单工厂模式,是Spring ioc容器顶级接口,可以理解为含有Bean集合的工厂类,作用是管理Bean,包括实例化、定位、配置对象及建立这些对象间的依赖。

BeanFactory实例化后并不会自动实例化Bean,只有当Bean被使用时才实例化与装配依赖关系,【属于延迟加载,适合多例模式。】

FactoryBean是一个工厂Bean,使用了工厂方法模式,作用是生产其他Bean实例,可以通过实现该接口,提供一个工厂方法来自定义实例化Bean的逻辑。FactoryBean接口由BeanFactory中配置的对象实现,这些对象本身就是用于创建对象的工厂,如果一个Bean实现了这个接口,那么它就是创建对象的工厂Bean,而不是Bean实例本身。

ApplicationConext是BeanFactory的子接口,扩展了BeanFactory的功能,提供了支持国际化的文本消息,统一的资源文件读取方式,事件传播以及应用层的特别配置等。容器会在初始化时对配置的Bean进行预实例化,Bean的依赖注入在容器初始化时就已经完成,【属于立即加载,适合单例模式】,一般推荐使用。


spring bean的作用域:

  1. singleton(默认)
  2. prototype
  3. request(只在WebApplicationContext中有)
  4. session(只在WebApplicationContext中有)
  5. global session(只在WebApplicationContext中有)

WebApplicationContext:ApplicationContext的子类,专门给web应用使用的。

无状态bean使用singleton,有状态bean使用prototype。

spring会管理singleton bean从创建到销毁的整个生命周期。
而对于prototype bean,spring只负责创建,不负责销毁。

单例bean生命周期的理解记忆,可以分为两部分:

  1. 生命周期的【概要流程】
  2. 生命周期的【扩展点】

概要流程:

  1. 创建实例(构造函数)
  2. 属性注入(setter)
  3. 初始化(init-method,通过XML配置)
  4. 销毁(destroy-method,通过XML配置)

BeanFactory中bean的生命周期:


bean生命周期.png

processor对所有的bean都有效。

AOP就是借助BeanPostProcessor#postProcessAfterInitialization实现的。
在postProcessAfterInitialization方法里对对象进行判断,看它需不需要织入切面逻辑,如果需要,那就根据这个对象,生成一个代理对象,然后返回这个代理对象,那么最终放入容器的,自然就是代理对象了。

@PostConstruct、@PreDestroy都是JDK定义的注解。
被@PostConstruct修饰的注解在BeanPostProcessor#postProcessBeforeInitialization之后,InitializingBean#afterPropertiesSet之前,执行。

如果注入的属性为null,你会从哪几个方向去排查?

  1. 想要注入的那个bean是否配置或加了注解。
  2. 扫描路径是否正确。
  3. 有一种低级的错误,自己用new实例化spring bean,那获取属性肯定NPE。
  4. @Autowired是否加到了static字段上。
  5. 是不是在spring注入前使用属性,比如在无参构造函数里使用。

AOP

aop:面向切面编程,把oop代码之间的冗余逻辑拿出来放到切面当中,在需要执行时,通过动态代理,在不改变oop源码的基础上对方法进行功能增强。

  1. 当切面bean是一个切口时,spring使用jdk的动态代理。
  2. 否则使用cglib的动态代理。

JDK动态代理:基于反射生成【实现接口】的代理类。
CGLib动态代理:基于ASM(开源的Java字节码编辑库),通过修改被代理类的字节码来【生成子类】作为代理类。

常用场景包括权限认证、自动缓存、错误处理、日志、事务等。

aop的常用注解:
@Aspect:声明被注解的类是一个切面Bean。
@Pointcut、@After、@Before、@Around

一般流程:

  1. 通过@Pointcut定义切点(正则,配置包路径)
  2. @After、@Before、@Around为匹配指定切点的方法进行功能增强。

相关文章

网友评论

      本文标题:面试官:讲一下spring的ioc和aop

      本文链接:https://www.haomeiwen.com/subject/asrslrtx.html