1.AOP基本概念
切面(Aspect):通知(advice)和切入点(pointcut)共同组成了切面(aspect)
切入点(Pointcut):匹配join point的谓词,切面切向哪里,某个类或者某一层包路径
连接点(Joinpoint):aop拦截的类或者方法,例如方法被调用时、异常被抛出时。(在Spring中,所有的方法都可以认为是joinpoint,但是我们不希望所有的方法都添加Advice,而pointcut的作用就是提供一组规则来匹配joinpoint,给满足规则的joinpoint添加Advice。)
通知(Advice):切面何时使用,即注有@Around、@Before、@After等注解的方法
目标对象(Target Object):被通知的对象
AOP代理(AOP Proxy): AOP的代理有两种,一种是JDK动态代理,一种是CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理;反之,采用CGLIB代理
Joinpoint和Pointcut区别:在Spring AOP中,所有的方法执行都是joinpoint,而pointcut是一个描述信息,它修饰的是joinpoint,通过pointcut可以确定哪些jointpoint可以被Advice。
2.通知(Advice)类型说明
@Around:环绕通知,包围一个连接点的通知,可以在核心方法前后完成自定义的行为。这是最常用最重要的。这个注解需要传入参数ProceedingJoinPoint pjp,决定是否进入核心方法—-**调用pjp.proceed();**如果不调的话将不进入核心方法!
@Before:前通知,核心代码执行前通知
@After:后通知,连接点执行退出时通知(不论正常返回还是异常退出)
@AfterReturning:返回后通知,正常返回后通知
@AfterThrowing:抛出异常后通知,抛出异常时通知
注意:除了@Around传的参数是ProceedingJoinPoint pjp外,其它都是传的JoinPoint jp,也就是说能控制是否进入核心代码的只有Around,因为aop走到核心代码就是通过调用ProceedingJoinPoint的proceed()方法,而JoinPoint没有这个方法。
3.使用注解声明切面
代码中的中文只是为了便于描述和理解,实际情况中不能使用中文!!!!
目标对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14//Banana组件
public class Banana {
public void 摔跤() {
//异常通知
//int i = 1;
//i=i/0;
System.out.println("摔跤");
}
public String 跳舞() {
return "我还要跳舞";
}
}定义切面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46//表明是一个切面
//表明是一个组件
public class Van {
//定义公共切点,这样不用以后每一次都写一遍 切入到Banana摔跤方法
public void poincut() {
}
//前置通知 在Banan摔跤之前说FQ
public void 前置sayFQ() {
System.out.println("前置FQ");
}
//后置通知 在Banana摔跤之后说FQ
public void 后置sayFQ() {
System.out.println("后置FQ");
}
//异常通知 Banana 摔跤发生异常说FQ 比如没体力
public void 异常sayFQ() {
System.out.println("异常FQ");
}
//返回后通知 Van想知道Banana跳舞之后在干啥 Van不知道,所以Object
public void 返回通知sayFQ(Object rvt) {
System.out.println("返回通知FQ,发现蕉说" + rvt.toString());
}
//环绕通知 Van在Banana摔跤之前之后都说FQ
public void 环绕sayFQ(ProceedingJoinPoint joinPoint) {
try {
System.out.println("前面FQ");
joinPoint.proceed();//执行方法
System.out.println("后面FQ");
} catch (Throwable throwable) {
System.out.println("异常FQ");
throwable.printStackTrace();
}
}装配
1
2
3
4
5
6//相当于一个xml配置文件
//表示开启AOP代理自动配置
//扫描com.yoyiyi.java 注解
public class GuiChuConfig { //配置
}
4.在XML文件中声明切面
==================================================================================================== aop配置元素 用途 <aop:advisor> 定义AOP通知器 <aop:after> 定义AOP后置通知(不管被通知的方法是否执行成功) <aop:after-returning> 定义aop返回通知 <aop:after-throwing> 定义aop异常通知 <aop:around> 定义aop环绕通知 <aop:aspect> 定义一个切面 <aop:aspectj-autoproxy> 启用@Aspect注解驱动的切面 <aop:before> 定义一个AOP前置通知 <aop:config> 顶层的AOP配置元素.大多数的<aop:*>元素必须包含在<aop:config>元素内. <aop:declare-parents> 以透明的方式为被通知的对象引入额外的接口 <aop:pointcut> 定义一个切点 =====================================================================================================
切面目标对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14//Banana组件
public class Banana {
public void 摔跤() {
//异常通知
//int i = 1;
//i=i/0;
System.out.println("摔跤");
}
public String 跳舞() {
return "我还要跳舞";
}
}切面类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36//表明是一个切面
//表明是一个组件
public class Van {
//前置通知 在Banan摔跤之前说FQ
public void 前置sayFQ() {
System.out.println("前置FQ");
}
//后置通知 在Banana摔跤之后说FQ
public void 后置sayFQ() {
System.out.println("后置FQ");
}
//异常通知 Banana 摔跤发生异常说FQ 比如没体力
public void 异常sayFQ() {
System.out.println("异常FQ");
}
//返回后通知 Van想知道Banana跳舞之后在干啥 Van不知道,所以Object
public void 返回通知sayFQ(Object rvt) {
System.out.println("返回通知FQ,发现蕉说" + rvt.toString());
}
//环绕通知 Van在Banana摔跤之前之后都说FQ
public void 环绕sayFQ(ProceedingJoinPoint joinPoint) {
try {
System.out.println("前面FQ");
joinPoint.proceed();//执行方法
System.out.println("后面FQ");
} catch (Throwable throwable) {
System.out.println("异常FQ");
throwable.printStackTrace();
}
}XML配置
1
2
3
4
5
6
7
8
9<aop:aspect ref="animalXmlAspect">
<aop:pointcut id="run" expression="execution(* com.yoyiyi.java.Banana.摔跤())"/>
<aop:before pointcut-ref="run" method="前置sayFQ"/>
<aop:after pointcut-ref="run" method="后置sayFQ"/>
<aop:after-returning pointcut-ref="run" method="返回通知sayFQ"/>
<aop:after-throwing pointcut-ref="run" method="异常sayFQ"/>
<aop:around pointcut-ref="run" method="环绕sayFQ"/>
</aop:aspect>