Spring AOP系列--AOP+注解 实例

tech2025-01-20  2

其他网址

另见《深入浅出Spring Boot 2.x》=> 4.3 AOP开发详解

简介

因为AOP可以将切点设为注解类,因此,若想控制Controller,只需要控制@RequestMapping,即:

@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")

创建工程

本文工程全部源码:https://gitee.com/shapeless/demo_JAVA/tree/master/demo_SpringAOP

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 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; } }

 单入参有返回值

package com.example.demo.aspect; import com.example.demo.annotation.OperationLog; import com.example.demo.entity.User; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.text.SimpleDateFormat; @Aspect @Component public class OperationLogAspect { //切点表达式,表示加了OperationLog注解的都是切点,路径是自定义注解的全路径 @Pointcut("@annotation(com.example.demo.annotation.OperationLog)") public void pointcut() { } // 有ProceedingJoinPoint无注解类,有返回值 @Around("pointcut()") public Object around1(ProceedingJoinPoint joinPoint) throws Throwable { 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()); System.out.println("-----------------------------------------------"); Object object = joinPoint.proceed(); OperationLog operationLog = method.getAnnotation(OperationLog.class); System.out.print("type: " + operationLog.type()); System.out.println("\tdesc: " + operationLog.desc()); System.out.println("-----------------------------------------------"); Object[] objects = joinPoint.getArgs(); for (Object o : objects) { System.out.println(o); if (o instanceof User) { System.out.println("id是:" + ((User)(o)).getId() + "; 名字是:" + ((User)(o)).getUserName() + "; 备注是:" + ((User)(o)).getNote()); } } return object; } }

测试

postman访问:http://localhost:8080/user/add?id=321&userName=Tony&note=abc

后端结果

joinPoint.getTarget().toString() : com.example.demo.controller.UserController@10852612 methodSignature.getName() : testAdd method.getName() : testAdd method.getReturnType().getName() : com.example.demo.entity.User ----------------------------------------------- type: 添加 desc: 添加数据 ----------------------------------------------- User(id=321, userName=Tony, note=abc) id是:321; 名字是:Tony; 备注是:abc

postman结果

{ "id": 321, "userName": "Tony", "note": "abc" }

postman访问:http://localhost:8080/user/update?id=321&userName=Tony&note=abc

后端结果

joinPoint.getTarget().toString() : com.example.demo.controller.UserController@10852612 methodSignature.getName() : testUpdate method.getName() : testUpdate method.getReturnType().getName() : com.example.demo.entity.User ----------------------------------------------- id = 321 userName = Tony note = abc type: 更新 desc: 更新数据 ----------------------------------------------- User(id=321, userName=Tony, note=abc) id是:321; 名字是:Tony; 备注是:abc

postman结果

{ "id": 321, "userName": "Tony", "note": "abc" }

双参数有返回值

package com.example.demo.aspect; import com.example.demo.annotation.OperationLog; import com.example.demo.entity.User; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.text.SimpleDateFormat; @Aspect @Component public class OperationLogAspect { //切点表达式,表示加了OperationLog注解的都是切点,路径是自定义注解的全路径 @Pointcut("@annotation(com.example.demo.annotation.OperationLog)") public void pointcut() { } // 有ProceedingJoinPoint和注解类,有返回值 @Around("@annotation(operationLog)") public Object around2(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable{ 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()); System.out.println("-----------------------------------------------"); Object object = joinPoint.proceed(); System.out.println("method.getName(): " + method.getName()); System.out.print("type: " + operationLog.type()); System.out.println("\tdesc: " + operationLog.desc()); System.out.println("-----------------------------------------------"); Object[] objects = joinPoint.getArgs(); for (Object o : objects) { System.out.println(o); if (o instanceof User) { System.out.println("id是:" + ((User)(o)).getId() + "; 名字是:" + ((User)(o)).getUserName() + "; 备注是:" + ((User)(o)).getNote()); } } return object; } }

测试

postman访问:http://localhost:8080/user/add?id=321&userName=Tony&note=abc

后端结果

joinPoint.getTarget().toString() : com.example.demo.controller.UserController@36efe205 methodSignature.getName() : testAdd method.getName() : testAdd method.getReturnType().getName() : com.example.demo.entity.User ----------------------------------------------- method.getName(): testAdd type: 添加 desc: 添加数据 ----------------------------------------------- User(id=321, userName=Tony, note=abc) id是:321; 名字是:Tony; 备注是:abc

postman结果

{ "id": 321, "userName": "Tony", "note": "abc" }

postman访问:http://localhost:8080/user/update?id=321&userName=Tony&note=abc

后端结果

joinPoint.getTarget().toString() : com.example.demo.controller.UserController@36efe205 methodSignature.getName() : testUpdate method.getName() : testUpdate method.getReturnType().getName() : com.example.demo.entity.User ----------------------------------------------- id = 321 userName = Tony note = abc method.getName(): testUpdate type: 更新 desc: 更新数据 ----------------------------------------------- User(id=321, userName=Tony, note=abc) id是:321; 名字是:Tony; 备注是:abc

postman结果

{ "id": 321, "userName": "Tony", "note": "abc" }

单入参无返回值

package com.example.demo.aspect; import com.example.demo.annotation.OperationLog; import com.example.demo.entity.User; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.text.SimpleDateFormat; @Aspect @Component public class OperationLogAspect { //切点表达式,表示加了OperationLog注解的都是切点,路径是自定义注解的全路径 @Pointcut("@annotation(com.example.demo.annotation.OperationLog)") public void pointcut() { } // 有ProceedingJoinPoint无注解类,无返回值 @Around("pointcut()") public void around3(ProceedingJoinPoint joinPoint) throws Throwable { 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()); System.out.println("-----------------------------------------------"); Object object = joinPoint.proceed(); OperationLog operationLog = method.getAnnotation(OperationLog.class); System.out.print("type: " + operationLog.type()); System.out.println("\tdesc: " + operationLog.desc()); System.out.println("-----------------------------------------------"); Object[] objects = joinPoint.getArgs(); for (Object o : objects) { System.out.println(o); if (o instanceof User) { System.out.println("id是:" + ((User)(o)).getId() + "; 名字是:" + ((User)(o)).getUserName() + "; 备注是:" + ((User)(o)).getNote()); } } } }

测试

postman访问:http://localhost:8080/user/add?id=321&userName=Tony&note=abc

后端结果:

joinPoint.getTarget().toString() : com.example.demo.controller.UserController@71e616a3 methodSignature.getName() : testAdd method.getName() : testAdd method.getReturnType().getName() : com.example.demo.entity.User ----------------------------------------------- type: 添加 desc: 添加数据 ----------------------------------------------- User(id=321, userName=Tony, note=abc) id是:321; 名字是:Tony; 备注是:abc

postman结果

postman访问:http://localhost:8080/user/update?id=321&userName=Tony&note=abc

后端结果:

joinPoint.getTarget().toString() : com.example.demo.controller.UserController@71e616a3 methodSignature.getName() : testUpdate method.getName() : testUpdate method.getReturnType().getName() : com.example.demo.entity.User ----------------------------------------------- id = 321 userName = Tony note = abc type: 更新 desc: 更新数据 ----------------------------------------------- User(id=321, userName=Tony, note=abc) id是:321; 名字是:Tony; 备注是:abc

postman结果

最新回复(0)