美文网首页
面试官:讲一下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