• 循序渐进之Spring AOP(6)


    前面几节的示例看起来让人沮丧,要记忆如此多的接口、类和继承关系,做各种复杂的配置。好在这些只是一种相对过时的实现方式,现在只需要使用@Aspect注解及表达式就可以轻松的使用POJO来定义切面,设计精妙正如spring MVC的@Controller。

    1 示例

    仍然使用上一节的"骑士和剑士"的例子,目标类Horseman和Swordman

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. public class Horseman {  
    2.     public void rush(String enemy) {  
    3.         System.out.println(this.getClass().getSimpleName() + "冲刺攻击" + enemy);  
    4.     }  
    5.       
    6.     public void chop(String enemy) {  
    7.         System.out.println(this.getClass().getSimpleName() + "砍劈攻击" + enemy);  
    8.     }  
    9. }  
    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. public class Swordman {  
    2.     public void block(String enemy) {  
    3.         System.out.println(this.getClass().getSimpleName() + "格挡" + enemy);  
    4.     }  
    5.       
    6.     public void chop(String enemy) {  
    7.         System.out.println(this.getClass().getSimpleName() + "砍劈攻击" + enemy);  
    8.     }  
    9. }  

    切面

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. @Aspect  
    2. public class StorageAdvisor {  
    3.   
    4.     @Before("execution(* chop(..))")  
    5.     public void beforeAttack(JoinPoint point) {  
    6.         System.out.println("Advice: " + point.getTarget().getClass().getSimpleName() + "蓄力");  
    7.     }  
    8. }  

    applicationContext.xml

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. <beans xmlns="http://www.springframework.org/schema/beans"  
    2.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
    3.     xmlns:aop="http://www.springframework.org/schema/aop"  
    4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
    5.   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
    6.   http://www.springframework.org/schema/aop  
    7.   http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">  
    8.     
    9.     <aop:aspectj-autoproxy />  
    10.     <bean id="horseman" class="examples.chap03.Horseman" />  
    11.     <bean id="swordman" class="examples.chap03.Swordman" />  
    12.     <bean class="examples.chap03.StorageAdvisor" />  
    13. </beans>  

    测试代码

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. public static void main(String[] args) {  
    2.     ApplicationContext context = new ClassPathXmlApplicationContext("examples/chap03/applicationContext.xml");  
    3.     Horseman hm = (Horseman)context.getBean("horseman");  
    4.     hm.rush("Ghoul");  
    5.     hm.chop("Ghoul");  
    6.     Swordman sm = (Swordman)context.getBean("swordman");  
    7.     sm.block("Ghoul");  
    8.     sm.chop("Ghoul");  
    9. }  

    对比上一节的内容可以看到,实现同样的功能,代码和配置都精简了很多,而且构建切面的类是一个普通的POJO,开发和测试的灵活性都大幅度提高。

    2 注解说明

    2.1 @Aspect

    作用是把当前类标识为一个切面供容器读取

    2.2 @Before
    标识一个前置增强方法,相当于BeforeAdvice的功能,相似功能的还有

    2.3 @AfterReturning

    后置增强,相当于AfterReturningAdvice,方法正常退出时执行

    2.4 @AfterThrowing

    异常抛出增强,相当于ThrowsAdvice

    2.5 @After

    final增强,不管是抛出异常或者正常退出都会执行

    2.6 @Around

    环绕增强,相当于MethodInterceptor

    2.7 @DeclareParents

    引介增强,相当于IntroductionInterceptor

    3 execution切点函数

    execution函数用于匹配方法执行的连接点,语法为:

    execution(方法修饰符(可选)  返回类型  方法名  参数  异常模式(可选)) 

    参数部分允许使用通配符:

    *  匹配任意字符,但只能匹配一个元素

    .. 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用

    +  必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类

    示例中的* chop(..)解读为:

    方法修饰符  无

    返回类型      *匹配任意数量字符,表示返回类型不限

    方法名          chop表示匹配名称为chop的方法

    参数               (..)表示匹配任意数量和类型的输入参数

    异常模式       不限

    更多示例:

    void chop(String,int)

    匹配目标类任意修饰符方法、返回void、方法名chop、带有一个String和一个int型参数的方法

    public void chop(*)

    匹配目标类public修饰、返回void、方法名chop、带有一个任意类型参数的方法

    public String *o*(..)

     匹配目标类public修饰、返回String类型、方法名中带有一个o字符、带有任意数量任意类型参数的方法

    public void *o*(String,..)

     匹配目标类public修饰、返回void、方法名中带有一个o字符、带有任意数量任意类型参数,但第一个参数必须有且为String型的方法

    也可以指定类:

    public void examples.chap03.Horseman.*(..)

    匹配Horseman的public修饰、返回void、不限方法名、带有任意数量任意类型参数的方法

    public void examples.chap03.*man.*(..)

    匹配以man结尾的类中public修饰、返回void、不限方法名、带有任意数量任意类型参数的方法

    指定包:

    public void examples.chap03.*.chop(..)

    匹配examples.chap03包下所有类中public修饰、返回void、方法名chop、带有任意数量任意类型参数的方法

    public void examples..*.chop(..)

    匹配examples.包下和所有子包中的类中public修饰、返回void、方法名chop、带有任意数量任意类型参数的方法
    可以用这些表达式替换StorageAdvisor中的代码并观察效果

    4 更多切点函数

    除了execution(),Spring中还支持其他多个函数,这里列出名称和简单介绍,以方便根据需要进行更详细的查询

    4.1 @annotation()

    表示标注了指定注解的目标类方法

    例如 @annotation(org.springframework.transaction.annotation.Transactional) 表示标注了@Transactional的方法

    4.2 args()

    通过目标类方法的参数类型指定切点

    例如 args(String) 表示有且仅有一个String型参数的方法

    4.3 @args()

    通过目标类参数的对象类型是否标注了指定注解指定切点

    如 @args(org.springframework.stereotype.Service) 表示有且仅有一个标注了@Service的类参数的方法

    4.4 within()

    通过类名指定切点

    如 with(examples.chap03.Horseman) 表示Horseman的所有方法

    4.5 target()

    通过类名指定,同时包含所有子类

    如 target(examples.chap03.Horseman)  且Elephantman extends Horseman,则两个类的所有方法都匹配

    4.6 @within()

    匹配标注了指定注解的类及其所有子类

    如 @within(org.springframework.stereotype.Service) 给Horseman加上@Service标注,则Horseman和Elephantman 的所有方法都匹配

    4.7 @target()

    所有标注了指定注解的类

    如 @target(org.springframework.stereotype.Service) 表示所有标注了@Service的类的所有方法

    4.8 this()

    大部分时候和target()相同,区别是this是在运行时生成代理类后,才判断代理类与指定的对象类型是否匹配

    5 逻辑运算符

    表达式可由多个切点函数通过逻辑运算组成

    5.1 &&

    与操作,求交集,也可以写成and

    例如 execution(* chop(..)) && target(Horseman)  表示Horseman及其子类的chop方法

    5.2 ||

    或操作,求并集,也可以写成or

    例如 execution(* chop(..)) || args(String)  表示名称为chop的方法或者有一个String型参数的方法

    5.3 !

    非操作,求反集,也可以写成not

    例如 execution(* chop(..)) and !args(String)  表示名称为chop的方法但是不能是只有一个String型参数的方法

  • 相关阅读:
    android 中文 api (43) —— Chronometer
    SVN客户端清除密码
    Android 中文 API (35) —— ImageSwitcher
    Android 中文API (46) —— SimpleAdapter
    Android 中文 API (28) —— CheckedTextView
    Android 中文 API (36) —— Toast
    Android 中文 API (29) —— CompoundButton
    android 中文 API (41) —— RatingBar.OnRatingBarChangeListener
    Android 中文 API (30) —— CompoundButton.OnCheckedChangeListener
    Android 中文 API (24) —— MultiAutoCompleteTextView.CommaTokenizer
  • 原文地址:https://www.cnblogs.com/sa-dan/p/6837219.html
Copyright © 2020-2023  润新知