【问题标题】:Spring AOP logging thread methodSpring AOP 日志记录线程方法
【发布时间】:2020-05-02 20:15:55
【问题描述】:

有没有办法实现 AOP 日志记录到 implements Runnable 并由 ExecutorService 运行的类的公共方法?

线程类

@Component
@Scope("prototype")
public class FileProcessor implements Runnable {

  private final LinkedBlockingQueue<File> filesQueue;
  private final GiftCertificateMapper certificateMapper;
  private final File errorFolder;
  private static final ReentrantLock LOCK = new ReentrantLock();

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

  public FileProcessor(LinkedBlockingQueue<File> filesQueue, GiftCertificateMapper certificateMapper,
      File errorFolder) {
    this.filesQueue = filesQueue;
    this.certificateMapper = certificateMapper;
    this.errorFolder = errorFolder;
  }

  @Override
  public void run() {
    File file = null;
    try {
      while ((file = filesQueue.poll(100, TimeUnit.MILLISECONDS)) != null) {
        processFile(file);
      }
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      LOGGER.warn("File thread was interrupted");
    } catch (IOException e) {
      LOGGER.error("Error processing file {} \n{}", file.getAbsolutePath(), e);
    }
  }

  public void processFile(File file) throws IOException {
    if (file != null) {
      try {
        ObjectMapper objectMapper = new ObjectMapper();
        List<GiftCertificate> certificates = Arrays.asList(objectMapper.readValue(file, GiftCertificate[].class));
        certificateMapper.insertList(certificates);
        file.delete();
      } catch (JsonParseException | UnrecognizedPropertyException | InvalidFormatException | DataIntegrityViolationException e) {
        moveFileToErrorFolder(file);
      }
    }
  }

  private void moveFileToErrorFolder(File file) throws IOException {
    try {
      LOCK.lock();
      Files.move(Paths.get(file.getAbsolutePath()), getPathForMovingFile(file), StandardCopyOption.ATOMIC_MOVE);
    } finally {
      LOCK.unlock();
    }
  }

  private Path getPathForMovingFile(File fileForMove) {
    File fileList[] = errorFolder.listFiles();
    int filesWithSameNameCounter = 0;
    if (fileList != null && fileList.length > 0) {
      for (File file : fileList) {
        if (file.getName().contains(fileForMove.getName())) {
          filesWithSameNameCounter++;
        }
      }
    }
    return filesWithSameNameCounter > 0 ?
        Paths.get(errorFolder.getAbsolutePath(), "(" + filesWithSameNameCounter + ")" + fileForMove.getName()) :
        Paths.get(errorFolder.getAbsolutePath(), fileForMove.getName());
  }
}

方面

@Aspect
@Component
@ConditionalOnProperty(
    value = "file-processing.logging.enabled",
    havingValue = "true",
    matchIfMissing = true)
public class FileProcessingLoggingAspect {

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

  @Pointcut("execution(* com.epam.esm.processor.FileProcessor.processFile(java.io.File))")
  public void processFilePointcut() {
  }

  @Around("processFilePointcut()")
  public Object logFileProcessing(ProceedingJoinPoint joinPoint) throws Throwable {
//    File file = (File) joinPoint.getArgs()[0];
//    long time = System.currentTimeMillis();
    Object object = joinPoint.proceed();
//    long resultTime = System.currentTimeMillis() - time;
    LOGGER.info("Processing of file took  milliseconds");
    return object;
  }
}

【问题讨论】:

  • 请举例说明您想建议的课程类型。该类是否注册为 Spring bean?你有什么努力让它发挥作用?为什么没有呢?
  • @SotiriosDelimanolis 添加了信息,不,它没有注册为 Spring bean
  • @SotiriosDelimanolis 如果对象没有注册为spring bean就不行?
  • 不,建议仅应用于 Spring Application Context 中的 bean。
  • @SotiriosDelimanolis editi 我的应用程序的结构,但 processFile 方法的切入点仍然不起作用,但是如果我在运行时更改方法,它可以工作,哪里有问题?你能帮忙吗?

标签: java multithreading concurrency aop


【解决方案1】:

在 Spring AOP 中,内部方法调用不能被拦截。

在共享代码中,即使 processFile() 方法是 public ,它也会从 run() 调用。这是一个自引用/内部方法调用,不能被拦截。

详情可阅读documentation

由于 Spring 的 AOP 框架基于代理的特性,内部调用 根据定义,目标对象不会被拦截。对于 JDK 代理,只能在代理上调用公共接口方法 拦截

截取对实现Runnable的类的所有外部方法调用的切入点表达式如下

@Around("this(java.lang.Runnable) && within(com.epam.esm.processor..*)")
public Object logFileProcessing(ProceedingJoinPoint pjp) throws Throwable {

    try {
        return pjp.proceed();
    } finally {
        //log
        System.out.println("****Logged");
    }
}

范围指示符within() 限制应用建议的范围。

切入点@Pointcut("execution(* com.epam.esm.processor.FileProcessor.processFile(java.io.File))") 是有效的,并且在发生外部方法调用时会起作用。

希望这会有所帮助。

【讨论】:

  • 已经获得并实现了加载时编织,但无论如何都是 ty。
猜你喜欢
  • 2018-04-13
  • 2011-08-12
  • 2012-11-04
  • 2012-09-30
  • 1970-01-01
  • 2015-06-09
  • 2012-09-12
  • 2015-11-22
  • 1970-01-01
相关资源
最近更新 更多