一 .切入点表达式语法
①作用
②语法细节
用
*
号代替
“
权限修饰符
”
和
“
返回值
”
部分表示
“
权限修饰符
”
和
“
返回值
”
不限
在包名的部分,一个
“*”
号只能代表包的层次结构中的一层,表示这一层是任意的。
例如:
*.Hello
匹配
com.Hello
,不匹配
com.atguigu.Hello
在包名的部分,使用
“*..”
表示包名任意、包的层次深度任意
在类名的部分,类名部分整体用
*
号代替,表示类名任意
在类名的部分,可以使用
*
号代替类名的一部分
例如:
*Service
匹配所有名称以
Service
结尾的类或接口
在方法名部分,可以使用
*
号表示方法名任意
在方法名部分,可以使用
*
号代替方法名的一部分
例如:
*Operation
匹配所有方法名以
Operation
结尾的方法
在方法参数列表部分,使用
(..)
表示参数列表任意
在方法参数列表部分,使用
(int,..)
表示参数列表以一个
int
类型的参数开头
在方法参数列表部分,基本数据类型和对应的包装类型是不一样的
切入点表达式中使用
int
和实际方法中
Integer
是不匹配的
在方法返回值部分,如果想要明确指定一个返回值类型,那么必须同时写明权限修饰符
例如:
execution(public int
..
Service.*(.., int))
正确
例如:
execution(* int
..
Service.*(.., int))
错误
![](https://img-blog.csdnimg.cn/91a4971c01c94f279e1b0f59491ac05a.png)
③ 具体用法
切点表达式
/*1、在切面中,需要通过指定的注解将方法标识为通知方法
* @Before:前置通知,在目标对象方法执行之前执行
*2、切入点表达式:设置在标识通知的注解的value属性中
* execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int)
* execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..)
* 第一个*表示任意的访问修饰符和返回值类型
* 第二个*表示类中任意的方法
* ..表示任意的参数列表
* 类的地方也可以使用*,表示包下所有的类
* */
@Component
@Aspect //将当前组件标识为切面
public class LoggerAspect {
@Before("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")
//@Before("execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int))")
public void beforeAdviceMethod() {
System.out.println("LoggerAspect,前置通知");
}
}
测试:
public class AOPByAnnotationTest {
@Test
public void testAOPByAnnotation(){
//获取IOC容器
ApplicationContext ioc = new ClassPathXmlApplicationContext("aop-annotation.xml");
//获取目标对象
// CalculatorImpl calculator = ioc.getBean(CalculatorImpl.class);
//获取代理对象
Calculator calculator = ioc.getBean(Calculator.class);
calculator.sub(10, 1);
}
}
获取连接点信息
/*1、在切面中,需要通过指定的注解将方法标识为通知方法
* @Before:前置通知,在目标对象方法执行之前执行
*2、切入点表达式:设置在标识通知的注解的value属性中
* execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int)
* execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..)
* 第一个*表示任意的访问修饰符和返回值类型
* 第二个*表示类中任意的方法
* ..表示任意的参数列表
* 类的地方也可以使用*,表示包下所有的类
* */
@Component
@Aspect //将当前组件标识为切面
public class LoggerAspect {
@Before("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")
//@Before("execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int))")
public void beforeAdviceMethod() {
System.out.println("LoggerAspect,前置通知");
}
}
我们之前在动态代理里面 我们在前置通知的位置 也就是在目标对象的方法执行之前
System.out.println("LoggerAspect,前置通知");输出的是调用方法的方法名 和参数列表
用了前置通知之后 不知道应该如何获取 还没有动态代理实现的功能多 我们连连接点的信息都获取不到 也就是说我们要加入的通知的方法的一些信息 我们都获取不到
那我们获取到呢
加入JoinPoint joinPoint 帮助我们获取连接点信息 换句话说 切点表达式定位的是哪个方法 那我们JoinPoint joinPoint 表示的是哪个方法的信息
package com.atguigu.spring.aop.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 1、在切面中,需要通过指定的注解将方法标识为通知方法
* @Before:前置通知,在目标对象方法执行之前执行
*
* 2、切入点表达式:设置在标识通知的注解的value属性中
* execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int)
* execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..)
* 第一个*表示任意的访问修饰符和返回值类型
* 第二个*表示类中任意的方法
* ..表示任意的参数列表
* 类的地方也可以使用*,表示包下所有的类
*
* 3、获取连接点的信息
* 在通知方法的参数位置,设置JoinPoint类型的参数,就可以获取连接点所对应方法的信息
* //获取连接点所对应方法的签名信息
* Signature signature = joinPoint.getSignature();
* //获取连接点所对应方法的参数
* Object[] args = joinPoint.getArgs();
*/
@Component
@Aspect //将当前组件标识为切面
public class LoggerAspect {
@Before("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")
//@Before("execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int))")
public void beforeAdviceMethod(JoinPoint joinPoint) {
//获取连接点所对应方法的签名信息
Signature signature = joinPoint.getSignature();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("LoggerAspect,方法:"+signature.getName()+",参数:"+ Arrays.toString(args));
}
}
重用切入点表达式
/**
* Date:2022/7/4
* Author:ybc
* Description:
* 1、在切面中,需要通过指定的注解将方法标识为通知方法
* @Before:前置通知,在目标对象方法执行之前执行
* @After:后置通知,在目标对象方法的finally字句中执行
*
* 2、切入点表达式:设置在标识通知的注解的value属性中
* execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int)
* execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..)
* 第一个*表示任意的访问修饰符和返回值类型
* 第二个*表示类中任意的方法
* ..表示任意的参数列表
* 类的地方也可以使用*,表示包下所有的类
* 3、重用切入点表达式
* //@Pointcut声明一个公共的切入点表达式
* @Pointcut("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")
* public void pointCut(){}
* 使用方式:@Before("pointCut()")
*
* 4、获取连接点的信息
* 在通知方法的参数位置,设置JoinPoint类型的参数,就可以获取连接点所对应方法的信息
* //获取连接点所对应方法的签名信息
* Signature signature = joinPoint.getSignature();
* //获取连接点所对应方法的参数
* Object[] args = joinPoint.getArgs();
*
*/
@Component
@Aspect //将当前组件标识为切面
public class LoggerAspect {
@Pointcut("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")
public void pointCut(){}
//@Before("execution(public int com.atguigu.spring.aop.annotation.CalculatorImpl.add(int, int))")
//@Before("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")
@Before("pointCut()")
public void beforeAdviceMethod(JoinPoint joinPoint) {
//获取连接点所对应方法的签名信息
Signature signature = joinPoint.getSignature();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("LoggerAspect,方法:"+signature.getName()+",参数:"+ Arrays.toString(args));
}
@After("pointCut()")
public void afterAdviceMethod(){
}
}