概述
execution()是最常用的切点函数,语法如下
execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
其中:返回类型模式、方法名模式、参数模式是必选项。
通过execution()定义切点的不同方式
下面我们通过各种实例来理解如何使用execution()
通过方法签名定义切点
execution(public * *(..))
匹配所有目标类的public方法。 第一个*
代表返回类型,第二个*
代表方法名,而..
代表任意入参的方法
execution(* *To(..))
匹配目标类所有以To为后缀的方法。 第一个*
代表返回类型,而*To
代表任意以To为后缀的方法。
通过类定义切点
execution(* com.xgj.aop.spring.advisor.aspectJ.function.execution.classpoint.Cleaner.*(..))匹配Cleaner接口的所有方法(包括实现类中覆写的方法), 第一个 * 代表返回任意类型 ,...Cleaner.*代表Cleaner接口中的所有方法
execution(* com.xgj.aop.spring.advisor.aspectJ.function.execution.classpoint.Cleaner.*(..))匹配Cleaner接口及其所有实现类的方法,不但匹配实现类中覆写的方法,也包括实现类中不在接口中定义的方法
通过类包定义切点
在类名模式串中,.*
表示包下的所有类,..*
表示包、子孙包下的所有类
execution(* com.xgj.*(..))匹配com.xgj包下所有类的所有方法
execution(* com.xgj..*(..))匹配com.xgj包、子孙包下所有类的所有方法.比如 com.xgj.dao ,com.xgj.service,com.xgj.dao.user包下所有类的所有方法都匹配。 当 ..出现在类名中时,必须后面跟*表示子孙包下的所有类。
execution(* com..*Dao.find*(..))匹配包名前缀为com的任何包下类名后缀为Dao的方法,方法名必须以find为前缀, 比如com.xgj.UserDao#findUserById()方法都是匹配切点。
通过方法入参定义切点
切点表达式中的方法入参部分比较复杂,可以使用*
和..
通配符。 其中 *
表示任意参数类型的参数, 而..
表示任意类型的参数且参数个数不限。
execution(* joke(String,int))匹配joke(String,int)方法,且joke方法的第一个入参是String,第二个入参是int。 比如 匹配 SmartSeller#joke(String ,int)方法。 如果方法中的入参类型是java.lang包下的,这可以直接使用类名,否则必须使用全限定类名,比如 joke(java.util.List,int)
execution(* joke(String,*))匹配目标类中的joke()方法,该方法第一个入参为String,第二个入参为任意类型。 比如 joke(String s1, String s2)和joke(String s1,double d)都匹配,但是 joke(String s1, String s2,double d3)不匹配
execution(* joke(String,..))匹配目标类中的joke方法,该方法的第一个入参为String,后面可以有任意个入参且入参类型不限。 比如 joke(String s1),joke(String s1,String s2)和joke(String s1,double d2,String s3)都匹配。
execution(* joke(Object+))匹配目标类中的joke()方法,方法拥有一个入参,且入参是Object类型或该类的子类。 它匹配joke(String s1) 和joke(Client c) . 如果定义的切点是execution(* joke(Object)) ,则只匹配joke(Object object)而不匹配joke(String s1) 或者joke(Client c)
实例
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster
仅以通过方法签名定义切点为例子,其余场景请参考https://github.com/yangshangwei/SpringMaster, 亲测通过。
execution(* com.xgj.aop.spring.advisor.aspectJ.function.execution.classpoint.Cleaner.*(..))
package com.xgj.aop.spring.advisor.aspectJ.function.execution; public class NaiveWaiter { /** * public方法,演示execution(public * *(..)),能匹配到 */ public void greetTo(String clientName) { System.out.println("NaiveWaiter greet to " + clientName); } }
package com.xgj.aop.spring.advisor.aspectJ.function.execution; public class SmartSeller { /** * public方法,演示execution(public * *(..)),能匹配到 */ public void sell(String goods) { System.out.println("SmartSeller sells " + goods); } /** * * * @Title: smileTo * * @Description: 非public方法,演示execution(public * *(..)),不能匹配到 * * @param clientName * * @return: void */ protected void smileTo(String clientName) { System.out.println("SmartSeller simles to " + clientName); } }
切面
package com.xgj.aop.spring.advisor.aspectJ.function.execution; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; /** * * * @ClassName: ExecutionPublicAspect * * @Description: TODO * * @author: Mr.Yang * * @date: 2017年8月27日 下午1:47:55 */ @Aspect public class ExecutionPublicAspect { @Before("execution(public * *(..))") public void crossCuttingLogic() { System.out.println("织入前置增强,横切逻辑code"); } }
配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 使用基于Schema的aop命名空间进行配置 --> <!-- 基于@AspectJ切面的驱动器 --> <aop:aspectj-autoproxy/> <!-- 目标Bean --> <bean id="smartSeller" class="com.xgj.aop.spring.advisor.aspectJ.function.execution.SmartSeller"/> <bean id="naiveWaiter" class="com.xgj.aop.spring.advisor.aspectJ.function.execution.NaiveWaiter"/> <!-- 使用了@AspectJ注解的切面类 --> <bean class="com.xgj.aop.spring.advisor.aspectJ.function.execution.ExecutionPublicAspect"/> </beans>
测试类
package com.xgj.aop.spring.advisor.aspectJ.function.execution; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * * * @ClassName: ExecutionPublicAspectTest * * @Description: execution(public * *(..)) 测试类 * * @author: Mr.Yang * * @date: 2017年8月27日 下午1:52:25 */ public class ExecutionPublicAspectTest { @Test public void test() { ApplicationContext ctx = new ClassPathXmlApplicationContext( "com/xgj/aop/spring/advisor/aspectJ/function/execution/conf-execution.xml"); SmartSeller smartSeller = (SmartSeller) ctx.getBean("smartSeller"); // sell方法是public,会织入前置增强中的横切逻辑 smartSeller.sell("bread"); // smileTo方法是protec,不会织入前置增强中的横切逻辑 smartSeller.smileTo("XiaoGongJiang"); NaiveWaiter naiveWaiter = (NaiveWaiter) ctx.getBean("naiveWaiter"); // greetTo方法是public,会织入前置增强中的横切逻辑 naiveWaiter.greetTo("XiaoGongJiang"); } }
运行结果
2017-08-29 00:00:39,395 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24b9371e: startup date [Tue Aug 29 00:00:39 BOT 2017]; root of context hierarchy 2017-08-29 00:00:39,514 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/execution/conf-execution.xml] 织入前置增强,横切逻辑code SmartSeller sells bread SmartSeller simles to XiaoGongJiang 织入前置增强,横切逻辑code NaiveWaiter greet to XiaoGongJiang