ProxyFactory选择cglib或jdk动态代理原理
ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术:
config就是ProxyFactory对象,把自己传进来了,因为ProxyFactory继承了很多类,其中一个父类就是ProxyConfig
// config就是ProxyFactory对象// 是不是运行在GraaJVM上面 如果是就用的JDK动态代理
// optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface
// Optimize默认是false 可以设置为ture,早期版本cglib工作效率高于jdk 后面就差不多了
// isProxyTargetClass()意思是你要代理的是不是类?设置为true 底层就只用cglib 默认false
// 因为jdk只能代理接口,底层就不会关心你传进来的是接口还是类,就算proxyFactory.addInterface()开启接口代理也没用
if (config.isOptimize() || config.isProxyTargetClass() // 判断当前proxyFactory有没有addInterface() 如果添加了 就返回false 调用jdk动态代理// 不会去真正看你的被代理类上是否真的实现了接口 这里之后spring就做了优化|| 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.");}// 如果被代理的类targetClass是接口,直接使用Jdk动态代理if (targetClass.isInterface() // 你设置的类是不是jdk动态代理产生的代理类【非常少用】|| Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}// 使用Cglibreturn new ObjenesisCglibAopProxy(config);
}
else {// 使用Jdk动态代理return new JdkDynamicAopProxy(config);
}
针对上面第18行
// 如果被代理的类targetClass是接口,直接使用Jdk动态代理
99%不会这么使用 无需掌握 会报错
因为没有设置target,被代理的是哪个对象,它咋增强。。target都是灰色的
总结:
运行在GraaJVM,开启了优化isOptimize,isProxyTargetClass传的代理是不是个类【而不是接口】,hasNoUserSuppliedProxyInterfaces看proxyFactory是不是调用了addInterface()方法,如果以上符合任意一个就会用cglib动态代理,否则用的就是jdk动态代理。
所以在ProxyFactory生成代理对象前会去判断用的哪个动态代理,选定好技术后再调用getProxy()去产生真正的代理对象
JDK动态代理 一行代码搞定【底层就调用newProxyInstance 一模一样 传入类加载器 接口 方法拦截器】
参数:类加载器,添加的接口,传的invokationHandler是this
这里advised其实是proxyFactory,拿到proxyFactory设置的TargetSource,拿到被代理对象然后判断当前执行的啥方法
像equals、hashCode这种方法是不会执行advice的代理逻辑的
如果为true会把代理对象放到ThreadLocal里去
具体可以在proxyFactory设置这个属性,设置为true
只要在当前线程 通过AppContext 可以拿到当前的代理对象了。那这个功能有啥用呢???
可以用于@Transcation失效的场景,自己把它取出来用。例如自己注入自己那个解决事务失效的办法其实也可以用这个方法
取出被代理对象
传入当前正在执行的方法,当前被代理的类到proxyFactory【也就是这里的advised属性】,在getInterceptorsAndDynamicInterceptionAdvice方法里筛选,筛选出符合当前方法和类的advice
我可以添加很多Advisor
先会执行Advice链路,再去执行被代理对象target的方法
如果没有筛选出来,就说明没有代理逻辑要执行,就直接执行被代理的方法
如果有advice就把得到的代理对象,被代理对象,当前执行的方法,参数,被代理的类,以及筛选出来的链传进去,然后执行
小总结
由ProxyFactory产生的代理对象底层怎么执行的?
代理对象在执行某个方法的时候,首先取出TargetSource,判断当前执行的方法是什么,如果是equals,hashCode这些就不走代理逻辑,直接执行被代理的方法。如果exposeProxy设置为true会放到TheardLocal里面去,然后调用TargetSource的getTarget方法 取出真正的被代理对象【可以自己实现】,然后筛选匹配的Advice和advisor然后去执行
筛选的详细逻辑
不是每次执行方法都要去找,这里会有个缓存 ,方法作为key
MethodInterceptor非常灵活,底层也用的这个
底层你添加的Advice最后都会转成MethodInterceptor,
config就是ProxyFactory,取出所有的Advisors,那advice去哪了?其实早就把那advice转成Advisor了
理由如下:
===================