Java自定义注解:定义、解析,AOP切面与日志打印
Java自定义注解:定义、解析,AOP切面与日志打印
本文主要介绍了 Java 中的自定义注解以及结合 AOP(面向切面编程)技术进行日志记录的方法。
1. 注解定义
注解是附在代码上的元数据(Metadata),给编译器或运行时提供额外指导信息。Java自带多种注解,也可自定义以适应特殊需求。
代码示例
创建一个名为LogExecution
的注解,它可以应用到方法上,并有两个可选参数:value
(用于存储自定义消息)和level
(用于指定日志级别)。
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
,那么控制台将会看到类似于以下格式的日志:
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组装电脑配置单推荐报价格
推荐阅读
留言与评论(共有 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分钟前 发表 |
它可以应用到方法上 |