01 引子
上面一篇文章你真的清楚SpringAOP在哪里进行代理的吗?我们猜想了Spring AOP在哪里进行代理的.
public class Test { public static void main(String[] args) { //猜想一:AOP在这里实现的?---【是否正确有待考证】 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Appconfig.class); //猜想二:AOP在这里实现的?---【错误】从上面的猜想可以推断出AOP不在这里进行的 UserDao bean = ac.getBean(UserDao.class); bean.query(); }
02 Spring AOP在这里进行代理的
我们点开这个
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(Appconfig.class)方法,代码如下:
AnnotationConfigApplicationContext方法
这个代码再往下看,你会发现一层套着一层,要是一层一层往下点看你会受不了,最后头皮发麻,最后了了收场,这也是源码最难最容易劝退大家的地方,不过我们不用灰心,不知道大家还没记得上篇文章你真的清楚SpringAOP在哪里进行代理的吗?我们得到了一个很关键的一段代码:
Object singletonObject = this.singletonObjects.get(beanName);
我们从容器中取出这个AOP被代理过的bean,那么肯定有地方进行存,我们可以全局搜一下在哪里进行put,这样我们才能有的放矢.
搜索结果如下:
从这个类名称上来看,第一个类的把握性比较大(
DefaultSingletonBeanRegistry),我们在源码阅读时要进行大胆的猜想和假设,就算猜错了大不了从头再来(做大事者不要纠结)
我们把这段代码点开,然后在这个put地方打个断点,再来具体看看对应的堆栈情况;
断点之后的情况如下:
堆栈信息
在这个堆栈中我们可以猜想很大可能是doGetBean这个方法(这个方法非常重要),为什么我会猜想是这个方法呢,因为只有这个方法看着比较像,排除一些get方法,这个方法概率最大,这个时候我们再点开这个方法:
doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
这个方法我们是不是很熟悉,我们在上面猜想的时候也是通过这个方法里面getSingleton(beanName)拿到这个代理的bean,这个时候我们点进去sharedInstance肯定是null,所以这个if方法不会走进去
然后我们一步步往下debug走,此处省略一些不重要的代码,我们来到了一个非常关键的方法createBean(beanName,mbd,args)如下:
我们点开这个createBean(beanName,mbd,args)代码,如下:
然后我们再一步步往下走,此处略去部分断点代码内容(如果碰到无法决定是否需要点进去要看的代码,我们就断点执行一下,看是不是我们期望的结果),然后我们走到下面这一步,也是关键的一步
这里有一个很关键的代码,aop也是从这里进来的,代码如下:
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
这个代码我们点进去看看如下:
继续往下走,此处略过部分断点内容,关键代码如下:
exposedObject = initializeBean(beanName, exposedObject, mbd)
这个代码我们点进去,如下图:
继续往下走,此处我们略过部分断点内容,关键代码如下:
我们点进这个方法如下图:
这个时候我们越来越接近事情的真相了,这段代码429行代码有个循环,这里需要注意一下,我们主要看循环第四次的结果往下走,也就是下标是3的
然后我们把下面这个方法点进去看看
点进去的代码如下:
接下来我们把这个return wrapIfNecessary(bean, beanName, cacheKey)代码点进去看看代码如下:
我们再把上面图片里面标红色的地方再点进去看看,如下图:
我们再一步步断点这个方法(此处略去部分断点内容),我们发现这个方法的最后一行代码是我们要看的,代码如下:
return proxyFactory.getProxy(getProxyClassLoader());
我们把proxyFactory.getProxy()方法点进去,如下图所示:
我们再把上面标注的关键代码的方法点进去看看,这个时候我们已经快接近真相了,点进去的代码如下:
这个地方就是真正选择使用cjlib还是java动态代理的地方,大家有没注意到下面的这个if判断:
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config);
targetClass.isInterface():判断是否是接口,如果是接口的话则使用jdk动态代理,如果不是则使用cjlib,这也是大家面试当中经常被问到spring的AOP是使用java动态代理还是cjlib;
在这里我们已经判断了是选择哪种方式进行代理(java动态代理还是cjlib),接下来我们再回过头来看之前的代码,因为真正实现代理的细节在前面这段代码:
public Object getProxy(@Nullable ClassLoader classLoader) { return createAopProxy().getProxy(classLoader); }
我们点开这个getProxy(classLoader)方法,如下图:
这里就是具体的动态代理实现的类.
03 总结
我们花了两篇文章去寻找Spring AOP在哪里进行代理的,我还是建议大家看完之后自己尝试去debug找一下,这样便于消化吸收.
后面的文章我会继续带大家分析Spring AOP里面的一些细节代码.
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!