什么是AOP

AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
 
 
将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
 
横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
 
AOP的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。
 

AOP使用场景

AOP用来封装横切关注点,具体可以在下面的场景中使用:
 
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging  调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence  持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务

实现AOP的技术

主要分为两大类:
一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
 

如何使用Spring AOP

可以通过配置文件或者编程的方式来使用Spring AOP。
配置可以通过xml文件来进行,大概有四种方式:
1.        配置ProxyFactoryBean,显式地设置advisors, advice, target等
2.        配置AutoProxyCreator,这种方式下,还是如以前一样使用定义的bean,但是从容器中获得的其实已经是代理对象
3.        通过<aop:config>来配置
4.        通过<aop: aspectj-autoproxy>来配置,使用AspectJ的注解来标识通知及切入点
 
也可以直接使用ProxyFactory来以编程的方式使用Spring AOP,通过ProxyFactory提供的方法可以设置target对象, advisor等相关配置,最终通过 getProxy()方法来获取代理对象
 

Spring AOP代理对象的生成

Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。默认的策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理。
 
具体的生成代码放在JdkDynamicAopProxy这个类中
 
获取代理类要实现的接口,除了Advised对象中配置的,还会加上SpringProxy, Advised(opaque=false) 
检查上面得到的接口中有没有定义 equals或者hashcode的接口 
调用Proxy.newProxyInstance创建代理对象 
 
   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是JDK动态代理的核心

生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。
  1. public Object invoke(Object proxy,Method method,Object[] args) throwsThrowable {
  2. MethodInvocation invocation =null;
  3. Object oldProxy =null;
  4. boolean setProxyContext =false;
  5. TargetSource targetSource =this.advised.targetSource;
  6. Class targetClass =null;
  7. Object target =null;
  8. try{
  9. //eqauls()方法,具目标对象未实现此方法
  10. if(!this.equalsDefined &&AopUtils.isEqualsMethod(method)){
  11. return(equals(args[0])?Boolean.TRUE :Boolean.FALSE);
  12. }
  13. //hashCode()方法,具目标对象未实现此方法
  14. if(!this.hashCodeDefined &&AopUtils.isHashCodeMethod(method)){
  15. return newInteger(hashCode());
  16. }
  17. //Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知
  18. if(!this.advised.opaque &&method.getDeclaringClass().isInterface()
  19. &&method.getDeclaringClass().isAssignableFrom(Advised.class)){
  20. // Service invocations onProxyConfig with the proxy config...
  21. returnAopUtils.invokeJoinpointUsingReflection(this.advised,method, args);
  22. }
  23. Object retVal =null;
  24. if(this.advised.exposeProxy){
  25. // Make invocation available ifnecessary.
  26. oldProxy =AopContext.setCurrentProxy(proxy);
  27. setProxyContext =true;
  28. }
  29. //获得目标对象的类
  30. target = targetSource.getTarget();
  31. if(target !=null){
  32. targetClass = target.getClass();
  33. }
  34. //获取可以应用到此方法上的Interceptor列表
  35. List chain =this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);
  36. //如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
  37. if(chain.isEmpty()){
  38. retVal =AopUtils.invokeJoinpointUsingReflection(target,method, args);
  39. }else{
  40. //创建MethodInvocation
  41. invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
  42. retVal = invocation.proceed();
  43. }
  44. // Massage return value if necessary.
  45. if(retVal !=null&& retVal == target &&method.getReturnType().isInstance(proxy)
  46. &&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())){
  47. // Special case: it returned"this" and the return type of the method
  48. // is type-compatible. Notethat we can't help if the target sets
  49. // a reference to itself inanother returned object.
  50. retVal = proxy;
  51. }
  52. return retVal;
  53. }finally{
  54. if(target !=null&&!targetSource.isStatic()){
  55. // Must have come fromTargetSource.
  56. targetSource.releaseTarget(target);
  57. }
  58. if(setProxyContext){
  59. // Restore old proxy.
  60. AopContext.setCurrentProxy(oldProxy);
  61. }
  62. }
  63. }
 
主流程可以简述为:获取可以应用到此方法上的通知链(Interceptor Chain),如果有,则应用通知,并执行joinpoint; 如果没有,则直接反射执行joinpoint。而这里的关键是通知链是如何获取的以及它又是如何执行的
 

参考文章

Spring AOP 实现原理:http://blog.csdn.net/moreevan/article/details/11977115

Spring AOP 实现原理的更多相关文章

  1. 【Spring】Spring AOP实现原理

    Spring AOP实现原理 在之前的一文中介绍过Spring AOP的功能使用,但是没有深究AOP的实现原理,今天正好看到几篇好文,于是就自己整理了一下AOP实现的几种方式,同时把代理模式相关知识也 ...

  2. 何为代理?jdk动态代理与cglib代理、spring Aop代理原理浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  3. Spring Aop底层原理详解

    Spring Aop底层原理详解(来源于csdn:https://blog.csdn.net/baomw)

  4. spring AOP底层原理实现——jdk动态代理

    spring AOP底层原理实现——jdk动态代理

  5. Spring AOP底层原理

    ------------------siwuxie095                                 Spring AOP 底层原理         AOP 即 Aspect Or ...

  6. jdk动态代理与cglib代理、spring Aop代理原理-代理使用浅析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

  7. Spring框架系列(9) - Spring AOP实现原理详解之AOP切面的实现

    前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的.本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所 ...

  8. Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建

    上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor).本文在此基 ...

  9. Spring框架系列(11) - Spring AOP实现原理详解之Cglib代理实现

    我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理.@pdai Spring框架系列 ...

随机推荐

  1. 虚拟机下Linux系统安装vmtool工具

    1.启动此虚拟机2.用超级用户root登录3.登录成功后,Ctrl+Alt ,取出鼠标,点选菜单栏,虚拟机 →安装VMware工具 → Install4.待虚拟系统挂载了光盘后,弹出cdrom文件夹或 ...

  2. 使用 Linux 终端 SSH 登录 VPS

    Windows 中远程 SSH 登录 VPS 进行管理的利器是 PuTTY,但是 Linux 中就没必要用它了.Linux.Unix(包括 Mac iOS)都必然有内置的命令行终端,内建了 OpenS ...

  3. 【转】Android Interface的使用

    原文网址:http://www.3g-edu.org/Android_free/art115.htm Android应用程序采用Java语言编写,Java语法和C/C++有很大的相似性,但也有一些特别 ...

  4. RAC实例 表空间 维护

    先配置一下监听,这样我们就可以从客户端进行连接了. 我这里写了三种连接. 第一种是正常方式,一般都采用这种方式,后面的rac1和rac2 是方便测试.因为如果用第一种方式的话,客户端连哪个实例是随机的 ...

  5. Oracle查看和修改其最大的游标数

    原文 Oracle查看和修改其最大的游标数 以下的文章主要是介绍Oracle查看和修改其最大的游标数,本文主要是通过相关代码的方式来引出Oracle查看和修改其最大的游标数的实际操作步骤,以下就是文章 ...

  6. 【Mongo】MongoVUE的使用

    我一直是在终端操作的mongo,各种update set remove insert,后来查了下有个叫mongoVUE的客户端,界面化比较方便操作吧~ 网上搜了下,说MongoVUE已经n年没有更新了 ...

  7. 如何配置Drupal数据库信息?

    Drupal的数据库连接信息通过文件settings.php中的变量$databases设置.变量$databases是一个二维的数组,第一维称为key,第二维称为target.使用这种方式可以处理多 ...

  8. win8 VS控件信息

    <TextBlock x:Name="button_1" HorizontalAlignment="Center"  TextWrapping=" ...

  9. 《学习OpenCV》中求给定点位置公式

    假设有10个三维的点,使用数组存放它们有四种常见的形式: ①一个二维数组,数组的类型是CV32FC1,有n行,3列(n×3) ②类似①,也可以用一个3行n列(3×n)的二维数组 ③④用一个n行1列(n ...

  10. webstorm启动bug

    场景描述: win10系统下,webstorm(32位)经常遇到无法启动的情况. 解决方案: 重启电脑. 1.win10系统需要更新时,webstorm无法启动,此为win10 bug,重启时,系统自 ...