- 浏览: 462015 次
- 性别:
- 来自: 长沙
文章分类
- 全部博客 (132)
- Java (17)
- Eclipse (2)
- Struts2 (6)
- SWT (9)
- Java Web Start (2)
- Heritrix (4)
- Nutch (1)
- Internet (2)
- J2me (2)
- Windows (4)
- Swing (8)
- JavaScript (11)
- Hibernate (1)
- Spring (6)
- Mysql (9)
- Oracle (10)
- Linux (6)
- RESTful (3)
- XML (1)
- Flex (4)
- EL (1)
- Apache (4)
- VC (3)
- OpenSourceLicence (1)
- Tomcat (4)
- Tiles2 (1)
- nosql (6)
- else (4)
- Nginx (2)
最新评论
-
mzlogin:
然而并没有讲 hash 函数
深入理解HashMap(及hash函数的真正巧妙之处) -
czp11210:
hi,你这篇文章很好。有两个细节跟你确认下:1.你使用的amo ...
Mysql 基于 Amoeba 的 水平和垂直 分片 -
Mybeautiful:
It seems the amoeba doesn't sup ...
Mysql 基于 Amoeba 的 水平和垂直 分片 -
xs.cctv:
言简意赅。。。。。。
深入理解HashMap(及hash函数的真正巧妙之处) -
mnhkahn:
h & (length-1)这个其实还是一个模运算,只 ...
深入理解HashMap(及hash函数的真正巧妙之处)
在动态代理 和 CGLIB 的支持下, Spring AOP 框架的实现经过了两代。
从 Spring AOP 框架第一次发布,到 Spring 2.0 发布之前的 AOP 实现,是 Spring 第一代 AOP 实现。
Spring 2.0 发布后的 AOP 实现是第二代。
但是,Spring AOP 的底层实现机制一直没有变,唯一改变的,是各种 AOP 概念实现的表现形式以及 Spring AOP 的使用
方式。
Spring AOP 的底层实现机制
1. Spring AOP 中的 Joinpoint
Spring AOP 中,仅支持方法级别的 Joinpoint ,更确切的说,只支持方法执行 (Method Execution )类型的 Joinpoint
虽然 Spring AOP 仅提供方法拦截,但是实际的开发过程中,这已经可以满足 80% 的开发需求了。Spring AOP 之所以
如此,主要有以下几个原因。
a. Spring AOP 要提供一个简单而强大的 AOP 框架,并不想因大而全使得框架本身过于臃肿。能够仅付出 20% 的
努力,就能够得到 80% 的回报。否则,事倍功半,并不是想看到的结果。
b. 对于类中属性 (Field )级别的 Joinpoint ,如果提供这个级别的拦截,那么就破坏了面向对象的封装,而且,完全
可以通过 setter 和 getter 方法的拦截达到同样的目的。
c. 如果应用需求非常特殊,完全超出了 Spring AOP 提供的那 80% 的需求支持,可以求助于现有其他 AOP 实现产品,
如 AspectJ。 目前看来, AspectJ 是 Java 平台对 AOP 支持最完善的产品,同时,Spring AOP 也提供了对 Aspect
的支持。
2. Spring AOP 中的 Pointcut
Spring 中以接口 org.springframework.aop.Pointcut 作为其 AOP 框架中的所有 Pointcut 的最顶层抽象。
package org.springframework.aop; public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE; }
ClassFilter 和 MethodMatcher 分别用于匹配被执行织入操作的对象以及相应的方法。
a. ClassFilter
ClassFilter 接口的作用是对 Joinpoint 所处的对象进行 Class 级别的类型匹配。
package org.springframework.aop; public interface ClassFilter { boolean matches(Class<?> clazz); ClassFilter TRUE = TrueClassFilter.INSTANCE; }
当织入的目标对象的 Class 类型与 Pointcut 所规定的类型相符时,matchers 方法将会返回 true,否则返回 false。
即意味着不会对这个类型的目标对象进行织入操作。比如,如果仅希望对系统中的 Foo 类型的对象执行织入,则可以
package prx.aop.proxy; import org.springframework.aop.ClassFilter; public class FooClassFilter implements ClassFilter{ public boolean matches(Class<?> clazz) { return Foo.class.equals(clazz); } }
如果类型对所捕捉的 Joinpoint 无所谓,那么 Pointcut 中使用的 ClassFilter 可以直接使用
ClassFilter TRUE = TrueClassFilter.INSTANCE 。
当 Pointcut 中返回的 ClassFilter 类型为该类型实例时,Pointcut 的匹配将会针对系统中所有类的实例。
b. MethodMatcher
MethodMatcher 接口的作用是描述 Pointcut 中 Method Execution 的 Joinpoint 的集合。即对象中的方法是否匹配
该 Pointcut 的而需要拦截。也就是 Spring 主要支持的 方法级别的拦截 的依据。
package org.springframework.aop; import java.lang.reflect.Method; public interface MethodMatcher { boolean matches(Method method, Class<?> targetClass); boolean isRuntime(); boolean matches(Method method, Class<?> targetClass, Object[] args); MethodMatcher TRUE = TrueMethodMatcher.INSTANCE; }
MethodMatcher 通过重载,定义了两个 matches 方法,而这两个方法的分界线就是 isRuntime 方法。
两个 mathcers 方法的区别在于:
在进行方法拦截的时候,可以选择忽略方法执行时的传入参数,也可以每次都检查方法执行时的传入参数。
比如:现在要对 登录方法 login(String username, String passwod) 进行拦截
1. 只想在 login 方法之前插入计数功能,那么 login 方法的参数对于 Joinpoint 捕捉就是可以忽略的。
2. 在用户登录的时候对某个用户做单独处理(拒绝登录 或 给予特殊权限),那么方法的参数在匹配 Joinpoint 时必须要考虑到
(1). StaticMethodMatcher
前一种情况下, isRuntime 返回 false , 表示不会考虑具体 Joinpoint 的方法参数, 这种类型的 MethodMatcher
称之为 StaticMethodMatcher。因为不用每次都检查参数,那么对于同样的类型的方法匹配结果,就可以在框架内部
缓存以提高性能。isRuntime 方法返回 false 表明当前的 MethodMatcher 为 StaticMethodMatcher 的时候, 只有
boolean matches(Method method, Class<?> targetClass);
方法将被执行, 它的匹配结果将会成为其所属的 Pointcut 主要依据。
package org.springframework.aop.support; import java.lang.reflect.Method; import org.springframework.aop.MethodMatcher; public abstract class StaticMethodMatcher implements MethodMatcher { public final boolean isRuntime() { return false; } public final boolean matches(Method method, Class<?> targetClass, Object[] args) { // should never be invoked because isRuntime() returns false throw new UnsupportedOperationException("Illegal MethodMatcher usage"); } }
(2). DynamicMethodMatcher
当 isRuntime 方法返回 true 时, 表明 MethodMatcher 将会每次都对方法调用的参数进行匹配检查,这种类型的
MethodMatcher 称之为 DynamicMethodMatcher。 因为每次都要对方法参数进行检查,无法对匹配结果进行缓存,
所以,匹配效率相对 StatisMethodMatcher 来说要差。
大部分情况下, StaticMethodMatcher 已经够用了,最好避免使用 DynamicMethodMatcher 类型。
如果一个 MethodMatcher 为 DynamicMethodMatcher , 那么只有 isRuntime 返回 true, 而且
matchers(Method method, Class targetClass) 也返回 true 的时候, 三个参数的 matchers 方法将被执行,进行
进一步检查匹配条件。否则不会执行 三个参数的 matchers 方法,直接返回 false 了。
package org.springframework.aop.support; import java.lang.reflect.Method; import org.springframework.aop.MethodMatcher; public abstract class DynamicMethodMatcher implements MethodMatcher { public final boolean isRuntime() { return true; } /** * Can override to add preconditions for dynamic matching. This implementation * always returns true. */ public boolean matches(Method method, Class<?> targetClass) { return true; } }
在 MethodMatcher 类型的基础上, Pointcut 可以分为两类, 即 StaticMethodMatcherPointcut 和 DynamicMethodMatcherPointcut。
因为 StaticMethodMatcherPointcut 具有明显的性能优势, 所以, Spring 为其提供了更多的支持。
Spring 中 Pointcut 局部类结构图
部分资料说明 AbstractRegexpMethodPointcut 还有个 子类 Perl5RegexpMethodPointcut,但是我在
Spring 3.0.5 包中没有看到此类。
从上图中看出 Spring 提供了集中常见的 Pointcut 实现 (浅红色的类图 )。
1. NameMatchMethodPointcut
最简单的 Pointcut 实现,根据自身指定的一组方法名称与 Joinpoint 处的方法的名称进行匹配,支持“*”通配符实现简单
的模糊匹配。
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); pointcut.setMappedName("methodName"); pointcut.setMappedNames(new String[]{"methodName1", "methodName2"}); pointcut.setMappedNames(new String[]{"method*", "*Name", "method*Num"});
但是, NameMatchMethodPointcut 无法对重载的方法名进行匹配, 因为它仅对方法名匹配,不考虑参数信息。
2. JdkRegexpMethodPointcut
StaticMethodMatcherPointcut 中正则表达式的分支实现,基于 JDK1.4 之后引入的 JDK 标准正则表达式。
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut(); pointcut.setPattern(".*method.*"); pointcut.setPatterns(new String[]{".*method.*", ".*name.*"});
注意:使用正则表达式来匹配对应的 Joinpoint 所处的方法时, 正则表达式的匹配模式必须以匹配整个方法签名的形式
指定,而不能像 NameMatchMethodPointcut 那样仅给出匹配的方法名称。
package prx.aop.proxy; public class Foo { public void doSomething() { } }
如果使用正则表达式 .*doS.* 则会匹配 Foo 的 doSomething 方法, 即完整签名:
prx.aop.proxy.Foo.doSomething 。 但是如果 Pointcut 使用 doS.* 作为匹配的正则表达式模式,就无法捕捉到
Foo 的 doSomething 方法的执行。
3. AnnotationMatchingPointcut
根据目标对象中是否存在指定类型的注解来匹配 Joinpoint , 只能使用在 JDK5 或更高版本中, 因为注解是 JDK5
发布后才有的。
AnnotationMatchingPointcut 根据目标对象中是否存在指定类型的注解来匹配 Joinpoint ,要使用该类型的 Pointcut
首先需要声明相应的注解。
例如:
package prx.aop.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface ClassLevelAnnotation { }
package prx.aop.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MethodLevelAnnotation { }
注解定义中的 @Target 指定注解可以标注的类型。 ClassLevelAnnotation用于类层次,MethodLevelAnnotation
用于方法层次。
不同的 AnnotationMatchingPointcut 的定义方式会产生不同的匹配行为。
//仅指定类级别的注解, 标注了 ClassLevelAnnotation 注解的类中的所有方法执行的时候,将全部匹配。 AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(ClassLevelAnnotation.class); //还可以使用静态方法创建 pointcut 实例 AnnotationMatchingPointcut pointcut = AnnotationMatchingPointcut.forClassAnnotation(ClassLevelAnnotation.class); //仅指定方法级别的注解,标注了 MethodLeavelAnnotaion 注解的方法(忽略类匹配)都将匹配 AnnotationMatchingPointcut pointcut = AnnotationMatchingPointcut.forMethodAnnotation(MethodLevelAnnotation.class); //同时限定类级别和方法级别的注解,只有标注了 ClassLevelAnnotation 的类中 同时标注了 MethodLevelAnnotation 的方法才会匹配 AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(ClassLevelAnnotation.class, MethodLevelAnnotation.class);
讲了这么多,比较空泛了, 来个简单的实际例子看下: (注解的定义延用上面的代码)
package prx.aop.annotation; @ClassLevelAnnotation public class TargetObject { @MethodLevelAnnotation public void method1() { System.out.println("target : method1"); } public void method2() { System.out.println("target : method2"); } }
package prx.aop.annotation; import java.lang.reflect.Method; import org.springframework.aop.BeforeAdvice; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; public class Client { public static void main(String[] args) { //pointcut 定义, 匹配方式可以按上面的说明修改, 这里是注解类的所有方法都匹配 AnnotationMatchingPointcut pointcut = AnnotationMatchingPointcut.forClassAnnotation(ClassLevelAnnotation.class); // advice 定义, 根据前面的介绍知道 这个是 横切逻辑的定义, 这里是 方法执行前插入横切逻辑 BeforeAdvice advice = new MethodBeforeAdvice() { public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getSimpleName() + ":" + method.getName() + " - before logic "); } }; // Spring 中的 Aspect , pointcut 和 advice 的封装类 DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); advisor.setPointcut(pointcut); advisor.setAdvice(advice); // Spring 基本织入器 weaving 和 weaver ProxyFactory weaver = new ProxyFactory(); weaver.setTarget(new TargetObject()); //指定代理目标对象 weaver.addAdvisor(advisor); //指定 Aspect Object proxyObject = weaver.getProxy(); //生成代理对象 (这里没接口, Spring 使用 CGLIB 创建子类) ((TargetObject) proxyObject).method1(); ((TargetObject) proxyObject).method2(); } }
4. ComposablePointcut
ComposablePointcut 是 Spring AOP 提供的可以进行 Pointcut 逻辑运算的 Pointcut 实现, 它可以进行 Pointcut
之间的 “并” 以及 “交” 运算。
ComposablePointcut pointcut1 = new ComposablePointcut(classFilter1, methodMatcher1); ComposablePointcut pointcut2 = new ComposablePointcut(classFilter2, methodMatcher2); //求并集 ComposablePointcut unitedPointcut = pointcut1.union(pointcut2); //求交集 ComposablePointcut intersectionPointcut = pointcut1.intersection(unitedPointcut); assertEquals(pointcut1, intersectionPointcut);
同时, Spring AOP 还提供了 工具类: org.springframework.aop.support.Pointcuts
Pointcut pointcut1 = ...; Pointcut pointcut2 = ...; //求并集 Pointcut unitedPointcut = Pointcuts.union(pointcut1, pointcut2); //求交集 Pointcut intersectionPointcut = Pointcuts.intersection(pointcut1, unitedPointcut); assertEquals(pointcut1, intersectionPointcut);
5. ControlFlowPointcut
非常有个性的 Pointcut 类型, 不是很常用。 指定只有当 Joinpoint 指定的某个方法 在 某个特定的 类中被调用时,才
对其进行拦截。而一般情况是,Joinpoint 指定的方法,无论被谁调用,都会被拦截。
package prx.aop.controlflow; public class TargetObject { public void method1() { System.out.println("TargetObject : method1"); } }
package prx.aop.controlflow; public class TargetCaller { private TargetObject target; public void callMethod() { target.method1(); } public void setTarget(TargetObject target) { this.target = target; } }
package prx.aop.controlflow; import java.lang.reflect.Method; import org.springframework.aop.BeforeAdvice; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.ControlFlowPointcut; import org.springframework.aop.support.DefaultPointcutAdvisor; public class Client { public static void main(String[] args) { //该 Pointcut 表示 Joinpoint 指定的方法 只有在 TargetCaller 类中被调用,才能拦截织入横切逻辑 ControlFlowPointcut pointcut = new ControlFlowPointcut(TargetCaller.class); // advice 定义, 根据前面的介绍知道 这个是 横切逻辑的定义, 这里是 方法执行前插入横切逻辑 BeforeAdvice advice = new MethodBeforeAdvice() { public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getSimpleName() + ":" + method.getName() + " - before logic "); } }; // Spring 中的 Aspect , pointcut 和 advice 的封装类 DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); advisor.setPointcut(pointcut); advisor.setAdvice(advice); // Spring 基本织入器 weaving 和 weaver ProxyFactory weaver = new ProxyFactory(); weaver.setTarget(new TargetObject()); //指定代理目标对象 weaver.addAdvisor(advisor); //指定 Aspect Object proxyObject = weaver.getProxy(); //生成代理对象 (这里没接口, Spring 使用 CGLIB 创建子类) //直接调用 method1 不会触发横切逻辑执行 ((TargetObject) proxyObject).method1(); System.out.println("-----------------"); //advice的逻辑在这里才能被触发执行 //因为 TargetCaller 的 callMethod() 将调用 method1 TargetCaller caller = new TargetCaller(); caller.setTarget((TargetObject)proxyObject); caller.callMethod(); } }
如果在 ControlFlowPointcut 的构造方法中单独指定 Class 类型的参数,如上面的例子,那么 ControlFlowPointcut
将尝试匹配指定的 Class 中声明的所有方法,跟目标对象的 Joinpoint 处的方法流程组合。 所以,如果是想要做到
“只有 TargetCaller 类的 callMethod 方法调用 TargetObject.method1() 才拦截,而 TargetCaller 的其他方法
全都忽略” 的话,可以在构造时,传入第二个参数
ControlFlowPointcut pointcut = new ControlFlowPointcut(TargetCaller.class, "callMethod");
因为 ControlFlowPointcut 类型的 Pointcut 需要在运行期间检查程序的调用栈,而且每次方法调用都需要检查,所以
性能比较差,应该尽量避免使用。
太长了。。。下回待续。O(∩_∩)O~
发表评论
-
Spring AOP 剖析(7)
2012-08-23 17:11 0Spring AOP 的底层实现机制 ... -
Spring AOP 剖析(6)
2012-08-23 10:44 2357Spring AOP 的底层实现机制 ... -
Spring AOP 剖析(4)
2012-08-10 14:44 1396Spring AOP 的实现机制 S ... -
Spring AOP 剖析(3)
2012-08-08 11:19 1935AOP 涉及到的几个基本概念 1. Jo ... -
Spring AOP 剖析(2)
2012-08-06 12:15 1488Java 平台上 AOP 的实现机 ... -
Spring AOP 剖析(1)
2012-08-06 12:14 1346软件开发的目的,最终是为了解决各种需求,包括业务需求和系统需求 ...
相关推荐
Spring AOP 是一种面向切面编程的技术,它允许我们在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行增强。在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态...
AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析...
**Spring AOP 实现机制详解** Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的...
《Spring AOP 源码分析》 在深入探讨Spring AOP之前,我们先要理解AOP(面向切面编程)的基本概念。AOP是一种编程范式,它将关注点分离,使得我们可以将横切关注点(如日志、事务管理、安全检查等)与业务逻辑解耦...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和抽象化的方法来处理系统中的交叉关注点,如日志、事务管理、安全性等。本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际...
在本文中,我们将从实现的角度来认识 SpringAOP 框架,从外部接口、内部实现、组成部分、执行过程四个方面来介绍 Spring AOP 框架的结构分析。 最后,本文的目标是从实现的角度来认识 SpringAOP 框架,观察的角度是...
**Spring AOP 简介** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个重要模块,它扩展了传统的面向对象编程,允许开发者定义“横切关注点”(cross-cutting concerns),如日志、事务...
在IT领域,Spring框架是一个广泛使用的Java应用框架,它提供了许多功能,包括依赖注入、面向切面编程(AOP)等。"spring-aop-jar"这个主题涉及到Spring框架中的核心组件之一——Spring AOP。这里我们将深入探讨...
在本文中,我们将深入探讨Spring AOP的运用,并结合源码分析其工作原理。 首先,了解AOP的基本概念: 1. 切面(Aspect):切面是关注点的模块化,这些关注点通常是跨越多个对象的横切关注点,例如事务管理、日志...
Spring AOP,全称Aspect-Oriented Programming,是Spring框架中的一个重要组成部分,它引入了面向切面编程的概念,使得开发者可以将关注点分离,更好地实现业务逻辑与系统服务的解耦。在这个经典例子中,我们将深入...
通过分析这个测试案例,你可以了解如何在实际项目中实现AOP。例如,它可能包含了一个带有切面逻辑的切面类,使用了`@Before`注解的方法会在目标方法执行前运行,而使用`@After`注解的方法则会在目标方法执行后运行。...
本篇文章将深入探讨如何使用Spring AOP实现性能监控器,并通过源码分析来理解其工作原理。 首先,我们要了解AOP的核心概念——切面(Aspect)、通知(Advice)、连接点(Join Point)、切入点(Pointcut)和织入...
**Spring AOP 使用实例** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个重要组成部分,它提供了一种在不修改原有代码的情况下,通过代理方式添加额外功能的技术。这种技术使得我们...
在提供的压缩包文件"springAOP"中,可能包含了以下内容: - **切面类(Aspect Class)**:包含切点和通知的Java类,可能使用了`@Aspect`注解。 - **目标类(Target Class)**:被AOP代理的对象,通常包含业务逻辑。...
Spring AOP(面向切面编程)是Spring框架的一个重要组成部分,它允许开发者将横切关注点与业务逻辑分离,实现业务逻辑的模块化。AOP核心组件包括几个关键概念,如切面(Aspect)、通知(Advice)、连接点(Joinpoint...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理、性能监控等。在Java应用中,AOP通过代理模式实现,使得我们可以将横切关注...
**Spring AOP 实现详解** 在Java开发中,Spring框架以其强大的功能和灵活性深受开发者喜爱。其中,AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架的一个重要特性,它允许开发者将关注点从核心业务...
Spring AOP 源码分析笔记 Spring AOP(Aspect-Oriented Programming)是一种编程范式,它允许开发者 modularize cross-cutting concerns,即将横切关注点模块化。AOP 使得开发者可以将一些公共的功能模块化,以便在...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理、性能监控等。AOP的核心概念包括切面(Aspect)、通知(Advice)、连接点...