@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
我想做一些关于正常关机的工作。
我试过下面显示的方法,但它不起作用。
我找到了一个解决方法(在 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