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

构造器

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

  1. final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable

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

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

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

getProxy

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

  1. @Override
  2. public Object getProxy() {
  3. return getProxy(ClassUtils.getDefaultClassLoader());
  4. }
  5. @Override
  6. public Object getProxy(ClassLoader classLoader) {
  7. if (logger.isDebugEnabled()) {
  8. logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
  9. }
  10. Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
  11. findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
  12. return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
  13. }
  14. /**
  15. * Finds any {@link #equals} or {@link #hashCode} method that may be defined
  16. * on the supplied set of interfaces.
  17. * @param proxiedInterfaces the interfaces to introspect
  18. */
  19. private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
  20. for (Class<?> proxiedInterface : proxiedInterfaces) {
  21. Method[] methods = proxiedInterface.getDeclaredMethods();
  22. for (Method method : methods) {
  23. if (AopUtils.isEqualsMethod(method)) {
  24. this.equalsDefined = true;
  25. }
  26. if (AopUtils.isHashCodeMethod(method)) {
  27. this.hashCodeDefined = true;
  28. }
  29. if (this.equalsDefined && this.hashCodeDefined) {
  30. return;
  31. }
  32. }
  33. }
  34. }

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

invoke

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

  1. @Override
  2. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  3. MethodInvocation invocation;
  4. Object oldProxy = null;
  5. boolean setProxyContext = false;
  6. TargetSource targetSource = this.advised.targetSource;
  7. Class<?> targetClass = null;
  8. Object target = null;
  9. try {
  10. if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
  11. return equals(args[0]);
  12. }
  13. else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
  14. return hashCode();
  15. }
  16. else if (method.getDeclaringClass() == DecoratingProxy.class) {
  17. return AopProxyUtils.ultimateTargetClass(this.advised);
  18. }
  19. else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
  20. method.getDeclaringClass().isAssignableFrom(Advised.class)) {
  21. return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
  22. }
  23. Object retVal;
  24. if (this.advised.exposeProxy) {
  25. oldProxy = AopContext.setCurrentProxy(proxy);
  26. setProxyContext = true;
  27. }
  28. target = targetSource.getTarget();
  29. if (target != null) {
  30. targetClass = target.getClass();
  31. }
  32. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
  33. if (chain.isEmpty()) {
  34. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
  35. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
  36. }
  37. else {
  38. invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  39. retVal = invocation.proceed();
  40. }
  41. Class<?> returnType = method.getReturnType();
  42. if (retVal != null && retVal == target &&
  43. returnType != Object.class && returnType.isInstance(proxy) &&
  44. !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
  45. retVal = proxy;
  46. }
  47. else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
  48. throw new AopInvocationException(
  49. "Null return value from advice does not match primitive return type for: " + method);
  50. }
  51. return retVal;
  52. }
  53. finally {
  54. if (target != null && !targetSource.isStatic()) {
  55. targetSource.releaseTarget(target);
  56. }
  57. if (setProxyContext) {
  58. AopContext.setCurrentProxy(oldProxy);
  59. }
  60. }
  61. }

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

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

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

  1. if (chain.isEmpty()) {
  2. //处理被代理方法参数
  3. Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
  4. //反射执行被代理方法
  5. retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
  6. }
  7. else {
  8. // 创建代理方法
  9. invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  10. // 执行代理方法
  11. retVal = invocation.proceed();
  12. }

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

  1. public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
  2. throws Throwable {
  3. // Use reflection to invoke the method.
  4. try {
  5. ReflectionUtils.makeAccessible(method);
  6. return method.invoke(target, args);
  7. }
  8. catch (InvocationTargetException ex) {
  9. // Invoked method threw a checked exception.
  10. // We must rethrow it. The client won't see the interceptor.
  11. throw ex.getTargetException();
  12. }
  13. catch (IllegalArgumentException ex) {
  14. throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
  15. method + "] on target [" + target + "]", ex);
  16. }
  17. catch (IllegalAccessException ex) {
  18. throw new AopInvocationException("Could not access method [" + method + "]", ex);
  19. }
  20. }

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

  1. protected ReflectiveMethodInvocation(
  2. Object proxy, Object target, Method method, Object[] arguments,
  3. Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
  4. this.proxy = proxy;
  5. this.target = target;
  6. this.targetClass = targetClass;
  7. this.method = BridgeMethodResolver.findBridgedMethod(method);
  8. this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
  9. this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
  10. }

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

  1. public Object proceed() throws Throwable {
  2. // We start with an index of -1 and increment early.
  3. if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
  4. return invokeJoinpoint();
  5. }
  6. Object interceptorOrInterceptionAdvice =
  7. this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  8. if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
  9. // Evaluate dynamic method matcher here: static part will already have
  10. // been evaluated and found to match.
  11. InterceptorAndDynamicMethodMatcher dm =
  12. (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
  13. if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
  14. return dm.interceptor.invoke(this);
  15. }
  16. else {
  17. // Dynamic matching failed.
  18. // Skip this interceptor and invoke the next in the chain.
  19. return proceed();
  20. }
  21. }
  22. else {
  23. // It's an interceptor, so we just invoke it: The pointcut will have
  24. // been evaluated statically before this object was constructed.
  25. return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  26. }
  27. }

从上面分析源码大致可以了解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. 为什么要用深度学习来做个性化推荐 CTR 预估

    欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 作者:苏博览 深度学习应该这一两年计算机圈子里最热的一个词了.基于深度学习,工程师们在图像,语音,NLP等领域都取得了令人振奋的进展.而深 ...

  2. 使用千位分隔符(逗号)表示web网页中的大数字

    做手机端页面我们常常遇到数字,而在Safari浏览器下这些数字会默认显示电话号码,于是我们就用到了补坑的方法加入<meta>标签: <meta name="format-d ...

  3. Javascript写的一个可拖拽排序的列表

    自己常试写了一个可拖拽进行自定义排序的列表,可能写的不太好,欢迎提供意见. 我的思路是将列表中的所有项都放进一个包裹层,将该包裹层设为相对定位,每当点击一个项时,将该项脱离文档并克隆一份重新添加到文档 ...

  4. Springboot - 学习笔记 ②

    前言 这一篇是关于spring boot中的配置(configuration)的介绍,我们接下来要说的男主就是 “application.properties”. “男神”默认是生成在“/src/ma ...

  5. Easyui后台管理角色权限控制

    最近需要做一个粗略的后台管理的权限,根据用户的等级来加载相应的菜单,控制到子菜单.使用的是Easyui这个框架. 1.我使用的mysql数据库.在这里我就建立四张表,角色表(tb_users),菜单表 ...

  6. VS2017 编译 chromium和webrtc

    Chromium的编译和WebRTC的编译方式相同,WebRTC官网也是使用的Chromium的编译文档. 步骤一.跳 - 墙,先跳 - 墙这是第一步哟,chromium大概有10几个G,webrtc ...

  7. JS类继承常用方式发展史

    JS类继承常用方式发展史 涉及知识点 构造函数方式继承 1-继承单个对象 1.1 多步走初始版 1.2 多步走优化版 1.3 Object.create()方式 2-继承多个对象 2.1 遍历 Obj ...

  8. gulp使用1-入门指南

    入门指南 1. 全局安装 gulp: $ npm install --global gulp 或使用cnpm 2. 作为项目的开发依赖(devDependencies)安装: $ npm instal ...

  9. ceph在品高云中的实践

    ceph简介 ceph是业界目前人气最高的开源存储项目之一,关于其定义在官网是这样的:"Ceph is a unified, distributed storage system desig ...

  10. scala PartialFunction

    1.orElse和andThen的区别 源码如下,区别很明显,orElse是并列的关系,而andThen是调用者的结果作为k的输入. trait PartialFunction[-A, +B] ext ...