参考博文: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个或一个的意思,那这句话的意思就是:
<返回类型模式> <方法名模式>(<参数模式>) ----- 这些是必须的
<修饰符模式> <异常模式> ------ 这些不是必须的
各种切点定义
网上的博客说主要有:方法、类、类包、参数四种方式匹配,我根据个人理解自己重新进行分类。
不考虑包的方法匹配
这种匹配方式不考虑方法的包名。
- 无修饰符,不考虑方法参数
- 无修饰符,匹配方法参数
- 有修饰符,不考虑方法参数
有修饰符,匹配方法参数
第一种, 无修饰符,不考虑方法参数
匹配任意方法
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))
其它的参数以及修饰符同上。
测试总结
上面提到的各种匹配,部分我都测试了,但是发现一个问题,如果代理执行的方法调用了内部的方法,无论这个方法的修饰符是什么,这个内部调用是不会被拦截的,网上其它博主也遇到类似的问题。
简单的解决办法,就是把这个内部方法写到其它类中,注入这个类,通过这个类调用方法。