==> 学习汇总(持续更新)
==> 从零搭建后端基础设施系列(一)-- 背景介绍
-
CASE
- A
@Component public class A { @Lazy @Autowired B b; public void sayA(){ b.sayB(); } }
- B
@Component public class B { public void sayB(){} }
- C
@Aspect @Component public class C { @Pointcut("execution(public * com.acme.lazydemo.*.*(..))") public void myAnnotationPointcut(){ } @Before("myAnnotationPointcut()") public void before(JoinPoint joinPoint){ System.out.println(joinPoint.getTarget() + " begin:" + System.currentTimeMillis()); } @After("myAnnotationPointcut()") public void after(JoinPoint joinPoint){ System.out.println(joinPoint.getTarget() + " end:" + System.currentTimeMillis()); } }
接着看现象,第一层代理,实例号记一下
@4610
接着单步跟进去,发现target是一个代理对象,并且实例号是@4016
,和刚才那个不是同一个。按理说,target应该是实例本身才对,为什么还是一个代理对象呢?
接下来我们就带着这个疑问,深入源码一探究竟。 - A
-
原理分析
-
第一层代理是什么?
第一层代理很简单,是因为@Lazy
而产生的一个代理。如果不知道的,可以看一下【追根究底】@Lazy注解为什么会失效?这篇文章。 -
第二层代理是什么?
第二层代理,其实就是bean的实例化过程创建的。在实例化一个bean的时候,会在最后判断一下,这个bean上是否存在增强器,存在的话,就会创建一个代理。通俗点,有没有被切(AOP),有的话,肯定得用代理才能生效吧。因为这个例子中,使用到了C
类,它是一个AOP类,将A
和B
切了,所以A
和B
都需要被代理。
由代码中的注释可以知道,如果存在增强器,那么就为这个bean创建代理
所以第二层代理就是这么来的 -
第一层代理是如何拿到第二层代理的?
就从targetSource.getTarget()
里面拿到的。看过【追根究底】@Lazy注解为什么会失效?这篇文章的都知道,在为B创建@Lazy
代理对象的时候,创建了TargetSource
,里面实现了getTarget
方法。这里再把代码贴一下吧。protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) { Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory, "BeanFactory needs to be a DefaultListableBeanFactory"); final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory(); TargetSource ts = new TargetSource() { …… @Override public Object getTarget() { Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null); …… return target; } @Override public void releaseTarget(Object target) { } }; ProxyFactory pf = new ProxyFactory(); pf.setTargetSource(ts); …… return pf.getProxy(beanFactory.getBeanClassLoader()); }
doResolveDependency
方法最终会调用createBean
,如果该bean已经被创建了,那么从缓存中直接拿,如果没有,就走正常的bean创建流程。所以此时返回的target
就是B
的第二层代理了。
-
-
总结
- 产生两层代理的原因是
@Lazy
标记的属性,会为它创建一个代理对象,此时不会创建真实实例 - 拿到第二层代理的方式,创建第一层代理的时候,创建
TargetSource
并实现getTarget
方法,当第一层代理调用该类的方法的时候,会通过getTarget
拿到第二层代理。 - 思考为什么要为B创建一个代理对象呢?因为spring容器初始化的时候,并没有实例化B,所以,如果你不给一个代理对象,什么都不做,使用到它的时候,会报空指针异常吧?给了一个代理对象,然后再通过一些手段,当使用到它的时候,创建或者拿到B,再用它真实的调用方法,这不就什么事都没了。
- 产生两层代理的原因是