Spring-总结

一、IOC与AOP

IOC是工厂模式的实现,对Bean进行的初始化和使用进行解耦。
减少初始化,增加Bean对象的复用率。

AOP是代理模式的实现
AOP是切片,是为了对功能进行前后增强

二、Bean的生命周期

可以直观的就是4个周期,在这之间会加载一些扩展。
1.实例化
2.属性赋值
3.初始化
4.销毁
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
具体点文字描述:
1.实例化对象;
2.填充属性值及引用;
3.调用 BeanNameAware 的 setBeanName(String name) 设置 bean 的 id;
4.调用 BeanFactoryAware 的 setBeanFactory(BeanFactory beanFactory) 设置 BeanFactory Bean工厂;
5.同上:ApplicationContextAwaresetApplicationContext(ApplicationContext applicationContext);
6.如果实现 BeanPostProcessor,则 调用 postProcessBeforeInitialization() 初始化前的后置处理方法
7.如果实现了 InitializingBean 接口,则使用 afterPropertiesSet() 来初始化属性
8.如果实现 BeanPostProcessor,则 调用 postProcessAfterInitialization() 初始化后的后置处理方法
此时,bean 就可以使用了
9.DisposableBean接口 destroy() 销毁bean。不过在Spring5.0开始,DisposableBean.destroy() 已经是过时的方法了,可直接使用 close()。

三、作用域

单例:
2)prototype
3)request
4)session
每次请求来一次
5)global session

四、动态代理cjlib,jdk的区别

JDK动态代理:代理类与委托类实现同一接口,主要是通过代理类实现InvocationHandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理,只能够代理实现了接口的委托类,底层使用反射机制进行方法的调用。

CGLib动态代理:代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理。不能对final类以及final方法进行代理,底层将方法全部存入一个数组中,通过数组索引直接进行方法。

1、jdk是通过反射
2、cjlib通过修改class文件,主要是继承
3、cjlib不能代理final类,代理的方法不能是final方法
4、bean实现了接口,默认jdk,bean没有实现接口,默认cjlib,
但是可以强制
5、效率:jdk代理随着JDK升级,效率一直在提升,两种差别不大

附送链接:
代理原理剖析

五、循环依赖

Bean的循环依赖是指两个或者两个以上的Bean互相持有对方的引用,最终形成闭环,比如A依赖于B,B又依赖于A,当程序初始化时就会陷入死循环,从而导致堆栈溢出,程序异常退出。Spring框架通过三级缓存结构来解决单列Bean的循环依赖问题的。Spring IOC三级缓存结构如下:

/** Cache of singleton objects: bean name --> bean instance */
/** 一级缓存,存放完成初始化好的Bean*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
/** 二级缓存,存放原始的Bean对象(尚未填充属性),用于解决循环依赖问题
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name --> bean instance */
/**三级缓存,存放Bean工厂对象,用于解决循环依赖*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

由上个章节介绍的Bean的生命周期可知,对于非构造器注入Bean,实例化和设置属性是两个独立分开的操作,另一方面,Java是天生支持对象引用的,因此当创建对象A时,可以将实例化后半成品的对象A存储在缓存中,提前暴露出来,当设置A对象的属性B时,同样将实例化后半成品的B缓存,并设置为A对象的属性B的引用,Spring框架就是通过这种缓存结构来解决Bean的循环依赖问题的,具体创建流程如下:

  1. 通过getBean方法来获取A对象,实例化后将提前暴露的A(构造了一个工厂)放入到三级缓存中。

     2. 设置A的属性,getBean获取B对象。
    
     3. 实例化B,将提前暴露的B (构造了一个工厂)放入三级缓存。
    
     4. 设置B的属性, getBean获取A对象,这时从三级缓存中getObject获取到提前暴露的A,同时清除三级缓存,将getObject返回值放入二级缓存。
    
     5. B的初始化,将完成初始化好的B放入一级缓存,同时清除二、三级缓存, getBean获取B对象返回。
    
     6. A的初始化,将完成初始化好的A放入一级缓存,同时清除二、三级缓存并返回。
    

当用户设置被Spring IOC托管的Bean为单列时才会被放入缓存,同时只有对于非构造器注入Bean,实例化和设置属性才是两个独立分开的操作,因为部分情况下,Spring框架是无法解决Bean的循环依赖问题,现总结相关的结论如下:
1.循环依赖的Bean中存在构造器注入无法解决循环依赖。(实例化时就需要设置属性)

  2.循环依赖的Bean都不是单例Bean无法解决循环依赖。(实例化后不放入缓存,无法提前暴露)

 3.循环依赖的Bean只要有一个Bean是单例非懒加载就可以解决循环依赖。(容器初始化后就存在)

 4.循环依赖的Bean中如果一个是单例懒加载Bean,一个不是单例Bean,能否解决循环依赖要看哪个Bean首先被实例化。(先实例化单例的Bean会被缓存)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值