AOP-03
7.AOP-切入表达式
7.1切入表达式的具体使用
1.切入表达式的作用:
通过表达式的方式定义一个或多个具体的连接点。
2.语法细节:
(1)切入表达式的语法格式:
execution([权限修饰符] [返回值类型] [简单类名/全类名] [方法名]([参数列表])
若目标类、接口与该切面类在用同一个包中,可以省略包名,只写简单类名
(2)举例说明:
例子1:
表达式:execution(* com.sina.spring.ArithmeticCalculator.*(..))
含义:ArithmeticCalculator.* :接口中声明的所有方法。第一个 *
代表任意修饰符和任意返回值。 第二个 *
代表任意方法。..
代表匹配任意数量和任意类型的参数,若目标类、接口与该切面类在用同一个包中,可以省略包名。
例子2:
表达式:execution(public * ArithmeticCalculator.*(..))
含义:ArithmeticCalculator 接口中的所有公有方法
例子3:
表达式:execution(public double ArithmeticCalculator.*(..))
含义:ArithmeticCalculator 接口中返回 double 类型数值的方法
例子4:
表达式:execution(public double ArithmeticCalculator.*(double, ..))
含义:第一个参数为double 类型的方法。..
匹配任意数量、任意类型的参数。
例子5:
表达式:execution(public double ArithmeticCalculator.*(double, double))
含义:参数类型为double ,double 类型的方法。
(3)在AspectJ中,切入点表达式可以通过 &&
或者 ||
或者 !
等操作符结合起来
例子:
表达式:execution(* *.add(int, ..))|| exexution(* *.sub(int, ..))
含义:任意类中第一个参数为 int 类型的 add 方法或 sub 方法
7.2注意事项和细节
-
切入表达式可以指向(实现了接口的)类的方法,这时切入表达式会对该类/对象生效
-
切入表达式也可以指向接口的方法,这时切入表达式会对实现了接口的类/对象生效
-
切入表达式可以对没有实现接口的类进行切入。
这涉及到CGlib动态代理:动态代理jdk的Proxy与spring的CGlib
-
两个动态代理的区别:
-
JDK动态代理是面向接口的,只能增强实现类中接口中存在的方法。CGlib是面向父类的,可以增强父类的所有方法
-
JDK得到的对象是JDK代理对象实例,而CGlib得到的对象是被代理对象的子类
-
静态代理例子:
一个普通类Car:
package com.li.aop.hw;
import org.springframework.stereotype.Component;
/**
* @author 李
* @version 1.0
*/
@Component
public class Car {
public void run() {
System.out.println("小汽车在running...");
}
}
MyAspect切面类:
package com.li.aop.hw;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @author 李
* @version 1.0
* 切面类
*/
@Component
@Aspect
public class MyAspect {
//CGlib
//给没有实现接口的一个普通类设置前置通知,其他通知亦可以设置
@Before(value = "execution(public void Car.run())")
public void ok(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("MyAspect前置通知ok()-目标方法-" + methodName +
" 参数-" + Arrays.toString(joinPoint.getArgs()));
}
}
测试类:
package com.li.aop.hw;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.Test;
/**
* @author 李
* @version 1.0
*/
public class UsbTest {
@Test
public void UsbAspectTest() {
ApplicationContext ioc = new ClassPathXmlApplicationContext("beans08.xml");
//carProxy是 被代理对象的子类
Car carProxy = ioc.getBean(Car.class);
System.out.println("carProxy的实际运行类型=" + carProxy.getClass());
carProxy.run();
}
}
测试结果:
8.AOP-JoinPoint
在切面类的通知方法中,可以通过 JoinPoint对象获取到目标方法的一系列信息:
JoinPoint对象的方法 | 释义 |
---|---|
getSignature().getName() | 获取目标方法名 |
getSignature().getDeclaringType().getSimpleName() | 获取目标方法所属类的简单类名 |
getSignature().getDeclaringTypeName() | 获取目标方法所属类的全类名 |
getSignature().getModifiers() | 获取目标方法声明类型(public/private/protected) |
getArgs() | 获取传入目标方法的参数,返回一个数组 |
getTarget() | 获取被代理的对象 |
getThis() | 获取代理对象自己 |
9.AOP-返回通知获取结果
- 在返回通知 @AfterReturning 中,可以获取目标方法返回的结果。
我们在 @AfterReturning (返回通知)的注解源码中可以看到有一个returnin