Spring Aspect的Execution表达式

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/u010173095/article/details/79549882

参考博文:Spring Aspect的Execution表达式

我最近在学习spring 隐式装配和自动化配置,在学习aop切面配置的时候,意外发现我竟然对切面匹配规则一点都不了解,现在根据网上的博客(没有找到官网的文档),学习一下。

@Aspect
@Component
public class ControllerAspectj {


    //execution 表达式 匹配需要的方法
    @Pointcut("execution(* com.cybx..*.*(..))")
    public void pointCut() {
        //定义切点
    }

    @Before("pointCut()")
    public void before() {
        //System.out.println("执行方法前执行这个方法");
    }

    @After("pointCut()")
    public void after() {
        //System.out.println("执行方法后执行这个方法");
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint jp) throws Throwable {

        String className = jp.getTarget().getClass().getSimpleName();
        String methodName = jp.getSignature().getName() + "()";
        System.out.println("className===" + className);
        System.out.println("methodName===" + methodName);

        Object obj = jp.proceed();

        System.out.println("方法执行结束");

        return obj;
    }
}

基本语法

execution(<修饰符模式>? <返回类型模式> <方法名模式>(<参数模式>) <异常模式>?)

? 在正则中是0个或一个的意思,那这句话的意思就是:

<返回类型模式> <方法名模式>(<参数模式>) ----- 这些是必须的
<修饰符模式>  <异常模式> ------ 这些不是必须的

各种切点定义

网上的博客说主要有:方法、类、类包、参数四种方式匹配,我根据个人理解自己重新进行分类。

不考虑包的方法匹配

这种匹配方式不考虑方法的包名。

  1. 无修饰符,不考虑方法参数
  2. 无修饰符,匹配方法参数
  3. 有修饰符,不考虑方法参数
  4. 有修饰符,匹配方法参数

    第一种, 无修饰符,不考虑方法参数

匹配任意方法

execution(* *(..)) 

测试

@Aspect
@Component
public class ControllerAspectj {

    //后面就只贴这个代码
    //execution 表达式 匹配所有的
    @Pointcut("execution(* *(..))")
    public void pointCut() {
        //定义切点
    }

    @Before("pointCut()")
    public void before() {
        //System.out.println("执行方法前执行这个方法");
    }

    @After("pointCut()")
    public void after() {
        //System.out.println("执行方法后执行这个方法");
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint jp) throws Throwable {

        String className = jp.getTarget().getClass().getSimpleName();
        String methodName = jp.getSignature().getName() + "()";
        System.out.println("className===" + className);
        System.out.println("methodName===" + methodName);

        Object obj = jp.proceed();

        System.out.println("方法执行结束");

        return obj;
    }
}

测试结果:

Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'redisTemplate' is expected to be of type [org.springframework.data.redis.core.StringRedisTemplate] but was actually of type [com.sun.proxy.$Proxy77]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:378)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1128)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
    ... 72 more

测试项目无法启动了,因为这种匹配方法,匹配了所有的方法,但是有的方法是代理生成的,启动过程无法执行,目前这种匹配方式我用不到。

第二种, 无修饰符,匹配方法参数

匹配方法,第一个参数是String,第二个参数int

execution(* *(String, int)) 

匹配方法,第一个参数是String,第二个参数类型不限制

execution(* *(String,*)) 

匹配方法,第一个参数是String,不限制其它参数的

execution(* *(String,..)) 

匹配名称后缀是ByPage的方法,一个参数是String

execution(* *ByPage(String)) 

匹配名称前缀是get的方法,一个参数是String

execution(* get*(String)) 

这些匹配方式,我的项目无法测试,启动项目就会报错。

剩下的修饰符,就不啰嗦了,就是在这些匹配方式之前加上修饰符,例如:

execution(public * get*(String)) 

包含类包限制的方法匹配

这种方式的匹配就是把上述的方法的*替换成有类包限制的的表达式,例如:

匹配名称后缀是ByPage的方法,一个参数是String

execution(* *ByPage(String)) 

加上类包限制,只匹配com.test.Controller.TestController下的后缀为ByPage,参数为String的方法:

execution(* com.test.Controller.TestController.*ByPage(String)) 

如果还想匹配TestController的实现类的方法,加上一个+号:

execution(* com.test.Controller.TestController+.*ByPage(String)) 

如果想匹配com.test.Controller包下类的方法:

execution(* com.test.Controller.*.*ByPage(String)) 

如果想匹配com.test.Controller包以及子包中类的方法:

execution(* com.test.Controller..*.*ByPage(String)) 

其它的参数以及修饰符同上。

测试总结

上面提到的各种匹配,部分我都测试了,但是发现一个问题,如果代理执行的方法调用了内部的方法,无论这个方法的修饰符是什么,这个内部调用是不会被拦截的,网上其它博主也遇到类似的问题。

简单的解决办法,就是把这个内部方法写到其它类中,注入这个类,通过这个类调用方法。

可以参考这个博客,以及这个博客

猜你喜欢

转载自blog.csdn.net/u010173095/article/details/79549882