Java 在Spring前后,返回类型为void的目标方法上的AOP跳过代码执行

Java 在Spring前后,返回类型为void的目标方法上的AOP跳过代码执行,java,spring,asynchronous,spring-aop,Java,Spring,Asynchronous,Spring Aop,据我所知,SpringAOP上的@Around注释可以处理方法上的任何返回类型;当void类型返回null时 这是记录方法持续时间的简单建议: @Target(ElementType.METHOD) @保留(RetentionPolicy.RUNTIME) public@interface Profiling{} @方面 @组成部分 公共类盈利方面{ // ... @周围(“@注释(profilingAnnotation)”) 公共对象日志持续时间(ProceedingJoinPoint、pr

据我所知,SpringAOP上的
@Around
注释可以处理方法上的任何返回类型;当
void
类型返回null时

这是记录方法持续时间的简单建议:

@Target(ElementType.METHOD)
@保留(RetentionPolicy.RUNTIME)
public@interface Profiling{}
@方面
@组成部分
公共类盈利方面{
// ...
@周围(“@注释(profilingAnnotation)”)
公共对象日志持续时间(ProceedingJoinPoint、profilingprofilingannotation)抛出可丢弃{
long startTime=Instant.now().toEpochMilli();
对象结果=空;
试一试{
result=joinPoint.procedure();//对于void方法,它应该返回null
}捕获(可丢弃的e){
logger.error(e.getMessage(),e);
投掷e;
}最后{
long-endTime=Instant.now().toEpochMilli();//下面的代码不是一起运行的
长持续时间=结束时间-开始时间;
logger.info(joinPoint.getSignature().ToSortString()+“:”+持续时间+“毫秒”);
}
//将结果返回给调用者
返回结果;
}
}
但是,在该方法上调用时,它不会返回任何内容,而是跳过
procedure()
之后的所有代码。偶数
最后

这是有问题的代码:

@GetMapping(“/members/exportpdf”)
@轮廓
public void exportToPDF(@RequestParam(required=false)字符串角色,HttpServletResponse)抛出DocumentException、IOException、ExecutionException、interruptedeexception{
可完成的未来行会成员;
如果(角色==null){
guildMembers=guildService.findAll();//异步方法
}否则{
guildMembers=guildService.findByType(角色);//异步方法
}
response.setContentType(“application/pdf”);
DateFormat dateFormatter=新的SimpleDateFormat(“yyyy-MM-dd_HH:MM:ss”);
字符串currentDateTime=dateFormatter.format(新日期());
字符串headerKey=“内容处置”;
String headerValue=“inline;filename=guildmembers_quot+currentDateTime+”.pdf”;
response.setHeader(headerKey,headerValue);
PDFExporter exporter=新的PDFExporter(行会成员);
exporter.export(response.get();//exporter.export(..)是一个返回CompletableFuture的异步方法
}
这怎么可能?我在配置中遗漏了什么吗?还是春天的虫子

注意。我正在使用SpringBoot2.4.4和starter依赖项


编辑
PDFExporter.export()
使用
HttpServletResponse
上的
OutputStream
向用户打印
application/pdf
,并返回
CompletableFuture
。至于原因,该方法与上面的异步函数通信,因此我想保证操作以某种方式完成。

为了教您什么是an以及如何在这里更好地提问,我将向您展示我根据您的代码片段和描述创建的MCVE:

我们需要依赖类来编译代码:

package de.scrum_master.spring.q66958382;
导入java.lang.annotation.ElementType;
导入java.lang.annotation.Retention;
导入java.lang.annotation.RetentionPolicy;
导入java.lang.annotation.Target;
@目标(ElementType.METHOD)
@保留(RetentionPolicy.RUNTIME)
public@interface Profiling{}
package de.scrum_master.spring.q66958382;
公会会员{
私有字符串名称;
公共行会成员(字符串名称){
this.name=名称;
}
@凌驾
公共字符串toString(){
返回“GuildMember{”+
“name=”+name+“\”+
'}';
}
}
PDFExporter
实用程序:

也许您正在使用PrimeFaces的
PDFExporter
,但这只是一个猜测。在任何情况下,它似乎都不是Spring组件,因为稍后您将调用构造函数,而不是从应用程序上下文获取bean实例。所以我在这里也将其建模为一个简单的POJO

package de.scrum_master.spring.q66958382;
导入org.springframework.scheduling.annotation.Async;
导入javax.servlet.http.HttpServletResponse;
导入java.util.List;
导入java.util.concurrent.CompletableFuture;
公共类PDFExporter{
可完成的未来行会成员;
公共PDFExporter(可完成的未来行会成员){
this.guildMembers=guildMembers;
}
@异步的
公共CompletableFuture导出(HttpServletResponse){
返回CompletableFuture.SupplySync(()->{
尝试{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}
返回null;
});
}
}
使用
@Async
方法的服务:

接下来,我对你的公会服务做了一个有根据的猜测:

package de.scrum_master.spring.q66958382;
导入org.springframework.scheduling.annotation.Async;
导入org.springframework.stereotype.Service;
导入java.util.array;
导入java.util.Collections;
导入java.util.List;
导入java.util.concurrent.CompletableFuture;
@服务
公共类行会服务{
@异步的
公共可完成的未来findAll(){
返回CompletableFuture.SupplySync(()->{
尝试{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}
返回数组.asList(新纪元成员(“Jane”)、新纪元成员(“John”)、新纪元成员(“Eve”);
});
}
@异步的
公共CompletableFuture findByType(字符串角色){
返回CompletableFuture.SupplySync(()->{
尝试{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}
返回集合。单一成员列表(新协会成员(“Eve”);
});
}
}
分析方面针对的组件:

这是您的示例组件,只是稍微简化了