提问者:小点点

@预拉伸和SpringAOP兼容性


我想在优雅的关闭上做一些工作。
我尝试了如下所示的方法,但它不起作用。
我找到了一个解决方法(在ContextClosedEvent的@EventListener标记方法上放置方面注释),但我想了解它失败的原因(Aud()方法没有任何异常根本没有调用)。

@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(我猜是JDK代理上的CGLIB)转换为Spring AOP顾问。因此,我不明白为什么在将SIGTERM发送到应用程序的JVM进程后不调用方面逻辑。我甚至检查了<code>System.out.println(this.getClass())的输出。getCanonicalName()),它被放在<code>destroy()方法的主体中-例如,它看起来像是应用程序$$EnhancerBySpringCGLIB$$25f99bf7。从我目前的观点来看,没有什么可以阻止方面围绕@PreDestroy回调方法包装<然而,它不起作用<有人能解释一下原因吗?


共2个答案

匿名用户

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

根据javadoc@PreDestroy,带注释的目标方法可能是私有的,甚至是最终的,即两个特征与基于代理的Spring AOP用法相矛盾。我根本不是Spring或Java EE用户,我可能是错的,但对我来说,这似乎不应该按照你期望的方式工作。像M. Deinum或R.G这样的Spring专家也许能够更多地了解这个问题。

匿名用户

以下是我的分析<修改了code>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$$8fbee297.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 

当Application ationContext关闭时,生命周期回调是由实际对象而不是代理上的InitDestRoyAnNotationBeanPostProcencer$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$1.run() line: 996