Java 自定义注解实现统一日志记录功能【Java核心技术_二十七】

news2024/11/13 9:36:38

一、什么是 Java 注解?

想象一下,你正在写一本日记,你可以在某些页面上贴上彩色的便签,上面写着一些关键词或者提醒。在 Java 中,注解就像是这些便签,它可以贴在类、方法、变量等程序元素上,为它们添加额外的信息。

注解本身不会改变程序的运行逻辑,但它们可以被其他工具或者框架读取和处理。比如,编译器可以根据注解来检查代码的正确性,或者框架可以根据注解来自动配置对象。

二、Java 内置注解

Java 自带了一些内置的注解,它们非常实用。

1. @Override

当你想要重写一个父类的方法时,可以使用 @Override 注解。这个注解就像是一个标志,告诉编译器你正在重写一个方法。如果你的方法签名不正确,编译器会报错,这样可以避免一些错误。
例如:

package java_core_27;

public class Parent {
	
	 public void sayHello() {
	        System.out.println("Hello from parent!");
	    }
}

class Child extends Parent {
    @Override
    public void sayHello() {
        System.out.println("Hello from child!");
    }
}

很显然,运行结果为:

Hello from child!

2. @Deprecated

如果你有一个方法或者类已经过时了,不建议再使用,可以使用 @Deprecated 注解。
例如:

@Deprecated
public class TestDeprecated {
	
}	

当其他程序员在使用这个注解标记的方法时,会有 删除线 警示。

在这里插入图片描述

3. @SuppressWarnings

有时候,编译器会发出一些警告,但是你可能知道这些警告是不必要的,或者你有特殊的原因不想处理这些警告。例如,对于上述过时的方法就有如下警告:

Multiple markers at this line
	- The constructor TestDeprecated() is deprecated
	- The type TestDeprecated is deprecated
	- The type TestDeprecated is deprecated

这时,你可以使用 @SuppressWarnings 注解来抑制这些警告。

public class Test {
	
	@SuppressWarnings("deprecation")
	public static void main(String[] args) {
		//过时的方法
		TestDeprecated testDeprecated = new TestDeprecated();
		testDeprecated.test();
	}
	
}	

三、什么是元注解?

元注解就是用来注解注解的注解。听起来有点绕,但是其实很简单。元注解可以为我们自定义的注解添加一些属性和行为。
比如,@Retention 元注解可以指定一个注解的生命周期。它有三个取值:

  • RetentionPolicy.SOURCE:注解只在源代码中有效,编译后就会被丢弃。
  • RetentionPolicy.CLASS:注解在编译后的字节码文件中有效,但在运行时不可用。
  • RetentionPolicy.RUNTIME:注解在运行时仍然有效,可以被反射机制读取。
    @Target 元注解可以指定一个注解可以应用的程序元素类型。比如,可以指定一个注解只能应用于方法、类、变量等。

四、Java 自定义注解实现统一日志

接下来,我们使用自定义注解实现一个日志打印的场景:

1. 自定义注解类 LogAnnotation

定义一个自定义注解 LogAnnotation,用于标记需要记录日志的方法。这个注解可以指定一些属性,也可以不指定,仅作为一个标记使用。

package com.jsglxx.demo.utils;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogAnnotation {

}

2. 日志记录切面类 LogAspect

  • 创建一个切面类,使用 @Aspect 注解标记该类为一个切面。
  • 在切面类中定义一个环绕通知方法,使用 @Around 注解并指定要拦截的连接点为带有自定义注解的方法 @annotation(com.jsglxx.demo.utils.LogAnnotation)
  • 在环绕通知方法中,通过 ProceedingJoinPoint 对象获取要执行的方法信息,在方法执行前可以记录日志表示进入方法,然后调用 joinPoint.proceed() 执行被拦截的方法,最后在方法执行后再次记录日志表示退出方法,并返回方法的执行结果。
package com.jsglxx.demo.utils;

import ch.qos.logback.classic.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

    private final Logger logger = (Logger) LoggerFactory.getLogger(LogAspect.class);

    @Around("@annotation(com.jsglxx.demo.utils.LogAnnotation)")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info("进入方法:{}", joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        logger.info("退出方法:{}", joinPoint.getSignature().getName());
        return result;
    }
}

3. 在服务类中使用自定义注解

在需要记录日志的服务类方法上添加自定义注解 LogAnnotation

package com.jsglxx.demo.service;

import org.springframework.stereotype.Service;
import com.jsglxx.demo.utils.LogAnnotation;

@Service
public class TestService {

    @LogAnnotation
    public void testMethod() {
        System.out.println("这是一个测试方法。");
    }
}

4. 配置和启动应用-测试

  • 在 Spring Boot 主启动类上添加必要的注解,如 @SpringBootApplication。如果切面类不在主启动类所在的包或子包中,可以通过 @ComponentScan 注解指定切面类所在的包路径,确保切面类被 Spring 容器扫描到。
  • 启动 Spring Boot 应用,当调用被标注了自定义注解的方法时,切面类中的逻辑会自动生效,记录方法的进入和退出日志。
package com.jsglxx.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

import com.jsglxx.demo.service.TestService;

@SpringBootApplication(/* scanBasePackages = {"com.jsglxx.service", "其他需要扫描的包"} */)
@EnableAspectJAutoProxy
public class DemoApplication {
	
	public static void main(String[] args) {
		ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        TestService testService = context.getBean(TestService.class);
        testService.testMethod();
	}

}

结束语

通过以上步骤,就可以在 Spring Boot 应用中利用自定义注解和 AspectJ 实现统一的日志记录功能,方便地对特定方法进行日志跟踪和监控。

遇见即是缘分,关注🌟、点赞👍、收藏📚,让这份美好延续下去!

🌟 对技术管理感兴趣 请关注 ⬇ 【 技术管理修行】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2099420.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue 3 中如何对接高德地图

1. 准备工作 1.1. 获取高德地图 API Key 首先,你需要在高德开放平台注册并获取一个 API Key。访问 高德开放平台 注册并申请。 1.2. 安装依赖 在 Vue 3 项目中使用高德地图,可以通过以下步骤安装依赖: npm install types/amap-js-api --…

5.注册中心的其他实现-Nacos

文章目录 1.Nacos简介2.Nacos的安装2.1Nacos Windows本地启动不成功?2.2Linux环境下载并启动 3. Nacos的使用4.Nacos的负载均衡5.Nacos 健康检查6.Nacos 环境隔离7.Nacos 配置中心7.1为什么需要配置中心7.2 Nacos配置中心使用7.3 Data id7.4Nacos 上Linux部署服务7.…

鹰眼应急实时三维重建装备,高质量交付中!

在《2024年地方应急管理科技信息化任务书》的指导和应急管理万亿国债支撑下,全国各地正积极推进应急管理现代化建设,全力提升“数据汇聚服务能力、监测预警能力、指挥调度能力、支撑保障能力”四项应急管理能力。 制定标准化流程规范,保障交…

计算机毕业设计选题推荐-茶园茶农文化交流平台-Java/Python项目实战

✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

分组密码的模式AES-CBC模式流程解析附:应用代码实现

CBC模式:Cipher Block Chaining mode(密码分组链接模式) CBC模式的加解密 CBC模式中,首先将明文分组与前一个密文分组进行XOR运算,然后再进行加密。密文分组像链条一样相互连接在一起。 CBC模式的加密流程图 CBC模式的解密流程图 将一个分…

使用 `wget` 和 `curl` 命令行工具的全面指南

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] &#x1f4f1…

3.3 语法规则

🎓 微机原理考点专栏(通篇免费) 欢迎来到我的微机原理专栏!我将帮助你在最短时间内掌握微机原理的核心内容,为你的考研或期末考试保驾护航。 为什么选择我的视频? 全程考点讲解:每一节视频都…

Oracle RAC关于多节点访问同一个数据的过程

一、说明 Oracle RAC 存在多个计算节点,但是使用的共享存储。那么多个节点共同访问同一个资源,怎么保证一致性。 白文的逻辑理解简述: 用户1访问rac1 ,通过rac1获取AA数据块后,会加上latch锁。用户2通过rac2访问AA数据…

union不能被初始化由于有 non-trivial构造函数

背景 最近遇到一个问题&#xff0c;当定义一个union的时候&#xff0c;发现初始化失败&#xff0c;具体如下&#xff1a; class NonTrivial { public:NonTrivial(const std::string& s) : data(s) {std::cout << "NonTrivial constructed with " <<…

嵌入式OTG硬件电路分析

大家好,今天主要给大家分享一下,如何使用OTG硬件检测电路,和之前的接口有什么区别。 1. OTG接口与转换器 OTG是"On The Go"的英文缩写,字面上可以理解为“安上即可用”。USB传输是主从结构,一切USB传输都有Host发起。比如在开发板上可以插入U盘,这时开发板作为…

计算机毕业设计选题推荐-店铺租赁平台-商铺租赁系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

【简历】25届武汉某二本JAVA简历:项目描述真是难为学生想这么偏

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 这是一份 25 届武汉某二本学校的JAVA简历。校招第一要点是上来必须先确定自己的求职层次&#xff0c;大中小厂要求不一样。二本同学主体…

Day 10-11:函数、函数传参

基本用法以及传参 基本用法 调用 1.无返回值函数调用 #include<stdio.h> #pragma warning(disable:4996); void my_helloworld() {printf("hello world!"); } int main() {my_helloworld();return 0; } //输出结果&#xff1a;hello world&#xff01;2.实际…

Leetcode每日刷题之438.找到字符串中所有字符异位词

1.题目解析 本题的题目要求是给定一个长字符串s与一个较短字符串p&#xff0c;判断s中是否有一段与p长度相同的字符串是由p打乱而得来&#xff0c;即为异位词&#xff0c;然后返回其开始位置下标&#xff0c;遍历s字符串中所有满足条件字符串的起始位置下标 2.算法原理 我们将p…

android AccessibilityService合法合规采集大众点评app商店商品详情(2024-09-02)

免责任声明: 任何可操作性的内容与本人无关,文章内容仅供参考学习&#xff0c;如有侵权损害贵公司利益&#xff0c;请联系作者&#xff0c;会立刻马上进行删除。 一、原理介绍 1、打开大众点评app商店 public void open_shop(Context context,String shop_id){String url"…

ARM基础知识---CPU---处理器

目录 一、ARM架构 1.1.RAM---随机存储器 1.2.ROM---只读存储器 1.3.flash---闪存存储器 1.4.时钟&#xff08;振晶&#xff09; 1.5.复位 二、CPU---ARM920T 2.1.R0~R12---通用寄存器 2.2.PC程序计数器 2.3.LR连接寄存器 2.4.SP栈指针寄存器 2.5.CPSR当前程序状态寄存…

【MySQL进阶】索引性能分析

1. 索引语法 创建索引&#xff1a; ​ 语法格式&#xff1a;create [unique|fulltext] index index_name on table_name(index_col_name...); 查看索引&#xff1a; ​ 语法格式&#xff1a;show index from table_name; 删除索引&#xff1a; ​ 语法格式&#xff1a;dr…

Spring Boot实现License生成和校验

1.License应用场景 在我们向客户销售商业软件的时候&#xff0c;常常需要对所发布的软件实行一系列管控措施&#xff0c;诸如验证使用者身份、软件是否到期&#xff0c;以及保存版权信息和开发商详情等。考虑到诸多应用场景可能处于离线环境&#xff0c;无法依赖网络进行实时认…

5.数据结构-c/c++二叉树详解(上篇)(遍历方法,完全二叉树)

目录 一. 二叉树的基本介绍 1.2 满二叉树 1.3 完全二叉树 1.4 搜索二叉树 1.5 平衡二叉搜索树 二. 二叉树的常用操作 2.1 二叉树的定义 2.2 创建一个新的节点 2.3 构建一颗树 2.5 销毁一棵树 三.二叉树的前序&#xff0c;中序&#xff0c;后序&#xff0c;层序遍历方…

day-47 子集

思路 利用深度优先遍历算法&#xff0c;对于每个数有选或不选两种抉择&#xff0c;每次遍历到idslen时将p加入答案中 解题过程 选中当前数字&#xff0c;调用dfs函数之后记得还原 Code class Solution {public int len;public List<List<Integer>> listnew Arra…