4.7.1 AOP源码
进入到这里
F8跳过assertBeanFactoryActive方法,因为spring它方法调用太乱了,如果不挑“核心”去看,很快你就会被绕晕,
那么我们怎么判断这个assertBeanFactoryActive不是核心,注意前面getbean方法返回值是个UserServiceImol,而设个assertBeanFactoryActive方法根本没有返回值
所以F8跳过,看下面的return getBeanFactory().getBean()
注意:看源码,不必每行源码都看,而是把核心看懂
点击getBean
里面调用了doGetBean方法
注意返回的sharedInstance对象就是一个代理对象
但是当我i们在这行加断点,Debug时,发现为空??
不是在这一步代理了,怎么为空?
因为spring自己的对象也要调用这个方法
进入getSingletion
先从单例缓存中查,根据key查询,这时候就已经是代理对象了,这里既然能get,证明之前肯定put过了。
我们可以搜索到addSingletion
打断点,发现这里的对象,根本不是我们想要的 。还是和上面的问题一样,因为spring自己的类也会调用这个。解决办法,使用条件断点,右键点击断点,在下面的condition中输入beanName.equals("userService"),输入自己想要的类名即可。
条件断点
再次Debug,会发现数据是我们想要的,但是发现,存进来的时候,就已经是代理对象了
追踪debug栈
那么,我怎么查
排除法,我使用折半查找
进入getSingletion,里面有这行代码,它的作用是 生产bean
会调用createBean方法
Landba表达式
进入createBean ,注意下面这行代码
查看这个mdbToUse对象,发现这里是原生对象,这里还没有进行代理
我们继续走,下面有这行代码
点击beanInstance,发现此时已经是代理对象了
因此,我们可以确定,在这个doCreateBean方法中发生了代理
在570行这里的bean还是原生,没有被代理的对象
继续往下走,这里进行了一次赋值,这里的exposeObject仍然是原生对象
但是当执行到initializeBean后,又一次赋值,注意这里的exposeObject就变成了代理对象
进入initializeBean方法
当执行到这里时
查看wrappedBean,已经是代理对象了
这里的result此时此刻还是个原生对象
spring的后置处理器,有很多个
我们代理的后置处理器
进入下面这个方法中
进入下面的方法中
方法里重点看这个
重点看最后一行
进入方法中
进入getProxy
注意,这里就是CGLIB和JDK代理的
具体选择哪个,取决于我们的那个原生对象是接口还是类
由于本例中的userServiceImpl是类,所以生成的是Cglib动态代理
如果我把它改成接口
那么最后就会生成JDK动态代理
下面就来研究这个
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//条件判断
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 如果是接口就使用jdk代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
//否则使用cglib代理
else {
return new JdkDynamicAopProxy(config);
}
}
说明:
isOptimize是个常量为optimize,默认false
isProxyTargetClass()也是个常量proxyTargetClass,默认false
但是这个proxyTargetClass可以修改
在启动类,就会使用到Cglib
hasNoUserSuppliedProxyInterfaces(config)就是判断是否实现了一个接口
编译完就是字节码文件,字节码文件是数组。所以通过数组来判断是否为接口
那么JDK和Cglib底层又是怎么实现的呢?
待更新