一、 Spring AOP 概念
其实AOP就是要将我们Aspect中的Pointcut和Target Object中的JointPoint动态的连接起来,同时我们通过Advice指明Pointcut执行的一个时机。这是个人理解
AOP相关名词解释
名词 | 解释 |
---|---|
Ascpect | 横跨多个类的模块化关注点 |
Pointcut | 指明Aspect和哪个连接点进行连接 |
Advice | Advice是单一横切关注点的逻辑的载体,他代表将会织入到JointPoint的横切逻辑;也可以说是Aspect的具体的方法 |
Target Object | Aspect关注的对象 |
Joint Point | 表示目标对象执行的方法 |
Advice 的分类
Adice种类 | 解释 |
---|---|
Before Advice | 在Joint Point(执行方法)之前执行Pointcut方法) |
After return Advice | 在 Joint Point(执行方法)正常退出时执行Pointcut |
After throwing Advice | 在Joint Point(执行方法)抛出异常退出时执行Pointcut |
After Advice | 在Joint Point(执行方法)退出(不管是正常退出还是抛异常退出)时执行Pointcut |
Around Advice | 在Joint Point(执行方法)被调用之前和之后都会执行Pointcut |
二、注解的方式声明一个切面
2.1、切面中涉及的注解
注解 | 声明地点 | 使用方式 |
---|---|---|
@Aspect | 声明在类上 | 表明这时一个Aspect |
@Pointcut | 声明在Pointcut(Aspect的方法)上 | 指明和哪个Target Object 的Joint Point进行连接 |
@Before | 声明注解在Aspect的方法上 | 表明在Joint Point(执行方法)之前执行Aspect的方法 |
@AfterReturning | 声明注解在Aspect的方法上 | 表明在 Joint Point(执行方法)正常退出时执行Aspect的方法 |
@AfterThrowing | 声明注解在Aspect的方法上 | 表明在Joint Point(执行方法)抛出异常退出时执行执行Aspect的方法 |
@After | 声明注解在Aspect的方法上 | 表明在Joint Point(执行方法)被调用之前和之后都会执行执行Aspect的方法 |
2.2、声明一个Aspect
package com.zbt.day03;
import org.aspectj.lang.annotation.*;
@Aspect
public class AfterThrowingAspect {
}
在Spring上下文中配置Bean注入,因为Aspect也是一个类,需要使用注入的方式让Spring管理一个Bean
<aop:aspectj-autoproxy/>//开启Spring AOP自动代理功能
<bean id="audience" class="com.zbt.day01.Audience"></bean>
因为使用@AspectJ表示我们已经放弃了自动代理(auto-proxy)的方式,因此我们需要使用注解的方式@Component或者在Spring上下文中配置自动代理。
2.3、切点表达式
方法 | 描述 |
---|---|
execution(public * *(..)) | 执行那些方法为public的Joint Point |
execution(* set*(..)) | 执行那些方法名为set的Joint Point |
execution(* com.xyz.service.AccountService.*(..)) | 执行com.xyz.service.AccountService中所有的JointPoint(方法) |
execution(* com.xyz.service.* . *(..) | 执行com.xyz.service包中任何的JointPoint(方法) |
execution(* com.xyz.service..* . *(..)) | 执行com.xyz.service..* . *(..))包和其子包下面所有的JointPoint(方法) |
within(com.xyz.service.*) | 执行所有在com.xyz.service包中所有的JointPoint(方法) |
this(com.xyz.service.AccountService) | |
target(com.xyz.service.AccoutnService) | 执行实现了com.xyz.service.AccoutnService接口的所有的类的JointPoint(方法) |
args(java.io.Serializable) | 执行任何链接点参数只有一个,且指定参数类型为运行时Serializable(我们可以指定任意参数类型,只要是我们需要的) |
@target(org.springframework.transaction.annotation.Transactional) | 执行目标对象注解了@Transaction注解的方法 |
bean(tradeService) | |
bean(*Service) |
2.4、声明一个Advice
@Before
@Before("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
public void beforeJointPoint(){
System.out.println("在Joint Point执行前执行此方法");
}
@AfterThrowing
@AfterThrowing("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
public void printAbonormal(){
System.out.println("在Joint Point抛出异常后执行此方法");
}
@AfterReturning
@AfterReturning("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
public void printNormal(){
System.out.println("在Joint Point正常退出执行此方法");
}
@After
@After("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
public void print(){
System.out.println("不管Joint Point是正常退出还是异常退出都执行此方法");
}
@Round
示例
编写Aspect和Advice
package com.zbt.day03;
import org.aspectj.lang.annotation.*;
@Aspect
public class AfterThrowingAspect {
@Before("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
public void beforeJointPoint(){
System.out.println("在Joint Point执行前执行此方法");
}
@AfterThrowing("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
public void printAbonormal(){
System.out.println("在Joint Point抛出异常后执行此方法");
}
@AfterReturning("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
public void printNormal(){
System.out.println("在Joint Point正常退出执行此方法");
}
@After("execution(* com.zbt.day03.ThrowExceptionApp.division(..))")
public void print(){
System.out.println("不管Joint Point是正常退出还是异常退出都执行此方法");
}
}
编写Target Object和Joint Point(Target 中的方法)
package com.zbt.day03;
/**
* Created by luckyboy on 2018/8/15.
*/
public class ThrowExceptionApp {
public int division(int a,int b){
int i = 0;
try{
i = a/b;
}catch (Exception e){
throw e;
}
return i;
}
}
代码测试
package com.zbt.day03;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAdvice {
@Test
public void testPerformance(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationConfig.xml");
ThrowExceptionApp throwExceptionApp = context.getBean("throwExceptionApp",ThrowExceptionApp.class);
throwExceptionApp.division(1,1);
}
}