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是通过使 ...
随机推荐
- windows下Emacs的安装与配置
1.下载 到这个网址可以下载到Emacs的windows版本:http://ftp.gnu.org/pub/gnu/emacs/windows/ 只需要一个压缩文档,如emacs-23.2-bin-i ...
- IIS 4.0配置
neHandler” 今天安装了windows7 开发web项目需要安装IIS,当安装完以后,web程序已经映射到了本地IIS上,运行出现如下错误提示 处理程序“PageHandlerFactor ...
- ExpandableListView的用法
ExpandableListView组件是android中一个比较常用的组件,当点击一个父item的时候可以将它的子item显示出来,像手机QQ中的好友列表就是实现的类型效果.使用Expandable ...
- LeetCode 231 Power of Two
Problem: Given an integer, write a function to determine if it is a power of two. Summary: 判断一个数n是不是 ...
- HDU 1087 Super Jumping! Jumping! Jumping! --- DP入门之最大递增子序列
DP基础题 DP[i]表示以a[i]结尾所能得到的最大值 但是a[n-1]不一定是整个序列能得到的最大值 #include <bits/stdc++.h> using namespace ...
- 51nod 1449 砝码称重(贪心算法)
题目:传送门. 题意:中文题. 题解:左物右码,w进制.m%w==0||m%w==1||m%w==w-1都是可以的,否则是NO. #include <iostream> #include ...
- 使用按钮控制HTML5背景音乐开关
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name ...
- PHP安全编程:不要让不相关的人看到报错信息
没有不会犯错的开发者,PHP的错误报告功 能可以协助你确认和定位这些错误,可以提供的这些错误的详细描述,但如果被恶意攻击者看到,这就不妙了.不能让大众看到报错信息,这一点很重要.做到这一 点很容易,只 ...
- Hibernate双向多对多对象关系模型映射
1 双向many-to-many 业务模型: 描述员工和项目 一个员工同时可以参与多个项目 一个项目中可以包含多个员工 分析:数据库的数据模型,通过中间关系表,建立两个one-to-many构成man ...
- java动态生成excel打包下载
@SuppressWarnings("unchecked") public String batchExport() throws DBException{ @SuppressWa ...