简介
本文介绍Spring(SpringBoot)的AOP的用法,以及其顺序的控制。
AOP的执行流程图
正常执行时的流程
代码抛异常时的流程
创建工程
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo_springaop-simple</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo_springaop-simple</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <!-- <exclusions>--> <!-- <exclusion>--> <!-- <groupId>org.junit.vintage</groupId>--> <!-- <artifactId>junit-vintage-engine</artifactId>--> <!-- </exclusion>--> <!-- </exclusions>--> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.20</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
公共代码
启动类
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoSpringaopSimpleApplication { public static void main(String[] args) { SpringApplication.run(DemoSpringaopSimpleApplication.class, args); } }
Entity
package com.example.demo.entity; import lombok.Data; @Data public class User { private Integer id; private String userName; private String note; }
Service
package com.example.demo.service; import com.example.demo.entity.User; public interface UserService { public void printUser(User user); }
package com.example.demo.service.impl; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Override public void printUser(User user) { if (user == null) { throw new RuntimeException("检查用户参数是否为空"); } System.out.print("id = " + user.getId()); System.out.print("\t userName = " + user.getUserName()); System.out.println("\t note = " + user.getNote()); } }
Controller
package com.example.demo.controller; import com.example.demo.annotation.OperationLog; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @RequestMapping("/user") @Controller public class UserController { @Autowired private UserService userService; @RequestMapping("/print") @ResponseBody public User testPrint(User user) { userService.printUser(user); return user; } @RequestMapping("/add") @ResponseBody @OperationLog(type = "添加", desc = "添加数据") public User testAdd(User user) { return user; } @RequestMapping("/update") @ResponseBody @OperationLog(type = "更新", desc = "更新数据") public User testUpdate(User user) { userService.printUser(user); return user; } }
AOP代码
代码
package com.example.demo.aspect; import com.example.demo.annotation.OperationLog; import com.example.demo.common.util.JsonUtil; import com.example.demo.entity.User; import com.sun.org.apache.regexp.internal.RE; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Aspect @Component // @Order(1) public class SimpleAspect { @Pointcut("execution(* com.example.demo.service.impl.UserServiceImpl.printUser(..))") // 多个切点时可指定优先级 // @Order(1) public void pointcut() { } @Before("pointcut()") public void before() { System.out.println("############################ SimpleAspect.before ############################"); } @Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("############################ SimpleAspect.around ############################"); MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); System.out.println("joinPoint.getTarget().toString() : " + joinPoint.getTarget().toString()); System.out.println("methodSignature.getName() : " + methodSignature.getName()); System.out.println("method.getName() : " + method.getName()); System.out.println("method.getReturnType().getName() : " + method.getReturnType().getName()); Object[] objects = joinPoint.getArgs(); System.out.println(JsonUtil.toJson(objects)); System.out.println("------------ SimpleAspect.around: proceed之前 ------------"); Object object = joinPoint.proceed(); System.out.println("------------ SimpleAspect.around: proceed返回值 ------------"); System.out.println(JsonUtil.toJson(object)); System.out.println("------------ SimpleAspect.around: proceed之后 ------------"); return object; } @AfterReturning(value = "pointcut()", returning = "returnValue") public void afterReturning(JoinPoint joinPoint, Object returnValue) { System.out.println("############################ SimpleAspect.afterReturning ############################"); MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method method = methodSignature.getMethod(); System.out.println("------------ SimpleAspect.afterReturning: 方法名字 ------------"); System.out.println(method.getName()); System.out.println("------------ SimpleAspect.afterReturning: 返回值 ------------"); System.out.println(JsonUtil.toJson(returnValue)); } @AfterThrowing(value = "pointcut()", throwing = "throwingValue") public void afterThrowing(JoinPoint joinPoint, Throwable throwingValue) { System.out.println("############################ SimpleAspect.afterThrowing ############################"); // MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); // Method method = methodSignature.getMethod(); System.out.println("------------ SimpleAspect.afterThrowing: 异常信息 ------------"); System.out.println(throwingValue.getMessage()); } /** * 无法获得返回值,只能获得参数 */ @After("pointcut()") public void after() { System.out.println("############################ SimpleAspect.after ############################"); } }
测试
后端结果
############################ SimpleAspect.around ############################ joinPoint.getTarget().toString() : com.example.demo.service.impl.UserServiceImpl@36c999c9 methodSignature.getName() : printUser method.getName() : printUser method.getReturnType().getName() : void [{"id":321,"userName":"Tony","note":"abc"}] ------------ SimpleAspect.around: proceed之前 ------------ ############################ SimpleAspect.before ############################ id = 321 userName = Tony note = abc ############################ SimpleAspect.afterReturning ############################ ------------ SimpleAspect.afterReturning: 方法名字 ------------ printUser ------------ SimpleAspect.afterReturning: 返回值 ------------ null ############################ SimpleAspect.after ############################ ------------ SimpleAspect.around: proceed返回值 ------------ null ------------ SimpleAspect.around: proceed之后 ------------
可以看到,返回值为null,因为printUser方法没有返回值。
请先
!