一, 目标:
自定义注解,完成通过自定义注解注释类方法,实现被自定义注解注释的方法执行特定aop逻辑,实现对被注释方法的功能增强。
比如可以开发一个自定义日志记录的注解,在需要记录日志的方法上使用注解,去记录方法的名称,传入的参数,执行的结果,把这些信息记录到日志文件。
二,实现:
1. 添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2. 自定义注解
public @interface TestAnnotation { }
3. 编写注解处理器,注解处理器中有通过aop对注解注释的方法的逻辑增强。
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Aspect @Component public class TestAnnotationHandler { @Pointcut("@annotation(com.haonan.tt.annotation.TestAnnotation)") public void jPoint() { } @Before("jPoint()") public void before(JoinPoint jp) { System.out.println("------------before--------------------"); } /** * 具体返回值,按照业务需求来做 * * @param joinPoint * @throws Throwable */ @Around("jPoint()") public void doAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("进入切面"); joinPoint.proceed(); System.out.println("离开切面"); } @After("jPoint()") public void after(JoinPoint jp) { System.out.println("------------after--------------------"); } }
4. 使用自定义注解
@RestController public class UserController { @Autowired private UserService userService; @TestAnnotation @GetMapping("/") public void hello() { // logic } }
5. 后话
在进行切面编程的过程中,至少涉及到切点,和切面,这两个概念,
切面 = 切点 + 一些通用的增强逻辑,比如上述代码中的:
@Before("jPoint()")
@Around("jPoint()")
@After("jPoint()")
这三个注解修饰的方法就是切面,切面可以对切点的逻辑进行增强,
换言之,切面修改了切点的业务逻辑。在spring中,最为常见的切点就是方法,即method,一个个函数,但显然这里的切点是注解,即annotation。
切点,通常是一个函数,即方法,一个类的成员函数,但是在springboot中,切注解的更为常见。可以通过:@Pointcut 这个注解定义一个切点,
定义好的切点,可以被多个切面使用。如本文中示例那样。也可以不单独定义如 @Before("jPoint()") == @Before("@annotation(com.haonan.tt.annotation.TestAnnotation)") 。
另外,可以通过execution表达式定义切点,然后在 @Before ,@Around, @After中直接使用。
execution( modifiers-pattern? // 访问修饰符 public private 等,?问号表示可以省略 ret-type-pattern // 返回值类型正则模式,* 表示任意返回类型 declaring-type-pattern? // 方法所在类的全路径名称正则模式,可以使用通配符,当然?问号表示可以省略 name-pattern(param-pattern) // 方法名称的正则模式,以及括号内的参数正则模式,参数正则模式通常写 .. 表示任意参数 throws-pattern? // 抛出异常的正则模式,?问号表示可以省略 ) // 方法所在类的全路径名称正则模式 与 方法名称的正则模式 之间同点.进行连接 //表示匹配所有方法 execution(* *(..)) //表示匹配com. example.controller中所有的public方法 execution(public * com.example.controller.*(..)) //表示匹配com. example.controller包及其子包下的所有方法 execution(* com.example.controller..*.*(..))
原文:https://www.cnblogs.com/luohaonan/p/12214515.html