您现在的位置是:首页 > 编程 > 

Java自定义注解:定义、解析,AOP切面与日志打印

2025-07-27 15:40:25
Java自定义注解:定义、解析,AOP切面与日志打印 本文主要介绍了 Java 中的自定义注解以及结合 AOP(面向切面编程)技术进行日志记录的方法。1. 注解定义注解是附在代码上的元数据(Metadata),给编译器或运行时提供额外指导信息。Java自带多种注解,也可自定义以适应特殊需求。代码示例创建一个名为LogExecution的注解,它可以应用到方法上,并有两个可选参数:value(用于存

Java自定义注解:定义、解析,AOP切面与日志打印

本文主要介绍了 Java 中的自定义注解以及结合 AOP(面向切面编程)技术进行日志记录的方法。

1. 注解定义

注解是附在代码上的元数据(Metadata),给编译器或运行时提供额外指导信息。Java自带多种注解,也可自定义以适应特殊需求。

代码示例

创建一个名为LogExecution的注解,它可以应用到方法上,并有两个可选参数:value(用于存储自定义消息)和level(用于指定日志级别)。

代码语言:java复制
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// @Target 表明该注解可以应用于哪些程序元素
@Target(ElementType.METHOD)
// @Retention 表明注解在何时可用:源码级别、类文件级别还是运行时级别
@Retention(RetentionPolicy.RUTIME)
public @interface LogExecution {
    // 定义注解的一个属性,并给出默认值
    String value() default "";
    
    // 可以定义更多的属性,例如记录的日志级别
    LogLevel level() default LogLevel.IFO;
}

// 自定义枚举用于指定日志级别
public enum LogLevel {
    DEBUG, IFO, WAR, ERROR
}

2. 注解解析

通过Java反射API(动态地获取和操作类、接口、字段、方法等信息)去利用自定义注解,下面的代码用于检查方法是否标有LogExecution注解,如果有则在运行时执行日志记录。

代码示例

代码语言:java复制
import java.lang.reflect.Method;

public class AnnotationProcessor {
    public void process(Method method) {
        if (method.isAnnotationPresent()) {
            LogExecution logExecution = method.getAnnotation();
            String message = logExecution.value();
            LogLevel level = logExecution.level();

            // 根据日志级别调用对应的日志接口
            switch (level) {
                case DEBUG:
                    println("DEBUG: " + message);
                    break;
                case IFO:
                    println("IFO: " + message);
                    break;
                // ... 其他级别处理 ...
            }
        }
    }
}

. 自定义注解结合AOP切面

Spring AOP能帮我们在程序中不改动原有代码的情况下,加上一些通用功能,比如记录日志。

假设有一个LogExecution标记,我们可以用AOP技术,设置在这个方法执行前后自动做某些事情。在方法开始前和结束后记时,然后按照标记里设定的日志级别,比如是警告还是信息,打印一条包含执行时长的消息。这样就不用每个方法都手动去写这些记录时间、打日志的代码了。

代码示例

代码语言:java复制
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Around("@annotation(LogExecution)")
    public Object logMethodExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        LogExecution annotation = signature.getMethod().getAnnotation();
        // 开始计时
        long start = ();
        // 执行原方法        
        Object result = joinPoint.proceed();
        // 结束计时并打印日志
        long executionTime = () - start;
        String message = annotation.value();
        LogLevel level = annotation.level();

        // 打印执行时间和注解信息
        printLog(level, message, executionTime);

        return result;
    }

    private void printLog(LogLevel level, String message, long executionTime) {
        // 根据日志级别调用对应的日志服务,这里仅做简单演示
        switch (level) {
            case DEBUG:
                printf("[DEBUG] %s took %d ms%n", message, executionTime);
                break;
            // ... 其他级别处理 ...
        }
    }
}

4. 自定义注解用于日志打印

结合前面的例子,我们可以进一步完善LogExecution注解的功能,使其不仅能记录执行时间,还能按照注解中定义的消息格式打印日志。

1.创建自定义注解

代码语言:java复制
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUTIME)
@Target(ElementType.METHOD)
public @interface LogExecution {
    String message() default "Method execution: {}";
    LogLevel level() default LogLevel.IFO;
    
    enum LogLevel {
        TRACE, DEBUG, IFO, WAR, ERROR
    }
}

2.定义服务接口和其实现类,并在方法上应用注解

代码语言:java复制
public interface UserService {
    @LogExecution(message = "User is being retrieved by ID: {}", level = LogLevel.DEBUG)
    User getUserById(Long id);
}

@Service
public class UserServiceImpl implements UserService {
    // ...
    @Override
    public User getUserById(Long id) {
        // 实现获取用户的方法逻辑
        // ...
        return user;
    }
}

. 编写AOP切面类处理日志打印

代码语言:java复制
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger();

    @Around("@annotation(logExecution)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogExecution logExecution) throws Throwable {
        String methodSignature = joinPoint.getSignature().toShortString();
        String formattedMessage = String.format((), methodSignature);

        switch (logExecution.level()) {
            case TRACE:
                (formattedMessage);
                break;
            case DEBUG:
                LOGGER.debug(formattedMessage);
                break;
            case IFO:
                LOGGER.info(formattedMessage);
                break;
            case WAR:
                LOGGER.warn(formattedMessage);
                break;
            case ERROR:
                (formattedMessage);
                break;
        }

        long start = ();
        try {
            // 执行原方法
            Object result = joinPoint.proceed();
            // 记录执行结束时间(此处仅演示了注解的功能性,实际可能需要记录更多信息)
            LOGGER.info("Finished executing {}, took {}ms", methodSignature, () - start);
            return result;
        } catch (Throwable ex) {
            ("An error occurred while executing {}", methodSignature, ex);
            throw ex;
        }
    }
}

当调用getUserById方法时,由于该方法被@LogExecution注解标记,所以会触发LoggingAspect中的logExecutionTime方法,在方法执行前后进行相应的日志记录。

4.在Controller类上应用自定义注解

代码语言:java复制
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/users/{id}")
    @LogExecution(message = "User is being retrieved from API with ID: {}", level = LogLevel.IFO)
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

当访问/users/{id}端点以获取用户信息时,由于getUser方法上添加了@LogExecution注解,所以每当此方法被调用时,LoggingAspect切面会捕获到这个事件,并根据注解的配置打印相应的日志信息。如果客户端请求 /users/1 ,那么控制台将会看到类似于以下格式的日志:

代码语言:java复制
IFO [LoggingAspect] - User is being retrieved from API with ID: UserController.getUser(Long)
IFO [LoggingAspect] - Finished executing UserController.getUser(Long), took x ms

5. 总结

自定义注解为程序元素加上标签,让代码携带更多信息。程序运行时,Java能读取这些标签(注解解析),按标签指示执行特别操作。结合AOP,自定义注解变身智能开关,自动执行如日志记录等任务。

  • 日志管理:用LogExecution等注解轻松标注方法,自动收集日志,涵盖执行时间、参数、结果和异常,提升日志管理的一致性和效率。
  • 微服务管理:在微服务中,特定注解帮助识别关键服务部分,集中监控、管理事务和缓存,增强服务性能和运维便利性。
  • 规范与安全强化:自定义注解不仅提升代码质量,还能确保遵循规范。在安全上,结合AOP,注解成为强效工具,强制执行权限检查和数据保护措施,防堵安全漏洞。

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1186215.html

相关标签:无
上传时间: 2025-07-22 11:49:14
留言与评论(共有 11 条评论)
本站网友 饲料市场
19分钟前 发表
LOGGER.warn(formattedMessage); break; case ERROR
本站网友 播种网
26分钟前 发表
由于getUser方法上添加了@LogExecution注解
本站网友 深圳爆炸
10分钟前 发表
message
本站网友 三七粉的功效
1分钟前 发表
1.创建自定义注解代码语言:java复制import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUTIME) @Target(ElementType.METHOD) public @interface LogExecution { String message() default "Method execution
本站网友 株洲日语
25分钟前 发表
由于该方法被@LogExecution注解标记
本站网友 张丰毅主演的电视剧
8分钟前 发表
参数
本站网友 找装修设计
5分钟前 发表
代码示例创建一个名为LogExecution的注解
本站网友 铜冶炼
8分钟前 发表
() - start); return result; } catch (Throwable ex) { ("An error occurred while executing {}"
本站网友 黑莓wipe
23分钟前 发表
比如记录日志
本站网友 减肥训练营
22分钟前 发表
它可以应用到方法上