我正在开发一个 Spring Boot 应用程序,我正在尝试实现一个自定义注释来记录用我的自定义注释注释的方法所使用的执行时间和内存。我无法让它工作,也不知道为什么它不起作用。我找到了类似的帖子并找到了各种示例,但它们都不适用于我的案例。
如果我在这里做错了什么,请告诉我。
请在下面找到我的代码详细信息:
build.gradle 依赖项:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
implementation "org.springframework.boot:spring-boot-starter-oauth2-resource-server"
implementation 'io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry'
implementation 'io.pivotal.spring.cloud:spring-cloud-services-starter-config-client'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation 'com.google.cloud:spring-cloud-gcp-starter'
implementation 'com.google.cloud:spring-cloud-gcp-starter-pubsub'
implementation 'com.google.cloud:spring-cloud-gcp-starter-storage'
implementation 'org.springframework.integration:spring-integration-core'
implementation 'javax.xml.bind:jaxb-api:2.3.0'
implementation 'com.sun.xml.bind:jaxb-core:2.3.0'
implementation 'com.sun.xml.bind:jaxb-impl:2.3.0'
implementation 'javax.annotation:javax.annotation-api:1.3.2'
implementation 'org.springdoc:springdoc-openapi-ui:1.4.3'
implementation 'io.swagger:swagger-annotations:1.6.1'
implementation 'javax.validation:validation-api:2.0.1.Final'
implementation 'org.openapitools:jackson-databind-nullable:0.2.1'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-loadbalancer'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
implementation('com.oracle.database.jdbc:ojdbc8')
implementation 'org.dom4j:dom4j:2.1.0'
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
//testImplementation 'io.projectreactor:reactor-test'
testImplementation 'org.springframework.amqp:spring-rabbit-test'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.aspectj:aspectjweaver'
}
自定义注释接口:
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 LogExecutionProfile {}
记录方面类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Aspect
@Component
public class LoggingAspect {
@Around("@annotation(LogExecutionProfile) || execution(public * @LogExecutionProfile *.*(..)))")
public Object profileMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
String className = methodSignature.getDeclaringType().getSimpleName();
String methodName = methodSignature.getName();
long startTime = System.currentTimeMillis();
long memoryAtStart = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
Object result = proceedingJoinPoint.proceed();
long endTime = System.currentTimeMillis();
long memoryAtEnd = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
log.debug("execution time: " + (endTime - startTime) + " ms"
+ " memory used: " + (memoryAtEnd - memoryAtStart) + " bytes of memory");
return result;
}
}
服务等级:
@Service
public class MyService {
@LogExecutionProfile
public void someServiceMethod(){
log.debug("service log");
// service method logic
}
}
预期结果:
service log
execution time: XX ms memory used: XX bytes of memory
实际结果:
service log
我也尝试过以下:
示例 1: 不工作
@Pointcut("execution(@com.example.LogExecutionProfile * *.*(..))")
public void annotatedMethod() {}
@Around("annotatedMethod()")
public Object profileMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
**
}
示例 2: 不工作
@Pointcut("@annotation(com.example.LogExecutionProfile)")
public void annotatedMethod() {}
@Around("execution(* *(..)) && (annotatedMethod())")
public Object profileMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
**
}
示例 3: 不工作
@Around("@annotation(com.example.LogExecutionProfile)")
public Object profileMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
**
}
spring apo 中的切面必须用 @Configuration 注解。因此,使用此类更改您的 LoggingAspect 类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Configuration;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Aspect
@Configuration
public class LoggingAspect {
@Around("@annotation(LogExecutionProfile) || execution(public * @LogExecutionProfile *.*(..)))")
public Object profileMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
String className = methodSignature.getDeclaringType().getSimpleName();
String methodName = methodSignature.getName();
long startTime = System.currentTimeMillis();
long memoryAtStart = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
Object result = proceedingJoinPoint.proceed();
long endTime = System.currentTimeMillis();
long memoryAtEnd = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
log.debug("execution time: " + (endTime - startTime) + " ms"
+ " memory used: " + (memoryAtEnd - memoryAtStart) + " bytes of memory");
return result;
}
有一个示例方面可供您使用
package com.dpco.aop;
import com.dpco.business.exception.CustomException;
import com.dpco.logger.Logger4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
@Aspect
@Configuration
public class LoggerAspect {
@Autowired
private Logger4j logger4j;
@Pointcut("execution(* com.dpco.controller.*.*(..)) && @annotation(requestMapping)")
public void controller(RequestMapping requestMapping){
}
@Around("controller(requestMapping)")
public Object around(ProceedingJoinPoint joinPoint , RequestMapping requestMapping) throws Throwable {
Object[] obj = joinPoint.getArgs();
File file = new File("log.txt");
Object object = null;
try {
if (file.createNewFile()) {
FileWriter fileWriter = new FileWriter(file);
fileWriter.write("\n\n-----------------------------------------this is the logger of project , you can see the methods that calls and information of them in here------------------------------------\n\n");
fileWriter.close();
}
FileWriter fileWriter = new FileWriter(file, true);
Date first = new Date();
fileWriter.write("\n---------------------------------------" + joinPoint.getSignature().getName() + "-------------------------------------------\n");
fileWriter.write("path is : " + requestMapping.path()[0] + "\n");
fileWriter.write("the method of request is :" + requestMapping.method()[0] + "\n");
StringBuilder builder = new StringBuilder();
for (Object arg : obj) {
builder.append(arg.toString() + ",");
}
if(builder.length() != 0) {
builder.deleteCharAt(builder.indexOf(builder.toString()));
}
fileWriter.write("the arguments of this method is : " + builder.toString() + "\n");
object = joinPoint.proceed();
Date second = new Date();
fileWriter.write("the milli seconds that left : " + String.valueOf(second.getTime() - first.getTime()));
fileWriter.close();
} catch (IOException e) {
logger4j.getLogger(e);
throw new CustomException("hello", HttpStatus.MULTI_STATUS);
}
return object;
}
}
此方面将围绕控制器包中由请求映射注释的任何方法执行。
我认为在您的方面类中使用@Configuration并省略@Component之后,它将正常工作。