SpringBoot面向切面编程(AOP)
gitee地址:SpringBoot面向切面编程
1.目录结构
2.依赖
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.1.0.RELEASE</version>
</parent>
<dependencies>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--切面依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
3.service
public interface ExampleService {
String findAll(String name);
boolean save();
boolean update();
boolean delete();
}
import com.qq.annotation.Sign;
import com.qq.service.ExampleService;
import org.springframework.stereotype.Service;
/**
* @author 黔程似景
* @description 业务代码
* @date 2021/12/5 9:55
**/
@Service
public class ExampleServiceImpl implements ExampleService {
@Override
public String findAll(String name) {
System.out.println("---------------------所有数据-------------------------");
return name;
}
@Sign
@Override
public boolean save() {
System.out.println("---------------------保存成功-------------------------");
return true;
}
@Override
public boolean update() {
System.out.println("---------------------修改成功-------------------------");
return true;
}
@Override
public boolean delete() {
System.out.println("---------------------删除成功-------------------------");
return true;
}
}
4.注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Sign {
}
5.aop配置文件
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @author 黔程似景
* @description 切面类
* @date 2021/12/5 9:58
**/
@Aspect // 标注此类为切面类
@Component
public class AopConfig {
/**
* 切入点
*/
@Pointcut("@annotation(com.qq.annotation.Sign) || execution(* com.qq.service..*.find*(..))")
public void pointcut(){
}
/**
* 前置通知:在执行方法前执行
*/
@Before(value = "pointcut()")
public void before(JoinPoint joinPoint){
System.out.println("--------------前置通知-----------------");
Signature signature = joinPoint.getSignature();
System.out.println("获取方法:"+signature);
Object[] args = joinPoint.getArgs();
System.out.println("获取传入参数:"+Arrays.toString(args));
}
/**
* 异常通知:在执行方法出现异常时执行
*/
@AfterThrowing(value = "pointcut()")
public void afterThrow(JoinPoint joinPoint){
System.out.println("--------------异常通知------------------");
System.out.println("异常方法:"+joinPoint.getSignature());
}
/**
* 后置通知:在执行方法后执行,无论是否出现异常,则都会执行
*/
@After(value = "pointcut()")
public void after(){
System.out.println("---------------后置通知-----------------");
}
/**
* 最终通知:当出现异常,则不会执行
*/
@AfterReturning(value = "pointcut()" , returning = "result")
public void afterReturning(Object result){
System.out.println("目标方法返回值:"+result);
}
// /**
// * 环绕通知(包含前置通知,后置通知,异常通知,最终通知)
// * 执行顺序:前置通知--->后置通知(异常通知)--->最终通知
// * @param joinPoint
// * @return
// */
// @Around(value = "pointcut()")
// public Object around(ProceedingJoinPoint joinPoint) {
//
// Object rvt = null;//不改变参数
// try {
// System.out.println("----------------前置通知------------------");
// rvt = joinPoint.proceed();
Object rvt = jp.proceed(new String[] { "被改变的参数" });
// System.out.println("----------------后置通知------------------");
// } catch (Throwable throwable) {
// System.out.println("----------------异常通知------------------");
// throwable.printStackTrace();
// }finally {
// System.out.println("----------------最终通知------------------");
// }
//
// return rvt + " 新增的内容";
// }
}
6.启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AopApplication {
public static void main(String[] args) {
SpringApplication.run(AopApplication.class, args);
}
}
7.测试类
import com.qq.service.ExampleService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
/**
* @author 黔程似景
* @description 测试类
* @date 2021/12/5 10:03
**/
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestExampleService {
@Resource
public ExampleService exampleService;
/**
* 切面测试
*/
@Test
public void test() {
exampleService.findAll("法外狂徒");
System.out.println("\n\n\n");
exampleService.save();
System.out.println("\n\n\n");
exampleService.update();
}
}
8.执行结果
9.了解内容:切点函数于表达式语法
切入点函数 | 作用 |
---|---|
execution | 细粒度函数,精确到方法 |
within | 粗粒度,只能精确到类 |
bean | 粗粒度,精确到类,从容器中通过id获取对象 |
@annotation | 包含注解的所有类和方法 |
execution表达式语法
execution(* *(..))
匹配所有的类和方法
!execution(* save(..))
除了方法名是save的所有方法
方法参数设置:
() 没有参数
(*) 1个或多个参数
(..) 0个或多个参数
例如:find()----->无参方法
execution(* save(..)) || execution(* update(..))
匹配方法名是save或update的方法
within表达式语法
within(com.qq..*)
匹配包和子包中所有的类
bean表达式语法
bean(exampleService)
从容器中获取一个id为accountService的类中所有方法
bean(*Service)
从容器中获取所有Service的方法
注解表达式语法
@annotation(com.qq.annotation.Sign)
匹配包含注解的所有类和方法