增强被织入到目标类的所有方法中,但是如果需要有选择性的织入到目标类某些特定的方法中时,就需要使用切点进行目标连接点的定位。增强提供了连接点方位信息:如织入到方法前面、后面等,而切点进一步描述织入到哪些类的哪些方法上。Spring通过org.springframework.aop.Pointcut接口描述切点,Pointcut由ClassFilter和MethodMatcher构成,它通过ClassFilter定位到某些特定类上,通过MethodMatcher定位到特定方法上。这样Pointcut就拥有了描述某些类的某些特定方法的能力。
    Spring支持两种方法匹配器:静态方法匹配器和动态方法匹配器。静态方法匹配器,它仅对方法名签名(包括方法名和入参类型及顺序)进行匹配;而动态方法匹配器,会在运行期检查方法入参的值。静态匹配仅会判别一次;而动态匹配因为每次调用方法的入参都可能不一样,所以每次调用方法都必须判断。因此,动态匹配对性能的影响很大。
 

1、切点类型

    1)静态方法切点:org.springframework.aop.support.StaticMethodMatcherPointcut是静态方法切点的抽象基类,默认情况下它匹配所有的类。StaticMethodMatcherPointcut包括两个主要的子类,分别是NameMatchMethodPointcut和AbstractRegexpMethodPointcut,前者提供简单字符串匹配方法签名,而后者使用正则表达式匹配方法签名。
    2)动态方法切点:org.springframework.aop.support.DynamicMethodMatcherPointcut 是动态方法切点的抽象基类,默认情况下它匹配所有的类。DynamicMethodMatcherPointcut类已经过时,可以使用DefaultPointcutAdvisor 和DynamicMethodMatcherPointcut动态方法匹配器替代之。
    3)注解切点:org.springframework.aop.support.AnnotationMatchingPointcut实现类表示注解切点。使用AnnotationMatchingPointcut支持在Bean中直接通过JDK5.0注解标签定义的切点。
    4)表达式切点:org.springframework.aop.support.ExpressionPointcut接口主要是为了支持AspectJ切点表达式语法而定义的接口。
    5)流程切点:org.springframework.aop.support.ControlFlowPointcut实现类表示控制流程切点。ControlFlowPointcut是一种特殊的切点,它根据程序执行堆栈的信息查看目标方法是否由某一个方法直接或间接发起调用,以此判断是否为匹配的连接点。
    6)复合切点:org.springframework.aop.suppot.ComposablePointcut实现类是为创建多个切点而提供的方便操作类。它所有的方法都返回ComposablePointcut类,这样,我们就可以使用连接表达式对切点进行操作。
 
2、切面类型
    Spring使用org.springframework.aop.Advisor接口表示切面的概念,一个切面同时包含横切代码和连接点信息。切面可以分为三类:一般切面、切点切面和引介切面。
    1)Advisor:代表一般切面,它仅包含一个Advice。由于Advice包含了横切代码和连接点的信息,所以Advice本身就是一个简单的切面,只不过它代表的横切的连接点是所有目标类的所有方法,因为这个横切面太宽泛,所以一般不会直接使用。
    2)PointcutAdvisor:代表具有切点的切面,它包含Advice和Pointcut两个类,这样,我们就可以通过类、方法名以及方法方位等信息灵活地定义切面的连接点,提供更具适用性的切面。
    3)IntroductionAdvisor:代表引介切面,引介切面是对应引介增强的特殊的切面,它应用于类层面上,所以引介切面适用ClassFilter进行定义。
 
    PointcutAdvisor主要有6个具体的实现类:    
    1)DefaultPointcutAdvisor:最常用的切面类型,它可以通过任意Pointcut和Advice定义一个切面,唯一不支持的是引介的切面类型,一般可以通过扩展该类实现自定义的切面。
    2)NameMatchMethodPointcutAdvisor:通过该类可以定义按方法名定义切点的切面。
    3)RegexpMethodPointcutAdvisor:允许用户以正则表达式模式串定义方法匹配的切点。
    4)StaticMethodMatcherPointcutAdvisor:静态方法匹配器切点定义的切面,默认情况下,匹配所有的目标类。
    5)AspectJExpressionPointcutAdvisor:用于AspectJ切点表达式定义切点的切面,它是Spring 2.0 新提供的类。
    6)AspectJPointcutAdvisor:用于AspectJ语法定义切点的切面,它也是Spring 2.0 新提供的类。
 
3、静态普通方法名匹配切面
    StaticMethodMatcherPointcutAdvisor 代表一个静态方法匹配切面,它通过 StaticMethodMatcherPointcut 定义切点,通过类过滤器和方法名匹配定义切点。
Waiter业务类:

  1. package com.yyq.aop;
  2. public class Waiter {
  3. public void greetTo(String name) {
  4. System.out.println("waiter greet to " + name + ".");
  5. }
  6. public void serveTo(String name) {
  7. System.out.println("waiter serving to " + name + ".");
  8. }
  9. }

Seller业务类:

  1. package com.yyq.aop;
  2. public class Seller {
  3. public void greetTo(String name) {
  4. System.out.println("seller greet to " + name + ".");
  5. }
  6. }

GreetingAdvisor切面实现类:

  1. package com.yyq.aop;
  2. import org.springframework.aop.ClassFilter;
  3. import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
  4. import java.lang.reflect.Method;
  5. public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {
  6. @Override
  7. public boolean matches(Method method, Class<?> aClass) {
  8. return "greetTo".equals(method.getName());
  9. }
  10. public ClassFilter getClassFilter() {
  11. return new ClassFilter() {
  12. @Override
  13. public boolean matches(Class<?> aClass) {
  14. return Waiter.class.isAssignableFrom(aClass);
  15. }
  16. };
  17. }
  18. }

GreetingBeforeAdvice前置增强实现类:

  1. package com.yyq.aop;
  2. import org.springframework.aop.MethodBeforeAdvice;
  3. import java.lang.reflect.Method;
  4. public class GreetingBeforeAdvice implements MethodBeforeAdvice {
  5. @Override
  6. public void before(Method method, Object[] objects, Object o) throws Throwable {
  7. System.out.println(o.getClass().getName() + "." + method.getName());
  8. String clientName = (String) objects[0];
  9. System.out.println("Hi! Mr." + clientName + ".");
  10. }
  11. }

配置切面:静态方法配置切面

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:p="http://www.springframework.org/schema/p"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  7. <bean id="waiterTarget" class="com.yyq.aop.Waiter"/>
  8. <bean id="sellerTarget" class="com.yyq.aop.Seller"/>
  9. <bean id="greetingAdvice" class="com.yyq.aop.GreetingBeforeAdvice"/>
  10. <bean id="greetingAdvisor" class="com.yyq.aop.GreetingAdvisor" p:advice-ref="greetingAdvice"/>
  11.  
  12. <bean id="parent" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean"
  13. p:interceptorNames="greetingAdvisor"
  14. p:proxyTargetClass="true"/>
  15. <bean id="waiter" parent="parent" p:target-ref="waiterTarget"/>
  16. <bean id="seller" parent="parent" p:target-ref="sellerTarget"/>
  17. </beans>

测试方法:

  1. @Test
  2. public void testAdvisor(){
  3. String configPath = "com\\yyq\\aop\\beans.xml";
  4. ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
  5. Waiter waiter = (Waiter)ctx.getBean("waiter");
  6. Seller seller = (Seller)ctx.getBean("seller");
  7. waiter.greetTo("John");
  8. waiter.serveTo("John");
  9. seller.greetTo("John");
  10. }
结果输出:
com.yyq.aop.Waiter.greetTo
Hi! Mr.John.
waiter greet to John.
waiter serving to John.
seller greet to John.
 
4、静态正则表达式方法匹配切面
    使用正则表达式进行匹配描述能够灵活匹配目标方法。
通过正则表达式定义切面:

  1. <bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
  2. p:advice-ref="greetingAdvice">
  3. <property name="patterns">
  4. <list>
  5. <value>.*greet.*</value>
  6. </list>
  7. </property>
  8. </bean>
  9. <bean id="waiter1" class="org.springframework.aop.framework.ProxyFactoryBean"
  10. p:interceptorNames="regexpAdvisor"
  11. p:target-ref="waiterTarget"
  12. p:proxyTargetClass="true"/>

测试方法:

  1. @Test
  2. public void testAdvisor2(){
  3. String configPath = "com\\yyq\\aop\\beans.xml";
  4. ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
  5. Waiter waiter = (Waiter)ctx.getBean("waiter1");
  6. waiter.greetTo("John");
  7. waiter.serveTo("John");
  8. }
输出结果:
com.yyq.aop.Waiter.greetTo
Hi! Mr.John.
waiter greet to John.
waiter serving to John.
 
5、动态切面
    DynamicMethodMatcherPointcut是一个抽象类,它将isRuntime()标识为final且返回true,这样其子类就一定是一个动态的切点了,该抽象类默认匹配所有的类和方法,因此需要通过扩展该类编写符合要求的顶贴切点。
GreetingDynamicPointcut动态切面实现类:

  1. package com.yyq.aop;
  2. import org.springframework.aop.ClassFilter;
  3. import org.springframework.aop.support.DynamicMethodMatcherPointcut;
  4. import java.lang.reflect.Method;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut {
  8. private static List<String> specialClientList = new ArrayList<String>();
  9. static {
  10. specialClientList.add("John");
  11. specialClientList.add("Tom");
  12. }
  13. public ClassFilter getClassFilter() {
  14. return new ClassFilter() {
  15. @Override
  16. public boolean matches(Class<?> aClass) {
  17. System.out.println("调用getClassFilter()对" + aClass.getName() + "做静态检查。");
  18. return Waiter.class.isAssignableFrom(aClass);
  19. }
  20. };
  21. }
  22. public boolean matches(Method method, Class clazz) {
  23. System.out.println("调用matches(method,clazz)" + clazz.getName() + "." + method.getName() + "做静态检查。");
  24. return "greetTo".equals(method.getName());
  25. }
  26. @Override
  27. public boolean matches(Method method, Class<?> aClass, Object[] objects) {
  28. System.out.println("调用matches(method,aClass)" + aClass.getName() + "." + method.getName() + "做动态检查。");
  29. String clientName = (String)objects[0];
  30. return specialClientList.contains(clientName);
  31. }
  32. }

   Spring动态检查机制:在创建代理时对目标类的每个连接点使用静态切点检查,如果仅通过静态切点检查就可以知道连接点是不匹配的,则在运行时就不再进行动态检查了;如果静态切点检查时匹配的,在运行时才进行动态切点检查。

动态切面配置:

  1. <bean id="dynamicAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
  2. <property name="pointcut">
  3. <bean class="com.yyq.aop.GreetingDynamicPointcut"/>
  4. </property>
  5. <property name="advice">
  6. <bean class="com.yyq.aop.GreetingBeforeAdvice"/>
  7. </property>
  8. </bean>
  9. <bean id="waiter2" class="org.springframework.aop.framework.ProxyFactoryBean"
  10. p:interceptorNames="dynamicAdvisor"
  11. p:target-ref="waiterTarget"
  12. p:proxyTargetClass="true"/>

测试方法:

  1. @Test
  2. public void testAdvisor3(){
  3. String configPath = "com\\yyq\\aop\\beans.xml";
  4. ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
  5. Waiter waiter = (Waiter)ctx.getBean("waiter2");
  6. waiter.serveTo("Peter");
  7. waiter.greetTo("Peter");
  8. waiter.serveTo("John");
  9. waiter.greetTo("John");
  10. }
输出结果:
调用getClassFilter()对com.yyq.aop.Waiter做静态检查。
调用matches(method,clazz)com.yyq.aop.Waiter.greetTo做静态检查。
调用getClassFilter()对com.yyq.aop.Waiter做静态检查。
调用matches(method,clazz)com.yyq.aop.Waiter.serveTo做静态检查。
调用getClassFilter()对com.yyq.aop.Waiter做静态检查。
调用matches(method,clazz)com.yyq.aop.Waiter.toString做静态检查。
调用getClassFilter()对com.yyq.aop.Waiter做静态检查。
调用matches(method,clazz)com.yyq.aop.Waiter.clone做静态检查。
调用getClassFilter()对com.yyq.aop.Waiter做静态检查。
调用matches(method,clazz)com.yyq.aop.Waiter.serveTo做静态检查。
waiter serving to Peter.
调用getClassFilter()对com.yyq.aop.Waiter做静态检查。
调用matches(method,clazz)com.yyq.aop.Waiter.greetTo做静态检查。
调用matches(method,aClass)com.yyq.aop.Waiter.greetTo做动态检查。
waiter greet to Peter.
waiter serving to John.
调用matches(method,aClass)com.yyq.aop.Waiter.greetTo做动态检查。
com.yyq.aop.Waiter.greetTo
Hi! Mr.John.
waiter greet to John.
 
6、流程切面
    Spring的流程切面由DefaultPointcutAdvisor 和ControlFlowPointcut实现。流程切点代表由某个方法直接或间接发起调用的其他方法。
WaiterDelegate类代理Waiter所有的方法:

  1. package com.yyq.aop;
  2. public class WaiterDelegate {
  3. private Waiter waiter;
  4. public void service(String clientName){
  5. waiter.greetTo(clientName);
  6. waiter.serveTo(clientName);
  7. }
  8. public void setWaiter(Waiter waiter){
  9. this.waiter = waiter;
  10. }
  11. }

配置控制流程切面:

  1. <bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut">
  2. <constructor-arg type="java.lang.Class" value="com.yyq.aop.WaiterDelegate"/>
  3. <constructor-arg type="java.lang.String" value="service"/>
  4. </bean>
  5. <bean id="controlFlowAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
  6. p:pointcut-ref="controlFlowPointcut"
  7. p:advice-ref="greetingAdvice"/>
  8. <bean id="waiter3" class="org.springframework.aop.framework.ProxyFactoryBean"
  9. p:interceptorNames="controlFlowAdvisor"
  10. p:target-ref="waiterTarget"
  11. p:proxyTargetClass="true"/>

测试方法:

  1. @Test
  2. public void testAdvisor4(){
  3. String configPath = "com\\yyq\\aop\\beans.xml";
  4. ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
  5. Waiter waiter = (Waiter)ctx.getBean("waiter3");
  6. WaiterDelegate wd = new WaiterDelegate();
  7. wd.setWaiter(waiter);
  8. waiter.serveTo("Peter");
  9. waiter.greetTo("Peter");
  10. wd.service("Peter");
  11. }
输出结果:
waiter serving to Peter.
waiter greet to Peter.
com.yyq.aop.Waiter.greetTo
Hi! Mr.Peter.
waiter greet to Peter.
com.yyq.aop.Waiter.serveTo
Hi! Mr.Peter.
waiter serving to Peter.
 
7、复合切点切面
    假设我们希望由WaiterDelegate#service()发起调用且被调用的方法是Waiter#greetTo()时才织入增,。这个切点就是复合切点,因为它是由两个单独的切点共同确定。ComposablePointcut 可以将多个切点以并集或交集的方式组合起来,提供了切点之间复合运算的功能。
GreetingComposablePointcut复合切点实现类:

  1. package com.yyq.aop;
  2. import org.springframework.aop.Pointcut;
  3. import org.springframework.aop.support.ComposablePointcut;
  4. import org.springframework.aop.support.ControlFlowPointcut;
  5. import org.springframework.aop.support.NameMatchMethodPointcut;
  6. public class GreetingComposablePointcut {
  7. public Pointcut getIntersectionPointcut(){
  8. ComposablePointcut cp = new ComposablePointcut();
  9. Pointcut pt1 = new ControlFlowPointcut(WaiterDelegate.class,"service");
  10. NameMatchMethodPointcut pt2 = new NameMatchMethodPointcut();
  11. pt2.addMethodName("greetTo");
  12. return cp.intersection(pt1).intersection((Pointcut)pt2);
  13. }
  14. }

配置复合切点切面:

  1. <bean id="gcp" class="com.yyq.aop.GreetingComposablePointcut"/>
  2. <bean id="composableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
  3. p:pointcut="#{gcp.intersectionPointcut}"
  4. p:advice-ref="greetingAdvice"/>
  5. <bean id="waiter4" class="org.springframework.aop.framework.ProxyFactoryBean"
  6. p:interceptorNames="composableAdvisor"
  7. p:target-ref="waiterTarget"
  8. p:proxyTargetClass="true"/>

测试方法:

  1. @Test
  2. public void testAdvisor5(){
  3. String configPath = "com\\yyq\\aop\\beans.xml";
  4. ApplicationContext ctx = new ClassPathXmlApplicationContext(configPath);
  5. Waiter waiter = (Waiter)ctx.getBean("waiter4");
  6. WaiterDelegate wd = new WaiterDelegate();
  7. wd.setWaiter(waiter);
  8. waiter.serveTo("Peter");
  9. waiter.greetTo("Peter");
  10. wd.service("Peter");
  11. }
输出结果:
waiter serving to Peter.
waiter greet to Peter.
com.yyq.aop.Waiter.greetTo
Hi! Mr.Peter.
waiter greet to Peter.
waiter serving to Peter.
 
8、引介切面
    引介切面是引介增强的封装器,通过引介切面,我们更容易为现有对象添加任何接口的实现。
配置引介切面:

  1. <bean id="introduceAdvisor"
  2. class="org.springframework.aop.support.DefaultIntroductionAdvisor">
  3. <constructor-arg>
  4. <bean class="com.yyq.advice.ControllablePerformanceMonitor" />
  5. </constructor-arg>
  6. </bean>
  7. <bean id="forumServiceTarget" class="com.yyq.advice.ForumService" />
  8. <bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"
  9. p:interceptorNames="introduceAdvisor"
  10. p:target-ref="forumServiceTarget"
  11. p:proxyTargetClass="true"/>

Spring AOP 创建切面的更多相关文章

  1. 详细解读 Spring AOP 面向切面编程(二)

    本文是<详细解读 Spring AOP 面向切面编程(一)>的续集. 在上篇中,我们从写死代码,到使用代理:从编程式 Spring AOP 到声明式 Spring AOP.一切都朝着简单实 ...

  2. spring AOP面向切面编程学习笔记

    一.面向切面编程简介: 在调用某些类的方法时,要在方法执行前或后进行预处理或后处理:预处理或后处理的操作被封装在另一个类中.如图中,UserService类在执行addUser()或updateUse ...

  3. 【spring-boot】spring aop 面向切面编程初接触--切点表达式

    众所周知,spring最核心的两个功能是aop和ioc,即面向切面,控制反转.这里我们探讨一下如何使用spring aop. 1.何为aop aop全称Aspect Oriented Programm ...

  4. 【spring-boot】spring aop 面向切面编程初接触

    众所周知,spring最核心的两个功能是aop和ioc,即面向切面,控制反转.这里我们探讨一下如何使用spring aop. 1.何为aop aop全称Aspect Oriented Programm ...

  5. 【Spring系列】Spring AOP面向切面编程

    前言 接上一篇文章,在上午中使用了切面做防重复控制,本文着重介绍切面AOP. 在开发中,有一些功能行为是通用的,比如.日志管理.安全和事务,它们有一个共同点就是分布于应用中的多处,这种功能被称为横切关 ...

  6. 从源码入手,一文带你读懂Spring AOP面向切面编程

    之前<零基础带你看Spring源码--IOC控制反转>详细讲了Spring容器的初始化和加载的原理,后面<你真的完全了解Java动态代理吗?看这篇就够了>介绍了下JDK的动态代 ...

  7. Spring AOP 面向切面编程入门

    什么是AOP AOP(Aspect Oriented Programming),即面向切面编程.众所周知,OOP(面向对象编程)通过的是继承.封装和多态等概念来建立一种对象层次结构,用于模拟公共行为的 ...

  8. 详细解读 Spring AOP 面向切面编程(一)

    又是一个周末, 今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西,名字与 OOP 仅差一个字母,其实它是对 OOP 编程方式的一种补充,并非是取而代之. ...

  9. 阿里四面:你知道Spring AOP创建Proxy的过程吗?

    Spring在程序运行期,就能帮助我们把切面中的代码织入Bean的方法内,让开发者能无感知地在容器对象方法前后随心添加相应处理逻辑,所以AOP其实就是个代理模式. 但凡是代理,由于代码不可直接阅读,也 ...

随机推荐

  1. 微软Hololens学院教程-Hologram 220-空间声音(Spatial sound )【本文是老版本,与最新的微软教程有出入】

    这是老版本的教程,为了不耽误大家的时间,请直接看原文,本文仅供参考哦! 原文链接https://developer.microsoft.com/EN-US/WINDOWS/HOLOGRAPHIC/ho ...

  2. discuz之同步登入

    前言   首先感谢dozer学长吧UCenter翻译成C# 博客地址----------->http://www.dozer.cc/   其次感谢群友快乐々止境同学的热心指导,虽然萍水相逢但让我 ...

  3. JS 学习笔记--10---基本包装类型

    练习中使用的浏览器是IE10,如果有什么错误或者不同意见,希望各位朋友能够指正,练习代码附在后面 1.基本包装类型:    首先是基本类型,但又是特殊的引用类型,因为他们可以调用系统的方法,这种类型就 ...

  4. jquery ajax/post/get 传参数给 mvc的action

    jquery ajax/post/get 传参数给 mvc的action1.ActionResult Test1    2.View  Test1.aspx3.ajax page4.MetaObjec ...

  5. Mac中安装maven3.2.1

    Mac中安装maven3.2.1 原文链接:http://blog.csdn.net/f_zongjian/article/details/24144803 本机OS X:10.9,未安装XCode, ...

  6. 图解JavaScript执行环境结构

    JavaScript引擎在开始编译代码的时候,会对JavaScript代码进行一次预编译,生成一个执行环境,比如如下代码: window.onload=function(){ function sub ...

  7. acdream1116 Gao the string!(hash二分 or 后缀数组)

    问题套了一个斐波那契数,归根结底就是要求对于所有后缀s[i...n-1],所有前缀在其中出现的总次数.我一开始做的时候想了好久,后来看了别人的解法才恍然大悟.对于一个后缀来说 s[i...n-1]来说 ...

  8. ZOJ3720 Magnet Darts(点在多边形内)

    第一道点在多边形内的判断题,一开始以为是凸的.其实题意很简单的啦,最后转化为判断一个点是否在一个多边形内. 如果只是简单的凸多边形的话,我们可以枚举每条边算下叉积就可以知道某个点是不是在范围内了.但对 ...

  9. poj 2348

    Euclid's Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7418   Accepted: 3022 Des ...

  10. jxl.dll操作总结

    1)Jxl是一个开源的Java Excel API项目,通过Jxl,Java可以很方便的操作微软的Excel文档.除了Jxl之外,还有Apache的一个POI项目,也可以操作Excel,两者相比之下: ...