目录
一、简介
二、什么是AspectJ
AOP 思想概述
AOP 实现方式
AOP 特性概念
切点指示器
通知类型
三、实现AOP的方式
四、配置说明
自定义注解作为切点
NeedCut
MyAop
GirlController
继承MethodInterceptor实现切面
MyMethodInterceptor
AopConfig
NeedCut 注解
GirlController
配置文件
一、简介
-
它不属于spring;
-
AspectJ是一个AOP的框架;
-
定义了AOP语法;
-
有一个专门的编译器用来生成遵守Java字节编码规范的Class文件
二、什么是AspectJ
AspectJ是使用面向切面的一个框架
它扩展了Java语言(它本身也是一种语言)
支持原生Java代码 有自己的编译器
将代码翻译成Java字节码文件
是为了方便编写AOP代码而出现的
使用AOP编程的三个重点 通知 切点 织入
AOP 思想概述
AOP(Aspect Oriented Programming)是一种面向切面的编程思想。面向切面编程是将程序抽象成各个切面,即解剖对象的内部,将那些影响了多个类的公共行为抽取到一个可重用模块里,减少系统的重复代码,降低模块间的耦合度,增强代码的可操作性和可维护性。
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理、增强处理。
AOP 实现方式
AOP 的初衷是,保证开发者不修改源代码的前提下,为系统中的业务组件添加某种通用功能。AOP 的本质是由 AOP 框架修改业务组件的源代码,达到增强功能的目的。按照 AOP 框架修改源代码的时机,可以将其分为两类:
-
静态 AOP 实现:AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。
-
动态 AOP 实现:AOP 框架在运行阶段动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。
AOP 特性概念
-
通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
-
连接点(Join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
-
切点(PointCut): 可以插入增强处理的连接点。
-
切面(Aspect): 切面是通知和切点的结合。
-
引入(Introduction):允许我们向现有的类添加新的方法或者属性。
-
织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的代理对象。
切点指示器
通知类型
三、实现AOP的方式
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Aspect
@Component
public class MyAOP {
// 定义切入点
@Pointcut("execution(* com.chensir.controller.*.*(..))")
public void point() {}
// 前置通知
@Before("point()")
public void before() {
System.out.println("前置通知");
}
// 后置通知 始终会执行
@After("point()")
public void after() {
System.out.println("后置通知");
}
// 环绕通知
@Around("point()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前");
Object result = pjp.proceed();
System.out.println("环绕后");
return result;
}
// 后置 发生异常时不会执行
@AfterReturning("point()")
public void returning() {
System.out.println("After returning 后置");
}
// 发生异常
@AfterThrowing("point()")
public void throwing() {
System.out.println("发生异常了");
}
}
四、配置说明
//定义切入点
//两种占位符
//* 代表的是一个单词,b* 代表的是以b开头的单词。 例如 bds
//.. 通配符 ,代表的是0个或者多个匹配项
//@Pointcut("execution(* com.chensir.service..*.*(..))") //com.chensir.service 下面以及子包所有类的所有方法
//@Pointcut("execution(* com.chensir.service..*.*(java.lang.String,..))") //com.chensir.service 下面以及子包所有类的,第一个参数是String类型的方法
//@Pointcut("execution(* com.chensir.service.*.*(..))") //com.chensir.service 下面所有类的所有方法
//execution(* com.bao.User.add(..)) com.bao.user类下面的add方法
//excution(* com.bao.user.*(..)) com.bao.user下的所用方法
//配置com.bao.User下的add()
execution(* com.bao.User.add(..))
//配置com.bao.User下的所有方法
execution(* com.bao.User.*(..))
//配置所有包下的所有方法
execution(**.*(..))
//配置所有包下的a开头方法
execution(* a*(..))
//配置com.service包下的所有类的所有方法
execution(* com.service.*.*(..)))
自定义注解作为切点
NeedCut
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedCut {
}
MyAop
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAop {
// 定义切入点
// @Pointcut("execution(* com.chensir.controller.*.*(..))")
@Pointcut("@annotation(com.chensir.annotation.NeedCut)")
public void point() {}
// 前置通知
@Before("point()")
public void before() {
System.out.println("---------前置通知--------");
}
// 后置通知 始终会执行
@After("point()")
public void after() {
System.out.println("----------后置通知-------");
}
// 环绕通知
@Around("point()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("-------环绕前----------");
Object result = pjp.proceed();
System.out.println("---------环绕后-----------");
return result;
}
// 后置 发生异常时不会执行
@AfterReturning("point()")
public void returning() {
System.out.println("------After returning 后置------------");
}
// 发生异常
@AfterThrowing("point()")
public void throwing() {
System.out.println("-------发生异常了----------");
}
}
GirlController
@RestController
@RequestMapping("/api")
public class GirlController {
@GetMapping("/kiss")
@NeedCut
public String kiss(){
return "么么哒";
}
@GetMapping("/kiss2")
public String kiss2(){
return "么么哒";
}
}
kiss使用了@NeedCut注解,调用时能够走aop拦截;而kiss2没有加@NeedCut注解,调用时不会走aop拦截
继承MethodInterceptor实现切面
MyMethodInterceptor
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;
@Slf4j
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取方法
Method method = invocation.getMethod();
//获取参数
Object[] arguments = invocation.getArguments();
//获取返回值
Object proceed = invocation.proceed();
log.info("方法:{},参数:{},返回值:{}", method.getName(), JSONUtil.toJsonStr(arguments), proceed);
return proceed;
}
}
AopConfig
import com.chensir.interceptor.MyMethodInterceptor;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
public class AopConfig {
@Value("${aop.MethodInterceptor.point}")
private String point;
@Bean
public AspectJExpressionPointcutAdvisor aspectJExpressionPointcutAdvisor(){
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setAdvice(new MyMethodInterceptor());
advisor.setExpression(point);
return advisor;
}
}
NeedCut 注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Deprecated
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedCut {
}
GirlController
@RestController
@RequestMapping("/api")
public class GirlController {
@GetMapping("/kiss")
@NeedCut
public String kiss(Integer id){
return "么么哒";
}
@GetMapping("/kiss2")
public String kiss2(){
return "么么哒";
}
}
配置文件
#aop.MethodInterceptor.point = execution(* com.chensir.controller.*.*(..))
# 使用注解方式
aop.MethodInterceptor.point = @annotation(com.chensir.annotation.NeedCut)