`
凤凰山
  • 浏览: 147602 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

Spring AOP框架实现的结构分析

 
阅读更多

本文的目标:

从实现的角度来认识SpringAOP框架。

观察的角度:

从外部接口,内部实现,组成部分,执行过程四个方面来认识SpringAOP框架。

本文的风格:

首先列出AOP的基本概念;

其次介绍框架所涉及到的核心组件列表,组件之间的结构关系图;

然后细化结构图中的部分;

接下来是一个简单的sample;

最后是后记部分。

注:

1.本文的源代码基于Spring2.x。Spring的源代码也处于演变中,但对基础代码的影响并不大。

2.本文是对Spring IoC容器实现的结构分析的姊妹帖。

正文:

Spring AOP框架涉及的基本概念介绍:

关注点(concern):一个关注点可以是一个特定的问题、概念、或是应用程序的兴趣区间--总而言之,应用程序必须达到的一个目标。

核心关注点(core concern):业务功能模块,如:存款模块,取款模块,转账模块等,

横切关注点(crosscutting concern):非功能性的、横切性模块,如:安全性管理,事务管理,性能监控等。

方面(aspect):一个方面是对一个横切关注点的模块化,它将那些原本散落在各处的、用于实现这个关注点的代码归整到一处。

连接点(join point):程序执行过程中的一点,如:

字段访问:读、写实例变量;

方法调用:对方法(包括构造方法)的调用;

异常抛出:特定的异常被抛出。

切入点(pointcut):一组连接点的总称,用于指定某个增强应该在何时被调用。切入点常用正则表达式或别的通配符语法来描述,有些AOP实现技术还支持切入点的组合。

增强(advice):在特定连接点执行的动作。很多AOP框架都以拦截器(interceptor)的形式来表现增强--所谓拦截器是这样的一个

对象:当连接点被调用时,它会收到一个回调消息。基本的增强有:

前增强(BeforeAdvice):在连接点调用之前,首先调用增强;

后增强(AfterAdvice):在连接点调用之后,再调用增强,在AspectJ中,后增强又分为三种:

AfterReturningAdvice:在调用成功完成(没有异常抛出)之后。

AfterThrowingAdvice:在抛出某种特定类型(或其子类型)的异常之后。

AfterAdvice:在连接点的任何调用之后,不管调用是否抛出异常。

环绕增强(AroundAdvice):这类增强可以完全控制执行流程。除了完成本身的工作之外,它还需要负责主动调用连接点,促使真实的操作发生(proceed)-- 这通常是通过调用某个特定的方法来完成的。

引介(introduction):为一个现有的Java类或接口添加方法或字段。这种技术可以用于实现Java中的多继承,或者给现有对象模型附加新的API。

混入继承(mixin inheritance):一个“混入类”封装了一组功能,这组功能可以被"混入"到现有的类当中,并且无须使用传统的继承手段。在AOP这里,混入是通过引介来实现的。在Java语言中,可以通过混入来模拟多继承。

织入(weaving):将方面整合到完整的执行流程(或完整的类,此时被织入的便是引介中)。

拦截器(initerceptor):很多AOP框架用它来实现字段和方法的拦截(interception)。随之而来的就是在连接点(如方法拦截)处挂接一条拦截器链(interceptor chain),链条上的每个拦截器通常会调用下一个拦截器。

AOP代理(AOP proxy):即被增强(advise)的对象引用--也就是说,AOP增强将在其上执行的这样一个对象引用。

目标对象(target object):位于拦截器链末端的对象实例--这个概念只存在于那些使用了拦截机制的框架之中。

注:上述概念描述引自《Expert One-on-One J2EE Development without EJB》中第八章对AOP概念描述部分,更多精彩部分可以参阅本章的完整内容。

上述概念已被Spring AOP框架很好的实现,相关组件:

Advisor 组件,

Advice 组件,

Pointcut 组件,

Advised 组件,

AopProxy 组件,

AopProxyFactory 组件,

图1.

 

 

图1是对增强、切入点、方面、AOP代理之间依赖关系的全景图。

增强和切入点组成一个方面,方面信息与目标对象信息被组织到Advised中,AopProxyFactory通过Advised中保存的信息生成AopProxy

对象,调用AopProxy.getProxy()方法即可获得增强后的对象。

这里要着重了解的是不同的增强子类型,不同的切入点子类型,

对于不同的切入点子类型最重要的两种子类型:静态切入点,动态切入点,

静态切入点:根据部署阶段的信息选择增强,如“拦截特定类的所有getter方法”;

动态切入点:根据运行时的信息选择增强,如“如果某方法的返回值为null,则将其纳入某切入点”。

图2.

 

 

图2是对图1中Advisor与Pointcut的实现细化,图中类之间的关系直观上有点乱,但细看下关系还是相当清晰的,

以Advisor结尾的是方面类型,以Pointcut结尾的是切入点类型,

Advisor与Pointcut的复用关系分两类:一类是组合复用,另一类是具体继承复用,

组合复用例子 如:RegexpMethodPointcutAdvisor 与 AbstractRegexpMethodPointcut之间的关系,

NameMatchMethodPointcutAdvisor 与 NameMatchMethodPointcut之间的关系,

具体继承复用例子 如:StaticMethodMatcherPointcutAdvisor 与 StaticMethodMatcherPointcut 之间的关系,

DynamicMethodMatcherPointcutAdvisor 与 DynamicMethodMatcherPointcut 之间的关系,

图3.

 

 

图3是对图1中生成AopProxy对象的实现细化,

AopProxyFactory通过AdvisedSupport提供的信息生成AopProxy对象,AopProxy对象的生成分两类方式:一类是动态代理,另一类是字节码增强;

需要注意的是,ProxyFactory与ProxyFactoryBean并不是功能实现的必要部分,主要目的为编程式使用代理提供便利的API。

 

下面是一个简单的sample:

//目标对象接口.  
public interface Target {  
    public String play(int arg);  
}  
//目标对象实现.  
public class TargetImpl implements Target {  
 
    public String play(int arg) {  
         System.out.println("play method....");  
        return "[Target:]" + arg;  
    }  
}  
//前置增强  
public class MyBeforeAdvice implements MethodBeforeAdvice {  
    public void before(Method method, Object[] args, Object target)  
            throws Throwable {  
         System.out.println(method.getName());  
         System.out.println("before method!");  
    }  
}  
//后置增强  
public class MyAfterAdvice implements AfterReturningAdvice {  
    public void afterReturning(Object returnValue, Method method,  
            Object[] args, Object target) throws Throwable {  
         System.out.println(returnValue + ":after method");   
    }  
}  
//切入点实现  
public class MyPointcut implements Pointcut {  
 
    public ClassFilter getClassFilter() {  
           
        return new ClassFilter() {  
 
            public boolean matches(Class arg0) {  
                if (arg0 == TargetImpl.class) {  
                    return true;  
                }  
                return false;  
            }  
              
        };  
    }  
 
    public MethodMatcher getMethodMatcher() {  
           
        return new MethodMatcher() {  
 
            public boolean isRuntime() {  
                   
                return false;  
            }  
 
            public boolean matches(Method arg0, Class arg1) {  
                  
                if ("play".equals(arg0.getName())) {  
                    return true;  
                }  
                return false;  
            }  
 
            public boolean matches(Method arg0, Class arg1, Object[] arg2) {  
                System.out.println("aaaaaa");  
                if ("play".equals(arg0.getName())) {  
                    return true;  
                }  
                return false;  
            }  
              
        };  
    }  
 
}  
public class Main {  
    public static void main(String[] args) {  
         Target target = new TargetImpl();   //目标对象  
         Advice beforeAdvice = new MyBeforeAdvice(); //增强  
         Pointcut pointcut = new MyPointcut(); //切入点  
         DefaultPointcutAdvisor dda = new DefaultPointcutAdvisor(); //切面  
         dda.setAdvice(beforeAdvice);  
         dda.setPointcut(pointcut);  
           
         AdvisedSupport advisedSupport = new AdvisedSupport(); //提供基本的编程方式,  
         advisedSupport.addAdvisor(dda);  
         advisedSupport.addAdvice(new MyAfterAdvice());  
         advisedSupport.addInterface(Target.class);  
         advisedSupport.setTarget(target);  
         AopProxy aopProxy = new DefaultAopProxyFactory().createAopProxy(advisedSupport);  
         Target proxy = (Target)aopProxy.getProxy();  
         System.out.println(proxy.play(200));  
           
         ProxyFactory proxyFactory = new ProxyFactory();  //提供便利的编程方式.  
         proxyFactory.addAdvisor(dda);  
         proxyFactory.addInterface(Target.class);  
         proxyFactory.setTarget(target);  
         Target proxy2 = (Target)proxyFactory.getProxy();  
         System.out.println(proxy2.play(201));  
           
         ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); //提供便利的配置方式  
         proxyFactoryBean.addAdvisor(dda);  
         proxyFactoryBean.addInterface(Target.class);  
         proxyFactoryBean.setTarget(target);  
         Target proxy3 = (Target)proxyFactoryBean.getObject();  
         System.out.println(proxy3.play(232));  
    }  
} 

注:此处为了简单忽略了一些概念描述:

1.对引介,混入继承没有涉及。

2.对通知链的管理,如:同一切入点多个通知对象之间的执行顺序问题;

3.上述的描述是Spring AOP框架本身,所提供的使用方式是编程式,这种使用方式太过于低级,以至于我们在九成的情况下不会使用到,主流的使用方式是配置化的声明式使用方式,将AOP与IoC结合起来使用才能发挥出最大威力,ProxyFactoryBean提供了有限的声明式使用方式,但严格来说它仍是编程式,因为ProxyFactoryBean是一个FactoryBean,一个FactoryBean的目标就是以编程式替换复杂的配置式,而且最重要的是它暴露的API太过低级,配置文件中bean元素的abstract属性对配置文件的长度提供有限的帮助,自动代DefaultAdvisorAutoProxyCreator很好的隐藏了低级的API,DefaultAdvisorAutoProxyCreator是一个BeanPostProcessor,用于完成AOP框架与IoC容器的集成工作,但是这种方式依然没有解决需要同XXXAdvisor这样的低级API打交道的问题;

随着spring2.x引入的xml元素及@Aspect注解的AspectJ描述性风格的出现,使用Spring AOP框架的使用达到完全的声明式标准,这种风格也使得Spring 事务框架受益,从TransactionProxyFactoryBean类到xml元素、

 

及@Transactional注解,

原文:http://www.iteye.com/topic/1114645

 

使得我们只需关注高层描述,而无需涉及低级API。

附上DefaultAdvisorAutoProxyCreator的类结构图:

 

 

总结:

要全面理解AOP相关概念,回答下述问题是必须的。

1。AOP概念产生的背景,AOP所要解决的问题,AOP所涉及的概念,

2。实现一个AOP框架所需要注意的问题是什么,

3。不同AOP框架实现之间的比较,

4。AOP的一些副作用讨论。

 

作者: H_eaven H_eaven 

分享到:
评论

相关推荐

    spring-aop AND proxy

    综上所述,Spring AOP是Spring框架的重要组成部分,它通过代理技术实现切面编程,简化了代码结构,提高了代码的可复用性和可维护性。了解和掌握Spring AOP的原理和使用方法,对于开发高效、整洁的Java企业级应用至关...

    Java spring AOP源码

    Spring框架提供了一种强大的AOP实现方式,支持声明式的AOP,并且与Spring容器紧密结合。 #### 关键知识点解析 **1. **Spring AOP对于最外层函数的拦截范围** Spring AOP对于最外层的函数只拦截`public`方法,不...

    spring-aop.pdf 源码电子书

    Spring AOP(Aspect-Oriented Programming)是Spring框架的一个重要组成部分,它支持面向切面编程的实践,是为了解决面向对象编程中的横切关注点问题而设计的。在理解该电子书涉及的知识点之前,我们需要先了解...

    SpringAOP测试Demo

    在"SpringAOP测试Demo"中,我们通常会涉及以下几个核心概念和操作: 1. **切面(Aspect)**:切面是关注点的一个模块化,它包括了连接点、通知、目标对象、织入和引入。在Spring AOP中,切面通常由一个或多个注解的...

    spring5框架学习笔记

    本笔记主要介绍了 Spring 5 框架的相关知识点,包括 IoC 原理分析、基于 XML 的 IoC 实现、基于 XML 的 DI 使用、基于注解的 IoC 实现、Spring 纯注解实现方式、Spring 整合 Junit、Spring 分模块开发、Spring AOP ...

    Java进阶之SpringAOP源码深度剖析共17页.pd

    总的来说,这份17页的PDF文档将带领读者深入Spring AOP的内部世界,揭示其工作原理,帮助Java开发者提升在实际项目中运用Spring AOP的能力,实现更加高效和优雅的代码结构。无论是对Spring框架的爱好者还是寻求技术...

    swagger和spring Aop日志结合

    另一方面,Spring AOP(面向切面编程)则是Spring框架的一个核心特性,用于实现跨切面的关注点,如日志记录。本篇文章将深入探讨如何将Swagger与Spring AOP结合起来,以实现优雅的日志记录功能。 首先,让我们了解...

    springAOP详解

    Spring AOP 正是利用了这一特性来实现在运行时动态地将切面代码织入到目标对象中。 #### 5.2 从一个输出日志的实例分析 Java 的代理机制 **5.2.1 通用的日志输出方法** 在使用 Spring 之前,开发者可能需要手动在...

    spring aop配置常用jar包

    Spring AOP和其他AOP框架如AspectJ都实现了这些接口,从而可以方便地混合使用。 4. **cglib-2-2.jar**:这是Code Generation Library的简称,它是一个强大的字节码处理库,常被用来动态生成子类,以实现对非接口类...

    Spring mvc mybatis plus 实现AOP 切面日志系统

    本项目“Spring MVC Mybatis Plus 实现AOP 切面日志系统”旨在提供一个基础的日志记录框架,能够自动追踪和记录应用程序的关键操作,同时支持数据持久化到数据库中,方便后期分析和问题排查。下面将详细介绍这些技术...

    Spring AOP的概要解析与逻辑设计

    Spring AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的一个重要组成部分,它为开发者提供了一种管理横切关注点的有效方式。在Java应用程序中,横切关注点通常指的是那些跨越多个对象、模块的...

    Spring之AOP注解之引入通知

    在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员将关注点分离,例如日志记录、事务管理等,从核心业务逻辑中解耦出来。本篇文章将深入探讨Spring AOP中的注解引入通知,以及如何利用它们来增强...

    java面试难点讲解:hashmap,spring aop,classload,dubbo,zookeeper,session等。

    面试必考之HashMap源码分析与实现 探索JVM底层奥秘ClassLoader源码分析与案例讲解 面试必备技能之Dubbo企业实战 分布式框架Zookeeper之服务注册与订阅 互联网系统垂直架构之...无处不在的Spring AOP事务及踩过的坑

    spring aop

    标题 "spring aop" 涉及的是Spring框架中的一个重要概念——面向切面编程(Aspect Oriented Programming,简称AOP)。在Spring框架中,AOP主要用于处理系统中的横切关注点,比如日志记录、事务管理、性能监控等,...

    7Spring AOP盗梦空间之二——获得返回值AfterReturnning

    在本篇博文中,我们将深入探讨Spring AOP(面向切面编程)中的一个重要概念——AfterReturning通知,这是Spring框架提供的一种强大的功能,允许我们在方法成功执行并返回后执行额外的操作。我们将通过源码分析和实际...

    spring_aop麻雀

    本项目“spring_aop麻雀”显然旨在展示如何在小型项目中整合Spring的AOP功能与Hibernate ORM框架,实现数据持久化。尽管项目规模不大,但涵盖了核心的功能模块,让我们逐一解析这些知识点。 1. **Spring AOP**:AOP...

    spring2-aop.pdf

    Spring中的AOP实现是本章的另一个重点,Spring提供了自己的AOP框架,它与AspectJ紧密集成,并提供了一套基于Spring的AOP配置方法。这些方法包括使用XML配置文件、使用Java注解以及通过编程方式使用AOP。SpringAOP的...

Global site tag (gtag.js) - Google Analytics