AOP动态代理解析4-jdk代理的实现
JDKProxy的使用关键是创建自定义的InvocationHandler,而InvocationHandler中包含了需要覆盖的函数getProxy,而当前的方法正是完成了这个操作。在此确认一下JDKDynamicAopProxy也确实实现了InvocationHandler接口,那么我们就可以推断出,在JdkDynamicAopProxy中一定会有个invoke函数,并且JdkDynamicAopProxy会把AOP的核心逻辑写在其中。查看代码,果然有这样个函数:
JdkDynamicAopProxy.java 获取代理对象的主要方法
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
主要切面逻辑在InvocationHandler的invoke方法中,而JdkDynamicAopProxy本身就实现了InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
//equals方法的处理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
//hash方法的处理
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
//Class类的isAssignableFrom(Class cls)方法:如果调用这个方法的class或接口与参数cls表示的类或接口相同,
//或者参数与cls表示的类或接口的父类,则返回true
//形象地:自身类.class.isAssignableFrom(自身类或子类.class)返回true。例:
//System.out.println(ArrayList.class.isAssignableFrom(Object.class));//false
//System.out.println(Object.class.isAssignableFrom(ArrayList.class));//true
if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
//有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
//获取当前方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
//如果没有发现任何拦截器那么直接调用切点方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
//将拦截器封装在ReflectiveMethodInvocation,以便于使用其proceed进行链表用拦截器
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
//使用拦截器链
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
//返回结果
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
上面的函数中最主要的工作就是创建了一个拦截器链,并使用ReflectiveMethodInvocation类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中实现了拦截器的逐一调用,那么继续来研究,在proceed方法中是怎么实现前置增强在目标方法前调用后置增强在目标方法后调用的逻辑呢?
public Object proceed() throws Throwable {
//执行完所有增强后执行切点方法
if(currentInterceptorIndex == interceptorsAndDynamicMethodMatchers.size() - 1)
return invokeJoinpoint();
//获取下一个要执行的拦截器
Object interceptorOrInterceptionAdvice = interceptorsAndDynamicMethodMatchers.get(++currentInterceptorIndex);
if(interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher)
{ //动态匹配
InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
if(dm.methodMatcher.matches(method, targetClass, arguments))
return dm.interceptor.invoke(this);
else
//不匹配则不执行拦截器
return proceed();
} else
{
//普通拦截器,直接调用拦截器,如:MethodBeforeAdviceInterceptor,AspectJAroundAdvice,AdpectJAfterAdvice
//将this作为参数传递以保证当前实例中调用链的执行
return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
}
}
在proceed方法中,获取代码逻辑并没有那么复杂,ReflectiveMethodInvocation中的主要职责是维护了链接调用的计数器,记录着当前调用链的位置,以便链可以有序地进行下去,那么在这个方法中并没有我们之前设想的维护各种增强的顺序,而是将此工作委托给了各个增强器,使各个增强器在内部进行逻辑实现。
AOP动态代理解析4-jdk代理的实现的更多相关文章
- spring源码系列8:AOP源码解析之代理的创建
回顾 首先回顾: JDK动态代理与CGLIB动态代理 Spring中的InstantiationAwareBeanPostProcessor和BeanPostProcessor的区别 我们得知 JDK ...
- Spring框架系列(12) - Spring AOP实现原理详解之JDK代理实现
上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分.@pdai Spring框架系列(12) - Spring AOP实现原理详解 ...
- java 代理模式(静态代理、动态代理、Cglib代理) 转载
Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩 ...
- AOP动态代理解析4-代理的创建
做完了增强器的获取后就可以进行代理的创建了 AnnotationAwareAspectJAutoProxyCreator->postProcessAfterInitialization-> ...
- spring的AOP动态代理--JDK代理和CGLIB代理区分以及注意事项
大家都知道AOP使用了代理模式,本文主要介绍两个代理模式怎么设置以及区别,对原文一些内容进行了引用后加入了自己的理解和更深入的阐述: 一.JDK代理和CGLIB代理的底层实现区别* JDK代理只能 ...
- Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理
AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...
- Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
spring-aop-4.3.7.RELEASE 在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...
- aop学习总结一------使用jdk动态代理简单实现aop功能
aop学习总结一------使用jdk动态代理实现aop功能 动态代理:不需要为目标对象编写静态代理类,通过第三方或jdk框架动态生成代理对象的字节码 Jdk动态代理(proxy):目标对象必须实现接 ...
- Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题
Spring AOP底层的动态代理实现有两种方式:一种是JDK动态代理,另一种是CGLib动态代理. JDK动态代理 JDK 1.3版本以后提供了动态代理,允许开发者在运行期创建接口的代理实例,而且只 ...
- AOP动态代理解析5-cglib代理的实现
CGLIB是一个强大的高性能的代码生成包.它广泛地被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的Interception(拦截).EasyMock和jMock是通过使 ...
随机推荐
- tomcat URL乱码问题
用get传参时,显示乱码 在tomcat里的server.xml中添加一下即可. <Connector port="8080" protocol="HTTP/1.1 ...
- JS 基本语句
1.循环中必备的条件: 初始值 循环条件 状态改变 循环体 for(初始值 循环条件 状态改变) { 循环体 } for(var i=0;i<100;i++ ...
- Gson解析复杂的json数据
最近在给公司做一个直播APK的项目,主要就是通过解析网络服务器上的json数据,然后将频道地址下载下来再调用Android的播放器进行播放,原先本来打算使用普通的json解析方法即JsonObject ...
- POJ 3597 Polygon Division (DP)
题目链接 题意:把一个正多边形分成数个三角形或者四边形,问有多少种方案. 题解: 如果分出的全为三角形的话,那就是正多边形三角剖分问题.它的结果就是Catalan数.现在也可以划分出四边形的话,可以采 ...
- ACdream 1224 Robbers (贪心)
一道贪心题,很久前做的,代码是我以前写的. 题意:有n个抢劫者抢劫了m块金子,然后第i个人平分xi/y块金子,但是会有除不尽的情况而金子不可再分,那么每个人都有一个不满意度fabs(xi / y - ...
- Does the OpenSceneGraph have a native file format?
From OpenSceneGraph-3.0 onwards we have new native file formats based on generic serializers that ar ...
- August 20th 2016 Week 34th Saturday
Everything you see exists together in a delicate balance. 你所看到的一切都处于微妙的平衡中. Seeking for balance in l ...
- 多线程编程1 - NSThread
每个iOS应用程序都有个专门用来更新显示UI界面.处理用户的触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验.一般的解决方案就是将 ...
- 转载_虚拟机下LInux(终端)配置网络的方法
出自: http://www.360doc.com/content/14/1027/11/17496895_420258403.shtml 对文章的重点进行剪贴,方便查看. 这几天在虚拟机vmware ...
- NYOJ题目62笨小熊
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAr4AAAK1CAIAAAChInrhAAAgAElEQVR4nO3dO3LjutaG4X8Szj0Qxx