文章目录
- 一、AOP术语
- 1、通知(advice)
- 2、连接点(join point)
- 3、切点(point cut)
- 4、切面(aspect)
- 5、引入(introduction)
- 6、织入(weaving)
- 二、指示器
- 三、编码使用
- 1、execution+args
- 2、使用自定义注解@annotation
- 3、@winthin、winthin
- 4、@args
- 5、this
- 6、target、@target
- 7、bean
- 四、通知参数
一、AOP术语
1、通知(advice)
切面的工作被称为通知。通知定义了切面是什么以及何时使用。除了描述切面要完成的工作,通知还定义了何时执行这个工作。
Spring切面可以应用五种类型的通知:
- 前置通知(before):在目标方法被调用之前调用的通知;
- 后置通知(after):在目标方法成功执行之后调用,此时不会关心方法的返回是什么;
- 返回通知(after-returning):在目标方法成功执行之后调用;
- 异常通知(after-throwing):在目标方法抛出异常后调用通知;
- 环绕通知(around):通知包裹了目标方法,在目标方法调用之前和之后执行自定义行为,可以决定是否执行目标方法。
2、连接点(join point)
就是指spring允许你使用通知的地方
3、切点(point cut)
切点定义何时使用通知。切点的定义会匹配通知所要织入的一个或多个连接点。可以动态的决定是否使用通知
4、切面(aspect)
切面是切点和通知的结合。
5、引入(introduction)
引入允许我们向目标类添加新的方法和属性,在不修改现有类的情况下,让他们具有新的行为和状态
6、织入(weaving)
织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多少个点可以织入:
- 编译期:切面在目标类的编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的
- 类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该类的字节码。AspectJ5的加载时织入(load-time weaving,LTW)就是支持这种方式
- 运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP会为目标类对象动态的创建一个代理对象。Spring AOP就是以这种方式。
二、指示器
Spring借助AspectJ的切点表达式语言来定义Spring切面
- args():限制连接点匹配参数为指定类型的执行方法
- @args():限制连接点由指定注解标注的执行方法,支持只有一个入参,且参数类持有指定注解
- execution():用于匹配是连接点的执行方法
- this():限制连接点匹配AOP代理的bean引用为指定类型的类
- target():限制连接点匹配对象为指定类型的类
- @target():限制连接点匹配特定的目标对象,要有指定的注解
- within():限制连接点匹配指定的类型
- @within():限制连接点匹配指定注解所标注的类型
- @annotation():限制匹配带有指定注解的连接点
三、编码使用
1、execution+args
定义一个重载的三个方法,用于验证args
@Service("aopDemo1Service")
public class AopDemo1ServiceImpl implements IAopDemoService {
@Override
public String getDemo() {
System.out.println("demo1 start..............");
System.out.println("我是没有入参的demo");
System.out.println("demo1 end..............");
return "no param!";
}
@Override
public String getDemo(String arg1) {
System.out.println("demo1 start..............");
System.out.println("我是有一个入参的demo,入参是:" + arg1);
System.out.println("demo1 end..............");
return "one param!";
}
@Override
public String getDemo(int arg1, String arg2) {
System.out.println("demo1 start..............");
System.out.println("我是有两个入参的demo,第一个参数:" + arg1 + "\n第二个参数:" + arg2);
System.out.println("demo1 end..............");
return "two params!";
}
}
切面配置
@Aspect
@Component
public class AopConfigDemo {
@Pointcut("execution(* com.wfs.springboot.aop.*.getDemo(..))")
public void pointCut() {
}
/**
* args 用于匹配到第一个参数为Integer、第二个参数为String的连接点
* @param joinPoint
* @param arg1
* @param arg2
*/
@Around(value = "pointCut() && args(arg1,arg2)")
public void around(ProceedingJoinPoint joinPoint, Integer arg1,String arg2) {
System.out.println("aop start................");
try {
Object proceed = joinPoint.proceed();
System.out.println("目标方法返回值:" + proceed);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("aop end................");
}
}
2、使用自定义注解@annotation
在类上和方法上加上注解
@Service("aopDemo2Service")
@AopAnnotation
public class AopDemo2ServiceImpl implements IAopDemoService{
@Override
@AopAnnotation
public String getDemo() {
System.out.println("demo2 start..............");
System.out.println("我是没有入参的demo");
System.out.println("demo2 end..............");
return "no param!";
}
@Override
public String getDemo(String arg) {
System.out.println("demo2 start..............");
System.out.println("我是有一个入参的demo,入参是:" + arg);
System.out.println("demo2 end..............");
return "one param!";
}
@Override
public String getDemo(int arg1, String arg2) {
System.out.println("demo2 start..............");
System.out.println("我是有两个入参的demo,第一个参数:" + arg1 + "\n第二个参数:" + arg2);
System.out.println("demo2 end..............");
return "two params!";
}
aop配置
/**
* 只有方法上有注解才会使用切面
*/
@Pointcut("@annotation(com.wfs.springboot.annotation.AopAnnotation)")
public void pointCut() {
}
/**
* args 用于匹配到第一个参数为Integer、第二个参数为String的连接点
* @param joinPoint
*/
@Around(value = "pointCut()")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("aop start................");
try {
Object proceed = joinPoint.proceed();
System.out.println("目标方法返回值:" + proceed);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("aop end................");
}
3、@winthin、winthin
/**
* 使用@within 当前注解的类所有方法都会被织入
*/
@Pointcut("@within(com.wfs.springboot.annotation.AopAnnotation)")
public void pointCut() {
}
/**
* IAopDemoService类型及子类型的任何方法
*/
@Pointcut("within(com.wfs.springboot.aop.IAopDemoService+)")
public void pointCut() {
}
within支持表达式,类似execution
4、@args
仅支持只有一个入参的方法,并且参数类上必须持有定义的注解
aop配置
@Around(value = "pointCut() && @args(com.wfs.springboot.annotation.AopAnnotation)")
public void around(ProceedingJoinPoint joinPoint) {
System.out.println("aop start................");
try {
Object proceed = joinPoint.proceed();
System.out.println("目标方法返回值:" + proceed);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("aop end................");
}
入参类
@Data
@AopAnnotation
public class User {
private String name;
private SexEnum sex;
}
调用方法
@Override
public void getDemo(User user) {
System.out.println("我有带注解的入参");
}
5、this
只支持全限定名,不支持通配符;是对代理对象类型的匹配所以包括接口类型也匹配
当前目标对象实现了IAopDemoService接口的任何方法
@Pointcut("this(com.wfs.springboot.aop.IAopDemoService)")
public void pointCut() {
}
6、target、@target
只支持全限定名,不支持通配符;是对目标对象类型的匹配所以不包括接口类型匹配
@Pointcut("target(com.wfs.springboot.aop.AopDemo1ServiceImpl)")
public void pointCut() {
}
@Pointcut("within(com.wfs.springboot.aop.IAopDemoService+) && @target(com.wfs.springboot.annotation.AopAnnotation)")
public void pointCut() {
}
@target不能单独使用,启动会报错
7、bean
支持通配符
/**
* 表示bean的id或者名称为aopDemo1Service
*/
@Pointcut("bean(aopDemo1Service)")
public void pointCut() {
}
四、通知参数
public interface JoinPoint {
// 连接点的信息execution(String com.wfs.springboot.aop.AopDemo1ServiceImpl.getDemo(String))
String toString();
//连接点简要信息 execution(AopDemo1ServiceImpl.getDemo(..))
String toShortString();
//连接点详细信息execution(public java.lang.String com.wfs.springboot.aop.AopDemo1ServiceImpl.getDemo(java.lang.String))
String toLongString();
//返回代理对象
Object getThis();
//返回目标对象
Object getTarget();
// 返回目标参数
Object[] getArgs();
// 返回当前连接点的签名
Signature getSignature();
// 返回连接点在类文件中的位置
SourceLocation getSourceLocation();
//连接点类型 method-execution
String getKind();
// 返回连接点静态部分
JoinPoint.StaticPart getStaticPart();
public interface Signature {
//String com.wfs.springboot.aop.AopDemo1ServiceImpl.getDemo(int,String)
String toString();
//AopDemo1ServiceImpl.getDemo(..)
String toShortString();
//public java.lang.String com.wfs.springboot.aop.AopDemo1ServiceImpl.getDemo(int,java.lang.String)
String toLongString();
// 方法名 getDemo
String getName();
// 表示修饰符 1
int getModifiers();
// 目标类
Class getDeclaringType();
// 目标类全限定名
String getDeclaringTypeName();
}