Spring源码学习笔记
AOP
面向切面横向编程
AOP所用到的代理模式有jdk代理(java动态代理),CGLIB代理,Spring是没有默认使用哪个代理的,取决于代理对象是否为接口,为接口则使用jdk代理,否则则是CGLIB代理。
原生对象在什么时候被代理?
在bean初始化到时候就已经被代理了。
spring有7个后置处理器,在第4个的时候开始处理。
在DefaultAopProxyFactory.java中选择代理模式。
抛出一个问题:java动态代理和CGLIB代理的底层实现?
反射
深入探讨:
为什么java动态代理必须是接口???
因为java是单继承多实现的,因为代理的对象已经默认集成了Proxy对象,所以只能实现接口。
(.java文件生成.class字节码文件后内容转变为jvm运行的指令,拿到它的字节码,就可以在前后增加一些指令实现代理。java提供了Proxy.java,其中generatorProxyClass方法可以修改生成字节码)
循环依赖
a依赖b,b依赖a。
这边需要了解Bean的生命周期。
概念:
第一级缓存:单例池(singletonObjects)
Map<beanName: 单例对象> ConcurentHashMap
单例池中的对象为代理对象。代理对象的内部实际包裹了原始对象。
如何解决:
第二级缓存(earlySingletonObjects)
实例化的原始对象存入缓存(一个Map),但是这边的原始对象是没有值的。
提前AOP生成代理对象,将此代理对象存入缓存(Map)。
HashMap
这边需要判断是否出现了循环依赖,实际上在初始化a的时候是无法判断的。在初始化b的时候需要a,但是a还是创建中,这时候就可以判断出现循环依赖了。提前进行AOP创建a的代理对象。
这样就可以解决了。
但是如果a依赖b和c,b依赖a,c依赖a,这边创建b和c的时候都需要提前AOP,创建a的代理对象,这边就出现了问题,不符合单例。这边就加一个Map,将提前AOP出来的代理对象放入此Map中,这样就可以先去此Map中找是否已经提前AOP出来a的代理对象。
第三级缓存(singletonFactories)
(Map<beanNmae: lambda(beanName, bd, 原始对象)>)HashMap
AOP的时候需要用到原始对象。
这边的lambda表达式是不会执行的,只是一个定义。
不执行的原因是不知道是否出现了循环依赖,这个lambda执行的话就是在进行AOP。
AOP生成代理对象后放入二级缓存中(这边对象如果不需要进行AOP的话就直接返回原始对象也需要放入二级缓存中),然后移除三级缓存中的这个bean。
为什么三级缓存要移除?
因为要符合单例。原子性。
为什么二级三级缓存是Hashmap,一级缓存是ConcurentHashMap?
因为二级三级缓存需要保证原子性,同时操作,需要加锁,用ConcurentHashMap影响性能。
正常进行AOP的时候会从一级二级缓存中寻找代理对象。