部署应用至GlassFish 4.1.2时出现PreDestroy异常求助
部署应用时出现PreDestroy异常
环境详情
- GlassFish 4.1.2完整平台
- JDK版本:1.8.0_171
- 操作系统:macOS 10.13.4
- 数据库:H2内存数据库
问题描述
将war文件部署至GlassFish时出现以下异常:
The lifecycle method [close] must not throw a checked exception
我期望该war文件能像在其他JEE容器中一样成功部署。
可复现性
Exception while deploying the app [sec-access-issue-0.1] : The lifecycle method [close] must not throw a checked exception. Related annotation information: annotation [@javax.annotation.PreDestroy()] on annotated element [public void org.grails.async.factory.future.CachedThreadPoolPromiseFactory.close() throws java.io.IOException] of type [METHOD] The lifecycle method [close] must not throw a checked exception. Related annotation information: annotation [@javax.annotation.PreDestroy()] on annotated element [public void org.glassfish.apf.impl.AnnotationProcessorImpl.process(AnnotationProcessorImpl.java:373) at org.glassfish.apf.impl.AnnotationProcessorImpl.process(AnnotationProcessorImpl.java:381) at org.glassfish.apf.impl.AnnotationProcessorImpl.processAnnotations(AnnotationProcessorImpl.java:289) at org.glassfish.apf.impl.AnnotationProcessorImpl.process(AnnotationProcessorImpl.java:217) at org.glassfish.apf.impl.AnnotationProcessorImpl.process(AnnotationProcessorImpl.java:134) at com.sun.enterprise.deployment.archivist.Archivist.processAnnotations(Archivist.java:627) at com.sun.enterprise.deployment.archivist.Archivist.readAnnotations(Archivist.java:463) at com.sun.enterprise.deployment.archivist.Archivist.readAnnotations(Archivist.java:447) at org.glassfish.web.deployment.archivist.WebArchivist.postAnnotationProcess(WebArchivist.java:338) at org.glassfish.web.deployment.archivist.WebArchivist.postAnnotationProcess(WebArchivist.java:91) at com.sun.enterprise.deployment.archivist.Archivist.readRestDeploymentDescriptors(Archivist.java:421) at com.sun.enterprise.deployment.archivist.Archivist.readDeploymentDescriptors(Archivist.java:396) at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:271) at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:280) at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:241) at com.sun.enterprise.deployment.archivist.ApplicationFactory.openArchive(ApplicationFactory.java:161) at org.glassfish.javaee.core.deployment.DolProvider.processDOL(DolProvider.java:203) at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:227) at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:96) at com.sun.enterprise.v3.server.ApplicationLifecycle.loadDeployer(ApplicationLifecycle.java:881) at com.sun.enterprise.v3.server.ApplicationLifecycle.setupContainerInfos(ApplicationLifecycle.java:821) at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:377) at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:219) at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:491) at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:539) at com.sun.enterprise.v3.admin.CommandRunnerImpl$2$1.run(CommandRunnerImpl.java:535) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:360) at com.sun.enterprise.v3.admin.CommandRunnerImpl$2.execute(CommandRunnerImpl.java:534) at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:565) at com.sun.enterprise.v3.admin.CommandRunnerImpl$3.run(CommandRunnerImpl.java:557) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:360) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:556) at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1464) at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1300(CommandRunnerImpl.java:109) at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1846) at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1722) at org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:253) at org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:231) at org.glassfish.admin.rest.utils.ResourceUtil.runCommand(ResourceUtil.java:275) at org.glassfish.admin.rest.resources.TemplateListOfResource.createResource(TemplateListOfResource.java:133) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at s
问题原因
这个异常的核心原因是Java EE规范明确要求标注了@PreDestroy的生命周期方法不能抛出受检异常(Checked Exception),而你代码中的org.grails.async.factory.future.CachedThreadPoolPromiseFactory.close()方法不仅标注了@PreDestroy,还声明抛出java.io.IOException(这是一个受检异常)。
GlassFish对Java EE规范的执行比较严格,而其他JEE容器可能放宽了这个限制,所以你的应用在其他容器能正常部署,但在GlassFish里触发了这个校验错误。
解决方案
根据你的情况,可以尝试以下几种方案:
1. 修改目标方法(如果是自定义代码)
如果这个CachedThreadPoolPromiseFactory是你自己的代码,直接修改close()方法:
- 把方法签名中的
throws java.io.IOException去掉 - 在方法内部捕获
IOException,要么内部处理(比如打印日志),要么转换成非受检异常(比如RuntimeException)抛出:
@PreDestroy public void close() { try { // 原有的close逻辑 } catch (IOException e) { // 记录日志 logger.error("Failed to close thread pool", e); // 或者转成RuntimeException抛出 throw new RuntimeException("Failed to close thread pool", e); } }
2. 处理第三方类(如果是Grails框架类)
如果这个类是Grails框架自带的,你可以:
- 升级Grails版本:检查Grails的更新日志,看后续版本是否修复了这个不符合规范的问题
- 使用拦截器或代理包装:创建一个代理类或者拦截器,包装原有的
CachedThreadPoolPromiseFactory,在代理类的@PreDestroy方法中调用原方法并处理异常 - 调整GlassFish配置(不推荐):虽然不建议,但可以尝试关闭GlassFish的注解校验严格性(不过可能会引入其他潜在问题,不推荐生产环境使用)
3. 排除相关类的注解扫描
如果你的应用使用了组件扫描,可以尝试在GlassFish部署时排除org.grails.async.factory.future.CachedThreadPoolPromiseFactory类的注解扫描,但这种方法需要结合你的应用配置来调整,比如在beans.xml中配置扫描排除规则。
内容的提问来源于stack exchange,提问作者ddelponte
相关产品推荐
相关产品推荐

