> 文章列表 > 4.7 AOP底层源码原理

4.7 AOP底层源码原理

4.7 AOP底层源码原理

 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底层又是怎么实现的呢?

待更新