@AspectJ切点函数详解
相关文章链接:
观前提示:
本文所使用的IDEA版本为ultimate 2019.1,JDK版本为1.8.0_141,Tomcat版本为9.0.12。
类别 | 函数 | 入参 | 说明 |
---|---|---|---|
方法切点函数 | execution() | 方法匹配模式串 | 满足某一匹配模式的所有目标类方法连接点 |
方法切点函数 | @annotation() | 方法注解类名 | 标注了特定注解的目标方法连接点 |
方法入参切点函数 | args() | 类名 | 定位于入参为特定类型的方法的连接点 |
方法入参切点函数 | @args() | 类型注解类名 | 定位于被特定注解所标注入参的方法的连接点 |
目标类切点函数 | within() | 类名匹配串 | 定位于特定作用域下的所有连接点 |
目标类切点函数 | target() | 类名 | 定位于指定类及其子类 |
目标类切点函数 | @within() | 类型注解类名 | 定位与标注了特定注解的类及其实现类 |
目标类切点函数 | @target() | 类型注解类名 | 定位于标注了特定注解的目标类里所有方法 |
代理类切点函数 | this() | 类名 | 代理类按类型匹配与指定类,则被代理的目标类的所有连接点都匹配与该切点 |
1 方法切点函数
1.1 execution()
语法表达式如下:
execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
其中:返回类型模式、方法名模式、参数模式是必选项
1.1.1 通过方法签名定义切点
execution(public * *(..))
匹配所有目标类的public方法。第一个 * 代表任意返回类型,第二个 * 代表方法名,而 . . 代表任意入参的方法。
execution(public String *(..))
匹配所有目标类修饰符为public,返回参数类型为String的方法。第一个 * 代表方法名,而 . . 代表任意入参的方法。
1.1.2 通过类定义切点
execution(* com.example.UserService.*(..))
匹配com.example.UserService接口中所有方法。第一个 * 代表任意返回类型,第二个 * 代表com.example.UserService中的所有方法,. . 代表任意入参的方法。
1.1.3 通过类包定义切点
execution(* com.example.*(..))
匹配com.example包下的所有方法。
execution(* com..*(..))
匹配com包及子孙包下所有方法。
类名模式 | 说明 |
---|---|
.* | 包中所有的类,不包括子孙包下的类 |
. .* | 包及子孙包下所有的类 |
1.1.4 通过方法入参定义切点
execution(* com.example.UserService.insert(String,int))
匹配com.example.UserService包下的insert(String,int)方法。
execution(* com.example.UserService.insert(String, *))
匹配com.example.UserService包下的insert()方法,其中第一个参数类型为String,第二个参数类型为任意参数类型。
execution(* com.example.UserService.insert(String,..))
匹配com.example.UserService包下的insert()方法,其中第一个参数类型为String,后面的参数类型为任意类型且个数不限。
execution(* com.example.UserService.insert(Object+))
匹配com.example.UserService包下的insert()方法,方法只有一个入参,为Object类型或Object类型的子类。
类名模式 | 说明 |
---|---|
* | 表示任意类型的参数 |
. . | 表示任意个数任意类型的参数 |
1.1.5 例子
这里给出的例子为通过类定义切点,其他定义切点方式可修改LogAop.java中的注解@Pointcut("execution(* testAop.UserService.*(..))")
即可
目录结构
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<bean id="userService" class="testExecution.UserService"/>
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="testExecution"></context:component-scan>
<!-- 开启aop注解方式,此步骤不能少,这样java类中的aop注解才会生效 -->
<aop:aspectj-autoproxy/>
</beans>
UserService.java
package testExecution;
public class UserService {
public void insertUser() {
System.out.println("插入用户成功");
}
public boolean updateUser() {
System.out.println("更新用户成功");
return true;
}
}
LogAop.java
package testExecution;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAop {
@Pointcut("execution(* testExecution.UserService.*(..))")
public void ponitCut() {
}
@Before("ponitCut()")
public void beforeAdvice() {
System.out.println("beforeAdvice");
}
@After("ponitCut()")
public void afterAdvice() {
System.out.println("afterAdvice");
}
//环绕通知。注意要有ProceedingJoinPoint参数传入
@Around("ponitCut()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("注解类型环绕通知..环绕前");
pjp.proceed();//执行方法
System.out.println("注解类型环绕通知..环绕后");
}
}
TestAop.java
package testExecution;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAop {
private ClassPathXmlApplicationContext ac;
@Before
public void before() {
ac = new ClassPathXmlApplicationContext("testExecution/applicationContext.xml");
}
@Test
public void test() {
try {
UserService userService = (UserService) ac.getBean("userService");
userService.insertUser();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果
1.2 @annotation()
用于标注了某个注解的目标切点。
1.2.1 例子
目录结构如下:
自定义注解 SystemLog.java
package testAnnotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) //注解保留期限
@Target(ElementType.METHOD) //注解目标类型
@Documented
public @interface SystemLog {
int LogType() default Constants.LogType.Empty;
}
注:@Rentention,@Target,@Document注解描述可参考文章:java元注解
常量类Constants.java
package testAnnotation;
public class Constants {
public static class LogType {
public static final int Empty = 0;//默认为0
public static final int Insert = 1;//插入操作日志
public static final int Update = 2;//更新操作日志
}
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<bean id="userService" class="testAnnotation.UserService"/>
<!-- 配置自动扫描的包 -->
<context:component-scan base-package="testAnnotation"></context:component-scan>
<!-- 开启aop注解方式,此步骤不能少,这样java类中的aop注解才会生效 -->
<aop:aspectj-autoproxy/>
</beans>
UserService.java
package testAnnotation;
public class UserService {
@SystemLog
public void defaultMethod(String param){
System.out.println("默认方法,入参为:" + param);
}
@SystemLog(LogType = Constants.LogType.Insert)
public void insertUser() {
System.out.println("插入用户成功");
}
@SystemLog(LogType = Constants.LogType.Update)
public boolean updateUser() {
System.out.println("更新用户成功");
return true;
}
}
LogAop.java
package testAnnotation;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation