上文介绍了代理类是由默认AOP代理工厂DefaultAopProxyFactory中createAopProxy方法产生的。如果代理对象是接口类型,则生成JdkDynamicAopProxy代理;否则生成ObjenesisCglibAopProxy代理,ObjenesisCglibAopProxy代理是继承于CglibAopProxy。下面先从熟悉的入手,选择JdkDynamicAopProxy分析。

构造器

查看源码,可以看到JdkDynamicAopProxy是一个final类,不能被继承和实现。其实现了AopProxy, InvocationHandler, Serializable接口,如下所示:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable

下面看看JdkDynamicAopProxy 构造器,源码如下:

public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}

从构造器可以看出,JdkDynamicAopProxy依赖于AdvisedSupport,根据config配置信息创建动态代理对象。代码中config.getAdvisors()提供的是Advisor列表。

getProxy

getProxy 方法是实现AopProxy接口,源码如下:

	@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
} @Override
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, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
} /**
* Finds any {@link #equals} or {@link #hashCode} method that may be defined
* on the supplied set of interfaces.
* @param proxiedInterfaces the interfaces to introspect
*/
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
for (Class<?> proxiedInterface : proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}

在创建代理时,既可以采用默认的类加载器,也可以指定特定的类加载器。JDK动态代理的代理对象是接口类型,先获取被代理对象的完整接口、根据指定的类加载器以及实现的调用处理器应用静态方法Proxy.newProxyInstance创建代理对象。

invoke

上文介绍了InvocationHandler 接口,invoke该接口中唯一一个定义的方法。JdkDynamicAopProxy 是final类并且实现了InvocationHandler 接口,那么也必然实现了invoke方法,其源码如下:

	@Override
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 {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
} Object retVal; if (this.advised.exposeProxy) { 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()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
} Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
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()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}

前面只是一些校验,直接省略,步入重点。通过target = targetSource.getTarget()得到被代理对象的类名。再根据被代理类名和方法名得到拦截链,也即通知链。如下所示:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

如果拦截链为空,则直接反射调用被代理方法,否则需要创建代理方法,此代理方法中已经加入附加处理(通知)。如下:

			if (chain.isEmpty()) {
//处理被代理方法参数
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//反射执行被代理方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建代理方法
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行代理方法
retVal = invocation.proceed();
}

反射执行被代理方法是调用工具类AopUtils中方法invokeJoinpointUsingReflection实现的,具体如下:

	public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
throws Throwable { // Use reflection to invoke the method.
try {
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
}
catch (InvocationTargetException ex) {
// Invoked method threw a checked exception.
// We must rethrow it. The client won't see the interceptor.
throw ex.getTargetException();
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
method + "] on target [" + target + "]", ex);
}
catch (IllegalAccessException ex) {
throw new AopInvocationException("Could not access method [" + method + "]", ex);
}
}

创建代理方法是通过ReflectiveMethodInvocation实现的,然后调用proceed()方法执行拦截链和被代理方法。ReflectiveMethodInvocation实现了Joinpoint接口,其构造器如下:

	protected ReflectiveMethodInvocation(
Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) { this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}

ReflectiveMethodInvocation调用proceed方法执行代理,proceed方法是在Joinpoint接口中定义的,ReflectiveMethodInvocation中进行了实现。具体实现如下:

	public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
} Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

从上面分析源码大致可以了解Spring AOP 动态代理的设计思想,采用类加载器根据接口产生代理方法,代理方法是在原方法的基础上加上通知链,以实现AOP功能。当执行方法时,判断该方法通知链是否为空,若为空,则通过反射直接调用原方法;若不为空,则产生代理方法,执行代理方法。下一节将继续探讨Spring AOP 的另一种实现方法CGLIB

Spring AOP分析(2) -- JdkDynamicAopProxy实现AOP的更多相关文章

  1. Spring AOP分析(3) -- CglibAopProxy实现AOP

    上文探讨了应用JDK动态代理实现Spring AOP功能的方式,下面将继续探讨Spring AOP功能的另外一种实现方式 -- CGLIB. 首先,来看看类名CglibAopProxy,该类实现了两个 ...

  2. 框架源码系列三:手写Spring AOP(AOP分析、AOP概念学习、切面实现、织入实现)

    一.AOP分析 问题1:AOP是什么? Aspect Oriented Programming 面向切面编程,在不改变类的代码的情况下,对类方法进行功能增强. 问题2:我们需要做什么? 在我们的框架中 ...

  3. 动态代理3--Spring AOP分析

    Spring AOP的基本实现方式 ​Spring AOP,一种模块化机制,能够动态的对切点添加行为,而不破坏原有的代码结构. 这是一个非常好地动态代理的应用方式.Spring AOP实现依赖于JDK ...

  4. Spring源码剖析7:AOP实现原理详解

    前言 前面写了六篇文章详细地分析了Spring Bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析.为了探究AOP实现原理,首先定义几个类,一个Dao接口: pub ...

  5. Spring:面向切面编程的AOP

    一.前言 除了依赖注入(DI),Spring框架提供的另一个核心功能是对面向方面的编程(AOP)的支持. AOP通常被称为实现横切关注点的工具.横切关注点一词是指应用程序中的逻辑不能与应用程序的其余部 ...

  6. spring框架学习(六)AOP

    AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可 ...

  7. Spring(4)——面向切面编程(AOP模块)

    Spring AOP 简介 如果说 IoC 是 Spring 的核心,那么面向切面编程就是 Spring 最为重要的功能之一了,在数据库事务中切面编程被广泛使用. AOP 即 Aspect Orien ...

  8. Spring框架系列(五)--面向切面AOP

    背景: 当需要为多个不具有继承关系的对象引入一个公共行为,例如日志.权限验证.事务等功能时,如果使用OOP,需要为每个对象引入这些公共 行为.会产生大量重复代码,并且不利用维护.AOP就是为了解决这个 ...

  9. Spring框架的核心功能之AOP技术

     技术分析之Spring框架的核心功能之AOP技术 AOP的概述        1. 什么是AOP的技术?        * 在软件业,AOP为Aspect Oriented Programming的 ...

随机推荐

  1. 移动端touch事件实现页面弹动--小插件

    动手之前的打盹 说实话真的是好久没有更新博客了,最近一直赶项目,身心疲惫:最关键的是晚上还要回去上一波王者,实在是忙啊! 这周下来,清闲了些许,或许是因为要到国庆的缘故吧,大家都显得无精打采.俗话说的 ...

  2. Python 编程基础之高阶函数篇(一)

      高阶函数:能接受函数作为参数的函数. 如: f=abs def   add(x,y,f): return f(x)+f(y) 如果我们用:add(-5,9,f)来调用该高阶函数,则返回结果为:14 ...

  3. .net窗体程序的基础知识及详细笔记

    第一章:初识Windows程序 1.1:第一个wondows程序 1.1.1:认识windows程序 Form1.cs:窗体文件:程序对窗体编写的代码一般都存放在这个文件(还有拖动控件时的操作和布局, ...

  4. Crossin-8-1;8-2课程记录

    打开文件:    open,注意打开文件的路径    读取结束需使用close读取文件:    read    readlines    readline    for in 重置光标位置:   se ...

  5. Python实战之SocketServer模块

    文章出处:http://www.cnblogs.com/wupeiqi/articles/5040823.html SocketServer内部使用 IO多路复用 以及 "多线程" ...

  6. BZOJ-5055-膜法师(离散化+树状数组)

    Description 在经历过1e9次大型战争后的宇宙中现在还剩下n个完美维度, 现在来自多元宇宙的膜法师,想偷取其中的三个维度为伟大的长者续秒, 显然,他能为长者所续的时间,为这三个维度上能量的乘 ...

  7. ZOJ2334 Monkey King 并查集 STL

    题意:两家原始人(猴)打交道后成为一家猴,打交道时两家分别派出最帅的两位猴子,颜值各自减半,问每次打交道后新家族最帅的猴子的颜值.当然,已经是一家子就没有必要打交道了,因为没有猴希望颜值降低,毕竟还得 ...

  8. spring cloud+dotnet core搭建微服务架构:配置中心(四)

    前言 我们项目中有很多需要配置的地方,最常见的就是各种服务URL地址,这些地址针对不同的运行环境还不一样,不管和打包还是部署都麻烦,需要非常的小心.一般配置都是存储到配置文件里面,不管多小的配置变动, ...

  9. java spark-streaming接收TCP/Kafka数据

    本文将展示 1.如何使用spark-streaming接入TCP数据并进行过滤: 2.如何使用spark-streaming接入TCP数据并进行wordcount: 内容如下: 1.使用maven,先 ...

  10. eval函数的用法

    可以把list,tuple,dict和string相互转化. ################################################# 字符串转换成列表 >>&g ...