Spring学习之使用注解配置AOP

Spring学习之使用注解配置AOP

前言

在前面的学习中,基本了解了AOP的概念,以及在使用原始的方法在Spring中配置AOP,不过在前面我们也看到了,通过编程的方式来实现AOP是比较繁琐,而且扩展性比较低了,所以Spring对AOP的配置方式进行了很大的改进,并且提供了更加方便的配置方式,本小节主要来学习使用注解进行配合,这是在使用Spring AOP中最常使用的方式了。

切点函数

在前面的内容中,我们看到了在配置增强的时候,很难进行切点的配置,所以,接下来我们首先来看下Spring AOP的一个重大的改进,使用切点表达式来描述切点

一个切点表达式或者称之为切点函数主要由两个部分组成:关键字 + 操作参数,其中的关键字,也称之为切点函数,主要由以下四种类型

切点函数类型

  • 方法切点函数:用于匹配方法
    • execution():比较常使用
      • 入参:匹配方法的串
      • 说明:满足指定模式的所有方法连接点
    • @annotation()
      • 入参:注解类型
      • 说明:匹配标注了该注解的连接点
  • 方法入参切点函数:用于匹配方法的参数
    • args()
      • 入参:类名
      • 说明:匹配入参类型的连接点
    • @args()
      • 入参:注解
      • 说明:匹配入参类型为标志了该注解的连接点
  • 目标类切点函数:用于匹配对应的目标类而不是代理类
    • within()
      • 入参:类名模式串
      • 说明:参数类型只能指定到类级别,包含子类,不能指定方法,其余同execution
    • target()
      • 入参:类名
      • 说明:类型匹配的类下的所有方法,但不包含子类
    • @within()
      • 入参:注解
      • 说明:匹配所有标注该注解的类的类的所有方法
    • @target()
      • 入参:注解
      • 说明:目标对象标注了该注解,不包含子类
  • 代理类切点函数:用于匹配对应的代理类而不是目标类
    • @this()
      • 入参:类名
      • 说明:匹配当前代理对象的类型,而不是目标类型

除了切入点函数外,还有一些符号需要了解

  • *:表示匹配任意一个元素,比如,cn.xuhuanfeng.service.*表示匹配该包下的所有类,但是不包含子包
  • ..*:表示匹配包以及所有的子包
  • ..:如果用于参数,则表示任意参数,比如cn.xuhuanfeng.service.UserService.save(..)表示该包下的UserService类的含有任意参数的save方法
  • +:只能用于类,表示对应的类及其子类

切入点表达式的基本格式:访问限制符(public/protected/private) 方法返回类型(int/double/char/...) 包.类.方法(参数)

接下来,我们来通过一些具体的表达式例子来更好地理解上面的内容

首先假定有如下类型


public class UserService {

    public void login(){
        System.out.println("login...");
    }

    protected void logout(){
        System.out.println("logout...");
    }

    protected int login(int number){
        System.out.println("login in..." + number);
        return number;
    }

    public int loout(int number){
        System.out.println("logout ... " + number);
        return number;
    }
}

表达式以及对应的匹配方法如下所示

  • public void cn.xuhuanfeng.aop.anno.UserService.login(..) 匹配的方法为public void login()
  • public * cn.xuhuanfeng.aop.anno.UserService.login(..) 匹配的方法为pulic int login()
  • * cn.xuhuanfeng.aop.anno.UserService.login(..) 匹配的方法为public int login()以及protected int login()
  • * cn.xuhuanfeng.aop.anno.UserService.*() 匹配上面的所有的方法
  • * cn.xuhuanfeng.aop.anno.UserService.*(int) 匹配上面含有一个int类型参数的方法
  • * cn.xuhuanfeng.aop.anno.*.*(..) 匹配anno包下的任意类的任意方法
  • * cn.xuhuanfeng.aop.anno.UserService+.*(..) 匹配anno包下的UserService类及其子类的所有方法
  • * cn.xuhuanfeng.aop..*UserService.*(..) 匹配anno包及其子包下UserService类的任意方法

可以看到,通过切入点表达式,可以非常方便地描述任意类型的切点了,也就是说,通过这种方式,以及解决了之前无法很好地描述切点的问题了

注解配置AOP实例

接下来通过几个具体的实例来使用上面所提到的切入点表达式以及对应的切点方法


    // 使用 @Before表示在方法执行前进行增强
    // 使用execution拦截方法
    // 对应的表达式表示具体的拦截方法
    @Before("execution(* cn.xuhuanfeng.aop..*.UserService+.*(..))")
    public void addLog(){
        System.out.println("info....");
    }

    // 使用 @AfterReturning表示在方法返回后进行增强
    // 用@annotation拦截标注了Deprecated的方法
    @AfterReturning("@annotation(Deprecated)")
    public void log(){

    }

除了上面的@Before@AfterReturning还有@After@AfterThrowing@Around 等用于表示切点方位的注解,基本上都见名知义

初次之外,还有一个用于标注切点的注解@Pointcut,用于在方法上标注,并且提供对应的表达式,表示一个命名的切点,名称为函数名,这样,一个切点就可以在多处引用了


    // 声明切点
    @Pointcut("execution(* cn.xuhuanfeng.aop..*.UserService+.*(..))")
    public void pointcut(){}

    // 引用切点
    @Before("pointcut()")
    public void logging(){

    }

经过上面的配置,基本上切面就配置好了,不过,此时是如果进行测试会发现,增强并没有起作用,原因在于,还需要将对应的增强配置到Spring容器中,配置如下


@Component // 方便IoC容器对其进行管理
@Aspect // 声明为切面
class LogManager{
    // 省略上面的内容
}

然后在Spring配置文件中,添加一下配置

 
 <!--开启Bean自动扫描-->
 <context:component-scan base-package="cn.xuhuanfeng.aop.anno"/>
 <!--开启注解自动配置-->
 <aop:aspectj-autoproxy/>

经过上面的配置之后,所配置的增强就可以正常的工作了

除了简单的切入点函数外,Spring还支持通过逻辑运算符(&&、|| 、!)来组合切入点函数,组成复合表达式

// 通过逻辑运算符组成复合表达式,不过此时相应的参数要求也就发生变化了,这里需要注意一下
@Before("execution(* cn.xuhuanfeng.aop..*.UserService+.*(..)) && args(int)")
    public void addLog(){
        System.out.println("info....");
    }

参数绑定

有时候还需要在增强中获取目标方法的参数,此时可以有两种方式来获取,下面直接通过代码进行演示

通过JointPoint来获取


    @Before("execution(* cn.xuhuanfeng.aop..*.UserService+.*(..))")
    public void addLog(JoinPoint joinPoint){
        joinPoint.getArgs();  // 获得参数
        joinPoint.getTarget(); // 获得对应的目标对象
        joinPoint.getThis(); // 获得当前代理对象
        joinPoint.getSignature(); // 获得方法签名
    }

也可以直接声明所需要的参数,不过这里的匹配规则需要注意


    @Before("execution(* cn.xuhuanfeng.aop..*.UserService+.*(..)) && args(id, id2)")
    public void addLog(int id, int id2){
        /*
            匹配的规则如下:
                首先表达式中的参数名称匹配增强方法中参数的名称,如果匹配,
                    则表达式中的参数的类型为增强方法中匹配的参数的类型
                    然后在目标方法的参数中根据类型进行匹配,然后将对应的值绑定到增强方法参数中
         */
    }

同样这里需要注意的是,execution 是不能用于指定参数的,也就是说,如果要使用exection进行匹配的话,必须为其增加多一个args()函数,用于作为参数的绑定,其他的方位注解则可以用于绑定相应的参数

总结

本小节主要了解了切入点表达式的具体内容,以及相应的写法,还学习了在Spring中通过注解的方式配置AOP,并且学习了参数的绑定以及对应的注意事项

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • 上篇我们介绍了Spring中有关高级依赖关系配置的内容,也可以调用任意方法的返回值作为属性注入的值,它解决了Spr...
    Single_YAM阅读 605评论 0 6
  • 一、增强类 1 前置增强(MethodBeforeAdvice)重写before(Method method,Ob...
    Q南南南Q阅读 1,202评论 0 0
  • AOP实现可分为两类(按AOP框架修改源代码的时机): 静态AOP实现:AOP框架在编译阶段对程序进行修改,即实现...
    数独题阅读 2,294评论 0 22
  • 大概明白这本为什么畅销了。这本在毛姆大爷絮絮叨叨的叙事风格里面已经可以算得上是“波澜起伏”了。更重要的是,满足了大...
    wanzi_763阅读 143评论 0 0