1.什么是Aop
AOP:面向切面编程,相对于OOP面向对象编程
Spring的AOP的存在目的是为了解耦。AOP可以让一组类共享相同的行为。在OOP中只能继承和实现接口,且类继承只能单继承,阻碍更多行为添加到一组类上,AOP弥补了OOP的不足。
还有就是为了清晰的逻辑,让业务逻辑关注业务本身,不用去关心其它的事情,比如事务。
Spring的AOP是通过JDK的动态代理和CGLIB实现的。
2.Aop的术语
AOP 领域中的特性术语:
- 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
- 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
- 切点(PointCut): 可以插入增强处理的连接点。
- 切面(Aspect): 切面是通知和切点的结合。
- 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
- 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
2.注解
@Before
在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可
@AfterReturning
在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值
@AfterThrowing
主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名
来访问目标方法中所抛出的异常对象
@After
在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式
@Around
环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint
value |
指定要进行增强的实体 |
argNames |
增强方法的参数名 |
3.执行的顺序
around > before > around > after > afterReturning
4.用例
配置类
(1) 对方法
@Aspect
@Component
public class TransactionAop {
@Pointcut("execution(* com.jiuxian..service.*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void beginTransaction() {
System.out.println("before beginTransaction");
}
@After("pointcut()")
public void commit() {
System.out.println("after commit");
}
@AfterReturning("pointcut()", returning = "returnObject")
public void afterReturning(JoinPoint joinPoint, Object returnObject) {
System.out.println("afterReturning");
}
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("afterThrowing afterThrowing rollback");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
try {
System.out.println("around");
return joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
throw e;
} finally {
System.out.println("around");
}
}
}
(2) 对注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
String value() default "";
}
@Aspect
@Component
public class AnnotationAop {
@Around(value = "@annotation(log)", argNames = "joinPoint,log")
public Object around(ProceedingJoinPoint joinPoint, Log log) throws Throwable {
try {
System.out.println(log.value());
System.out.println("around");
return joinPoint.proceed();
} catch (Throwable throwable) {
throw throwable;
} finally {
System.out.println("around");
}
}
@Before("@annotation(com.jiuxian.annotation.Log)")
public void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Log log = method.getAnnotation(Log.class);
System.out.println("注解式拦截 " + log.value());
}
}
public interface UserService {
String save(String user);
void testAnnotationAop();
}
@Service
public class UserServiceImpl implements UserService {
@Override
public String save(String user) {
System.out.println("保存用户信息");
if ("a".equals(user)) {
throw new RuntimeException();
}
return user;
}
@Log(value = "test")
@Override
public void testAnnotationAop() {
System.out.println("testAnnotationAop");
}
}
5.maven导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
6.execution解释
例: execution(* com.jiuxian..service.*.*(..))
- execution 表达式的主体
- 第一个* 代表任意的返回值
- com.jiuxian aop所横切的包名
- 包后面.. 表示当前包及其子包
- 第二个* 表示类名,代表所有类
- .*(..) 表示任何方法,括号代表参数 .. 表示任意参数
例: execution(* com.jiuxian..service.*Service.add*(String))
表示:com.jiuxian 包及其子包下的service包下,类名以Service结尾,方法以add开头,参数类型为String的方法的切点。