@PreDestroy 和 Spring AOP 兼容性

@PreDestroy and Spring AOP compatibility

我想做一些关于正常关机的工作。
我试过下面显示的方法,但它不起作用。
我找到了一个解决方法(在 ContextClosedEvent 的 @EventListener 标记的方法上放置方面注释),但我想了解它失败的原因(audit() 方法没有任何例外根本没有被调用)。

@SpringBootApplication
public class Application {

    public static void main(String args[]) {
       SpringApplication.run(Application.class, args);
    }
    
    @AuditProcess
    @PreDestroy
    public void destroy() {
    }
}
@Aspect
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class AuditProcessAspect {

    @Pointcut("@annotation(com.aaa.bbb.annotation.AuditProcess) && execution(public * *(..))")
    public void executionOfPublicAuditableMethod() {
    }

    @Around("executionOfPublicAuditableMethod()")
    public Object audit(ProceedingJoinPoint joinPoint) {
        // some business logic ...
    }
}

据我挖掘 Spring 5 个胆量,我发现 @PreDestroy 由 CommonAnnotationBeanPostProcessor 处理,@Aspect 类 由 AspectJAdvisorFactory (CGLIB) 转换为 Spring AOP Advisors在 JDK 代理上,我猜)。因此,我不明白,为什么在将 SIGTERM 发送到应用程序的 JVM 进程后不调用方面逻辑。我什至检查了 System.out.println(this.getClass().getCanonicalName()) 的输出,它被放入 destroy() 方法的主体中 - 例如,它看起来像 Application$$EnhancerBySpringCGLIB$$25f99bf7。从我目前的观点来看,没有什么可以阻止方面环绕@PreDestroy 回调方法。
然而,它不起作用。
有人可以解释为什么吗?

如果像appContext.getBean(Application.class).destroy()那样手动调用pre-destroy方法,就会触发该方面。但是在应用程序被销毁的生命周期部分,似乎不再应用任何方面。

根据 @PreDestroy javadoc,带注释的目标方法可能是私有的,甚至是最终的,即两个特征与基于代理的 Spring AOP 用法相矛盾。我根本不是 Spring 或 Java EE 用户,我可能是错的,但对我来说,这似乎不应该按照您期望的方式工作。 Spring 附近的专家,如 M. Deinum 或 R.G 可能能够进一步阐明这个问题。

以下是我的分析。 main() 修改方法以说明 bean 方法触发器。

@SpringBootApplication
public class MainApp {
    
    public static void main(String[] args) {
        ConfigurableApplicationContext context = new SpringApplication(MainApp.class).run(args);
        MainApp app = context.getBean(MainApp.class);
        app.destroy();
    }


    @PreDestroy
    @AuditProcess
    public void destroy() {
        System.out.println("PreDestroy");
    }
}

当在 main() 方法中调用 app.destory() 时,调用在代理上完成

MainApp$$EnhancerBySpringCGLIB$$f2c7a1b4(MainApp).destroy() line: 25    
MainApp$$FastClassBySpringCGLIB$fbee297.invoke(int, Object, Object[]) line: not available 
MethodProxy.invoke(Object, Object[]) line: 218  
... 
MyAspect.preDestroyLog(ProceedingJoinPoint) line: 27    
... 
CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 692  
MainApp$$EnhancerBySpringCGLIB$$b98f9ed6.destroy() line: not available  
MainApp.main(String[]) line: 18 

当 ApplicationContext 关闭时,生命周期回调是由 InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeDestroyMethods(Object, String) 在实际对象上完成的,而不是代理,因此没有建议发生。

MainApp$$EnhancerBySpringCGLIB$$f2c7a1b4(MainApp).destroy() line: 25    
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]  
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 62  
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
Method.invoke(Object, Object...) line: 566  
InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(Object) line: 389    
InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeDestroyMethods(Object, String) line: 347 
CommonAnnotationBeanPostProcessor(InitDestroyAnnotationBeanPostProcessor).postProcessBeforeDestruction(Object, String) line: 177    
DisposableBeanAdapter.destroy() line: 242   
DefaultListableBeanFactory(DefaultSingletonBeanRegistry).destroyBean(String, DisposableBean) line: 587  
DefaultListableBeanFactory(DefaultSingletonBeanRegistry).destroySingleton(String) line: 559 
DefaultListableBeanFactory.destroySingleton(String) line: 1152  
DefaultListableBeanFactory(DefaultSingletonBeanRegistry).destroySingletons() line: 520  
DefaultListableBeanFactory.destroySingletons() line: 1145   
AnnotationConfigApplicationContext(AbstractApplicationContext).destroyBeans() line: 1111    
AnnotationConfigApplicationContext(AbstractApplicationContext).doClose() line: 1080 
AbstractApplicationContext.run() line: 996