Spring AOP 之二:Pointcut注解表达式

Stella981
• 阅读 837

简介

Spring AOP概述中我们重点注意的是AOP的整体流程和Advice,简化了一些其他的东西,其中就有一些对灵活应用Spring AOP很重要的知识点,例如Pointcut表达式,下面就介绍一下Spring AOP的Pointcut表达式。

如果你对Pointcut表达式的作用还不是很了解,可以先看一下Spring AOP概述,也可以先了解一下匹配规则,后面会有一些具体的例子来帮助理解。

我们使用最多的就是execution表示了,下面就从execution表达式开始介绍吧。

注意:把designators翻译为表达式也许不太合适,所以不必纠结这个问题,只需要知道在看到Spring AOP中的designators知道对应的是个什么东西就可以了。管它是表达式还是指示器只是一个代称而已。

execution表达式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)

上面的就是execution表达式的格式,execution匹配的就是连接点(Joinpoint,一般是方法),看上面的表达式execution是固定的,方法的修饰符是可选的,返回类型是必须的,定义的全限类型也是可选的,名称是必须的,参数是必须的,这些都可以使用通配符。

任何的public方法

execution(public * *(..))

以set开始的方法

execution(* set*(..))

定义在cn.freemethod.business.pack.Say接口中的方法

execution(* cn.freemethod.business.pack.Say.*(..))

任何cn.freemethod.business包中的方法

execution(* cn.freemethod.business.*.*(..))

任何定义在com.xyz.service包或者其子包中的方法

execution(* cn.freemethod.business..*.*(..))

其他表达式

任何在com.xyz.service包中的方法

within(com.xyz.service.*)

任何定义在com.xyz.service包或者其子包中的方法

within(com.xyz.service..*)

任何实现了com.xyz.service.AccountService接口中的方法

this(com.xyz.service.AccountService)

任何目标对象实现了com.xyz.service.AccountService的方法

target(com.xyz.service.AccountService)

一般情况下代理类(Proxy)和目标类(Target)都实现了相同的接口,所以上面的2个基本是等效的。

有且只有一个Serializable参数的方法

args(java.io.Serializable)

只要这个参数实现了java.io.Serializable接口就可以,不管是java.io.Serializable还是Integer,还是String都可以。

目标(target)使用了@Transactional注解的方法

@target(org.springframework.transaction.annotation.Transactional)

目标类(target)如果有Transactional注解中的所有方法

@within(org.springframework.transaction.annotation.Transactional)

任何方法有Transactional注解的方法

@annotation(org.springframework.transaction.annotation.Transactional)

有且仅有一个参数并且参数上类型上有Transactional注解

@args(org.springframework.transaction.annotation.Transactional)

注意是参数类型上有Transactional注解,而不是方法的参数上有注解。

bean的名字为tradeService中的方法

bean(simpleSay)

bean名字为simpleSay中的所有方法。

bean名字能匹配

bean(*Impl)

bean名字匹配*Impl的bean中的所有方法。

实例

这个实例是对Spring AOP概述中介绍的实例进行了扩展。当然下面给的实例也可以独立测试,最好是一个一个测试观察输出了验证,多个输出结果不够直观。

下面的图片是项目工程目录结构:

Spring AOP 之二:Pointcut注解表达式

下面的代码列表因为比较多,可以在后面找到完整的代码工程代码的附件链接,因为其他一些原因没有放到github或者码云上,可以直接下载附件解压使用maven方式导入。

OtherPointcutAspect

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class OtherPointcutAspect {
    
//    @After("cn.freemethod.pointcut.OtherPointcut.argsSerializable()")
    public void argsSerialize(){
        System.out.println("OtherPointcutAspect argsSerialize after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.inBusinessPackage()")
    public void inBusinessPackage(){
        System.out.println("OtherPointcutAspect inBusinessPackage after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.inBusinessOrSubPackage()")
    public void inBusinessOrSubPackage(){
        System.out.println("OtherPointcutAspect inBusinessOrSubPackage after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.proxyImplementHaveResultBusinessInteferce()")
    public void proxyImplementHaveResultBusinessInteferce(){
        System.out.println("OtherPointcutAspect proxyImplementHaveResultBusinessInteferce after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.targetImplementBusinessInteferce()")
    public void targetImplementBusinessInteferce(){
        System.out.println("OtherPointcutAspect targetImplementBusinessInteferce after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.targetHaveTransactional()")
    public void targetHaveTransactional(){
        System.out.println("OtherPointcutAspect targetHaveTransactional after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.targetDeclareHaveTransactional()")
    public void targetDeclareHaveTransactional(){
        System.out.println("OtherPointcutAspect targetDeclareHaveTransactional after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.methodHaveTransactional()")
    public void methodHaveTransactional(){
        System.out.println("OtherPointcutAspect methodHaveTransactional after...");
    }
    
    @After("cn.freemethod.pointcut.OtherPointcut.argsHaveValueAnnotation()")
    public void argsHaveTransactional(){
        System.out.println("OtherPointcutAspect argsHaveValueAnnotation after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.beanName()")
    public void beanName(){
        System.out.println("OtherPointcutAspect beanName after...");
    }
    
//    @After("cn.freemethod.pointcut.OtherPointcut.matchBeanName()")
    public void matchBeanName(){
        System.out.println("OtherPointcutAspect matchBeanName after...");
    }

}

上面是一个测试Pointcut表达式的切面,很多Advice都注释了,请为了从输出中直观的了解Pointcut表达式匹配到了什么方法(Joinpoint),请根据自己的需要测试的Pointcut表达式取消添加注释。

ExecutionPointcutAspect

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class ExecutionPointcutAspect {
    
    @Before("cn.freemethod.pointcut.ExecutionPointcut.allPublicMethod()")
    public void allPublicBefore(){
        System.out.println("PointcutExpressionAspect allPublicBefore...");
    }
    
    @After("cn.freemethod.pointcut.ExecutionPointcut.allStartSayMethod()")
    public void sayAfter(){
        System.out.println("PointcutExpressionAspect sayAfter...");
    }
    
    @AfterReturning("cn.freemethod.pointcut.ExecutionPointcut.allInSayInterfaceMethod()")
    public void allInSayInterfaceMethod(){
        System.out.println("PointcutExpressionAspect allInSayInterfaceMethod...");
    }
    
    @Before("cn.freemethod.pointcut.ExecutionPointcut.allInBusinessPackage()")
    public void allInBusinessPackageBefore(){
        System.out.println("PointcutExpressionAspect all business before...");
    }
    
    @After("cn.freemethod.pointcut.ExecutionPointcut.allInBusinessOrSubPackage()")
    public void allallInBusinessOrSubPackageAfter(){
        System.out.println("PointcutExpressionAspect allallInBusinessOrSubPackageAfter...");
    }

}

ParamBean

import org.springframework.transaction.annotation.Transactional;

@Transactional
public class ParamBean {

}

HaveResultBusinessImpl

import org.springframework.stereotype.Service;

import cn.freemethod.business.HaveResultBusiness;

@Service
public class HaveResultBusinessImpl implements HaveResultBusiness {

    @Override
    public Integer getResult(Integer div) {
        System.out.println("HaveResultBusinessImpl getResult");
        Integer result = 100 / div;
        return result;
    }

}

IOtherPointcutImpl

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.freemethod.bean.ParamBean;
import cn.freemethod.business.pack.IOtherPointcut;

@Transactional
@Service
public class IOtherPointcutImpl implements IOtherPointcut {

    @Override
    public Integer printInteger(Integer arg) {
        System.out.println("IOtherPointcutImpl printInteger");
        return arg;
    }


    @Override
    public void withAnotationParam(ParamBean arg) {
        System.out.println("IOtherPointcutImpl withAnotationParam");
    }

}

SimpleSay

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.freemethod.business.pack.Say;

@Transactional
@Service
public class SimpleSay implements Say {

    @Override
    public String sayChiness(String name) {
        String result = "你好:" + name;
        System.out.println(result);
        return result;
    }

    @Override
    public String sayEnglish(String name) {
        String result = "Hello " + name;
        System.out.println(result);
        return result;
    }

    @Transactional
    @Override
    public String whatSay() {
        System.out.println("what say");
        return "what say";
    }

}

IOtherPointcut

import cn.freemethod.bean.ParamBean;

public interface IOtherPointcut {
    
    Integer printInteger(Integer arg);
    
    void withAnotationParam(ParamBean arg);

}

Say

public interface Say {
    
    String sayChiness(String name);
    
    String sayEnglish(String name);
    
    String whatSay();

}

HaveResultBusiness

public interface HaveResultBusiness {
    
    Integer getResult(Integer div);

}

AspectConfig

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = {"cn.freemethod"})
public class AspectConfig {

}

ExecutionPointcut

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class ExecutionPointcut {

    @Pointcut("execution(public * *(..))")
    public void allPublicMethod(){}
    
    @Pointcut("execution(* say*(..))")
    public void allStartSayMethod(){}
    
    @Pointcut("execution(* cn.freemethod.business.pack.Say.*(..))")
    public void allInSayInterfaceMethod(){}
    
    @Pointcut("execution(* cn.freemethod.business.*.*(..))")
    public void allInBusinessPackage(){}
    
    @Pointcut("execution(* cn.freemethod.business..*.*(..))")
    public void allInBusinessOrSubPackage(){}
    
    
}



import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class OtherPointcut {
    
    @Pointcut("within(cn.freemethod.business.impl.*)")
    public void inBusinessPackage(){}
    
    @Pointcut("within(cn.freemethod.business..*)")
    public void inBusinessOrSubPackage(){}
    
    @Pointcut("this(cn.freemethod.business.HaveResultBusiness)")
    public void proxyImplementHaveResultBusinessInteferce(){}
    
    @Pointcut("target(cn.freemethod.business.HaveResultBusiness)")
    public void targetImplementBusinessInteferce(){}
    
    @Pointcut("args(java.io.Serializable)")
//    @Pointcut("args(java.lang.Integer)")
    public void argsSerializable(){}
    
    
    @Pointcut("@target(org.springframework.transaction.annotation.Transactional)")
    public void targetHaveTransactional(){}
    
    @Pointcut("@within(org.springframework.transaction.annotation.Transactional)")
    public void targetDeclareHaveTransactional(){}
    
    @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
    public void methodHaveTransactional(){}

    @Pointcut("@args(org.springframework.transaction.annotation.Transactional)")
    public void argsHaveValueAnnotation(){}
    
    @Pointcut("bean(simpleSay)")
    public void beanName(){}
    
    @Pointcut("bean(*Impl)")
    public void matchBeanName(){}

}

AnnotationConfigStart

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

import cn.freemethod.business.HaveResultBusiness;
import cn.freemethod.business.pack.Say;
import cn.freemethod.config.AspectConfig;

public class AnnotationConfigStart {
    
    public static void main(String[] args) {
        AbstractApplicationContext  context = new AnnotationConfigApplicationContext(AspectConfig.class);
        HaveResultBusiness haveResultBusiness = context.getBean(HaveResultBusiness.class);
        haveResultBusiness.getResult(100);
        Say say = context.getBean(Say.class);
        say.sayChiness("tim");
        say.sayEnglish("tim");
        say.whatSay();
        context.close();
    }

}

PointcutExpressionStart

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;

import cn.freemethod.bean.ParamBean;
import cn.freemethod.business.HaveResultBusiness;
import cn.freemethod.business.pack.IOtherPointcut;
import cn.freemethod.business.pack.Say;
import cn.freemethod.config.AspectConfig;

public class PointcutExpressionStart {
    
    public static void main(String[] args) {
        AbstractApplicationContext  context = new AnnotationConfigApplicationContext(AspectConfig.class);
        IOtherPointcut iOtherPointcut = context.getBean(IOtherPointcut.class);
        iOtherPointcut.printInteger(new Integer(10));
        iOtherPointcut.withAnotationParam(new ParamBean());
        
        HaveResultBusiness haveResultBusiness = context.getBean(HaveResultBusiness.class);
        haveResultBusiness.getResult(100);
        
        Say say = context.getBean(Say.class);
        say.sayChiness("tim");
        say.sayEnglish("tim");
        say.whatSay();
        context.close();
    }

}

参考

完整工程代码

Spring AOP 之一:基本概念与流程

Spring AOP 之二:Pointcut注解表达式

Spring AOP 之三:通知(Advice)方法参数

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
thinkphp3.2.3模板渲染支持三元表达式
thinkphp3.2.3模板渲染支持三元表达式{$status?'正常':'错误'}{$info'status'?$info'msg':$info'error'}注意:三元运算符中暂时不支持点语法。如下:           <divclass"modalhidefade"id'myModa
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
AJPFX总结关于Java中过滤出字母、数字和中文的正则表达式
1、Java中过滤出字母、数字和中文的正则表达式(1)过滤出字母的正则表达式\^(AZaz)\(2)过滤出数字的正则表达式\^(09)\(3)过滤出中文的正则表达式\^(\\\\u4e00\\\\u9fa5)\(4)过滤出字母、数字和中文的正则表达式\^(azAZ09\\\\u
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这