当前位置: 首页 > article >正文

Spring Aop+自定义注解实践(待完善日志)

目录

前言

1.引入依赖

2.SpringAop的用法举例

3. 自定义注解+AOP的用法举例

3.1 关于Target注解补充

3.2 关于Retention注解补充

3.3 举例


前言

如果你不太理解aop的知识,请看我写的这篇文章,非常详细:

Spring AOP(定义、使用场景、用法、3种事务、事务失效场景及解决办法、面试题)_spring aop的事件-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/m0_64422133/article/details/143376059?spm=1001.2014.3001.5501

1.引入依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.SpringAop的用法举例

service类(获取名字接口)

package com.example.aop_annotation.service;
import org.springframework.stereotype.Service;

/**
 * @author xcw
 */
@Service
public class NameService {
    public String getName(String name){
        System.out.println("getName方法执行了");
        return "NameService:"+name;}
}

TestService

这个类实现了 CommandLineRunner类并且重写run(),run()中的操作会在springboot启动后调用

package com.example.aop_annotation.service;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author xcw
 */
@Component
public class TestService implements CommandLineRunner {

    @Resource
    NameService nameService;


    @Override
    public void run(String... args) throws Exception {
        nameService.getName("xcw");

    }
}

切面类:

package com.example.aop_annotation.aop;

import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author xcw
 */
@Aspect
@Component
public class LogAspect {
    //定义切点拦截NameService类中的所有方法
    @Pointcut("execution(* com.example.aop_annotation.service.NameService.*(..))")
    public void pointcut(){

    }

    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println("拦截的类: " + joinPoint.getTarget().getClass().getName());
        System.out.println("拦截的方法: " + joinPoint.getSignature().getName());
        System.out.println("方法参数: " + Arrays.toString(args));
        //方法返回值
        System.out.println("before前置通知执行了");
        System.out.println("----------------------------------------------");
    }

    @AfterReturning(pointcut = "pointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("拦截的类: " + joinPoint.getTarget().getClass().getName());
        System.out.println("拦截的方法: " + joinPoint.getSignature().getName());
        System.out.println("返回值: " + result);
        System.out.println("afterReturning后置通知执行了");
        System.out.println("----------------------------------------------");
    }
}

执行结果如下:

我们把上面代码改为使用自定义注解+AOP的方式

3. 自定义注解+AOP的用法举例

首先我们先创建一个自定义注解类

package com.example.aop_annotation.annotation;

import java.lang.annotation.*;

/**
 * @author xcw
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {
    String value() default "";
}

3.1 关于Target注解补充

@Target:常常配合枚举类ElementType来指定注解的作用位置,即你定义了一个注解,这个注解是类注解还是方法注解还是属性字段注解等具体作用的范围

ElementType的枚举值有

枚举值含义
TYPE类、接口(包括注解类型)、或枚举声明
FIELD字段,包括枚解常量
METHOD方法声明
PARAMETER正式的参数声明
CONSTRUCTOR构造函数的声明
LOCAL_VARIABLE局部变量的声明
ANNOTATION_TYPE注解类型的声明
PACKAGE包声明

3.2 关于Retention注解补充


@Retention:常常配合枚举类RetentionPolicy来指定注解的各种策略,注解的保留时间(生命周期),也就是何时生效,即你定义了一个注解,这个注解是编译时生效还是仅仅只是在代码中标记等等,具体作用的范围,取决于@Retention({RetentionPolic.TYPE})中,RetentionPolic的枚举值,在进行自定义枚举时,大多数都是使用RUNTIME(编译时生效)

RetentionPolic的枚举值

枚举值含义
SOURCE解只在源代码级别保留,编译时被忽略。
CLASS注解将被编译器在类文件中记录,但在运行时不需要JVM保留。这是默认的。
RUNTIME注解将被编译器记录在类文件中,在运行时保留,VM可以读取。一般自定义注解均使用这个。

3.3 举例

我们把上面 2 中的例子改成使用Aop+自定义注解的方式实现

1. 首先我们先创建一个自定义注解类

package com.example.aop_annotation.annotation;

import java.lang.annotation.*;

/**
 * @author xcw
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation {
    String value() default "";
}

2. 在方法上使用自定义注解

package com.example.aop_annotation.service;
import com.example.aop_annotation.annotation.MyAnnotation;
import org.springframework.stereotype.Service;

/**
 * @author xcw
 */
@Service
public class NameService2 {
    @MyAnnotation
    public String getName2(String name){
        System.out.println("getName2方法执行了");
        return "NameService2:"+name;}
}

3. 把aop切点 指向改为 注解类的包路径

package com.example.aop_annotation.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author xcw
 */
@Aspect
@Component
public class LogAspect2 {
    //定义切点拦截使用了自定义注解@MyAnnotation的方法
    @Pointcut(value = "@annotation(com.example.aop_annotation.annotation.MyAnnotation)")
    public void pointcut(){}

    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println("拦截的类: " + joinPoint.getTarget().getClass().getName());
        System.out.println("拦截的方法: " + joinPoint.getSignature().getName());
        System.out.println("方法参数: " + Arrays.toString(args));
        //方法返回值
        System.out.println("before前置通知执行了");
        System.out.println("----------------------------------------------");
    }

    @AfterReturning(pointcut = "pointcut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("拦截的类: " + joinPoint.getTarget().getClass().getName());
        System.out.println("拦截的方法: " + joinPoint.getSignature().getName());
        System.out.println("返回值: " + result);
        System.out.println("afterReturning后置通知执行了");
        System.out.println("----------------------------------------------");
    }
}

项目启动后执行的类

package com.example.aop_annotation.service;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @author xcw
 */
@Component
public class TestService implements CommandLineRunner {

    @Resource
    NameService nameService;

    @Resource
    NameService2 nameService2;

    @Override
    public void run(String... args) throws Exception {
        nameService2.getName2("xcw");
    }
}

执行结果如下:

后续待完善此文章(AOP+自定义注解+枚举类 实现日志写入打印功能)

如果你也感兴趣可以参考:

springboot aop 自定义注解方式实现完善日志记录(完整源码)-腾讯云开发者社区-腾讯云 (tencent.com)


http://www.kler.cn/a/408017.html

相关文章:

  • 微前端基础知识入门篇(二)
  • 【论文阅读】WGSR
  • Qt界面设计时使各控件依据窗口缩放进行栅格布局的方法
  • python特殊字符序列
  • mq 消费慢处理方式,rocketmq消费慢如何处理,mq如何处理消费端消费速率慢。rocketmq优化
  • 内存级文件原理——Linux
  • windows10下3DGS环境配置
  • Rust 力扣 - 2466. 统计构造好字符串的方案数
  • Redis的理解
  • cangjie (仓颉) vscode环境搭建
  • 2024年亚太杯数学建模竞赛赛题选题人数发布
  • Qt之QWidget相关
  • 7、深入剖析PyTorch nn.Module源码
  • 【入门篇】欧几里德最差序列——多语言求解版
  • 后端:事务
  • RabbitMQ2:介绍、安装、快速入门、数据隔离
  • 八、无刷电机电压电流温度采集
  • CSS布局学习1
  • Oracle SQL优化②——访问路径
  • 使用 Elastic AI Assistant for Search 和 Azure OpenAI 实现从 0 到 60 的转变
  • 2-测试bigcache做进程内缓存 --开源项目obtain_data测试
  • Python爬虫:获取1688店铺详情的实战指南
  • JMeter监听器与压测监控之 InfluxDB
  • 在Excel中处理不规范的日期格式数据并判断格式是否正确
  • 【JAVA面试题】什么是Springboot的自动配置以及注意事项
  • 【深度学习之回归预测篇】基于卷积神经网络(CNN)的数据回归预测