【问题标题】:Why @PostConstruct called twice on @Singleton为什么@PostConstruct 在@Singleton 上调用了两次
【发布时间】:2013-05-10 05:52:27
【问题描述】:

我正在 Glassfish 4.0-b87 下运行一个简单的 .war 文件,该文件是在 Eclipse Kepler M6 中使用 M2E 作为一个简单项目创建的,并使用 Oracle Java 7 JDK/JVM 添加了动态 Web 模块方面。

基本上有一个类,我希望post_construct 方法只被调用一次。但它会被调用两次,第一次是在部署应用程序时调用,然后在第一个且仅是第一个 HTTP 请求时再调用一次。

这是类(日志输出如下):

package com.example.main;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.LocalBean;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.enterprise.inject.spi.PassivationCapable;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;

@Singleton
@Startup
@LocalBean
@ApplicationPath("/rest")
@Path("/life")
public class Life extends Application implements PassivationCapable {

  @PostConstruct
  public void post_construct () {
    System.out.println("hello world!");
  }

  @PreDestroy
  public void pre_destroy () {
    System.out.println("so long and thanks for the fish!");
  }

  @PrePassivate
  public void pre_passivate () {
    System.out.println("taking a break");
  }

  @PostActivate
  public void post_activate () {
    System.out.println("back from break");
  }

  @Override
  public String getId () {
    return "life";
  }

  @GET
  public String greet () {
    return "hi";
  }
}

日志输出如下,用虚线分隔第一次HTTP调用前和HTTP调用后的部分:

[2013-05-09T19:42:26.660-1000] [glassfish 4.0] [INFO] [NCLS-DEPLOYMENT-00027] [javax.enterprise.system.tools.deployment.autodeploy] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546660] [levelValue: 800] [[
  Selecting file /usr/local/glassfish4/glassfish/domains/domain1/autodeploy/singleton.war for autodeployment]]

[2013-05-09T19:42:26.692-1000] [glassfish 4.0] [INFO] [] [javax.enterprise.system.tools.deployment.common] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546692] [levelValue: 800] [[
  visiting unvisited references]]

[2013-05-09T19:42:26.702-1000] [glassfish 4.0] [INFO] [] [javax.enterprise.system.tools.deployment.common] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546702] [levelValue: 800] [[
  visiting unvisited references]]

[2013-05-09T19:42:26.706-1000] [glassfish 4.0] [INFO] [] [javax.enterprise.system.tools.deployment.common] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546706] [levelValue: 800] [[
  visiting unvisited references]]

[2013-05-09T19:42:26.709-1000] [glassfish 4.0] [INFO] [] [javax.enterprise.system.tools.deployment.common] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546709] [levelValue: 800] [[
  visiting unvisited references]]

[2013-05-09T19:42:26.749-1000] [glassfish 4.0] [INFO] [ejb.portable_jndi_names] [javax.enterprise.system.container.ejb.com.sun.ejb.containers] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546749] [levelValue: 800] [[
  EJB5181:Portable JNDI names for EJB Life: [java:global/singleton/Life, java:global/singleton/Life!com.example.main.Life]]]

[2013-05-09T19:42:26.959-1000] [glassfish 4.0] [WARNING] [] [org.jboss.weld.Bootstrap] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546959] [levelValue: 900] [[
  WELD-001473 javax.enterprise.inject.spi.Bean implementation org.glassfish.jms.injection.JMSCDIExtension$LocalBean@cbcbf4a declared a normal scope but does not implement javax.enterprise.inject.spi.PassivationCapable. It won't be possible to inject this bean into a bean with passivating scope (@SessionScoped, @ConversationScoped). This can be fixed by assigning the Bean implementation a unique id by implementing the PassivationCapable interface.]]

[2013-05-09T19:42:26.970-1000] [glassfish 4.0] [INFO] [] [] [tid: _ThreadID=59 _ThreadName=Thread-3] [timeMillis: 1368164546970] [levelValue: 800] [[
  hello world!]]

[2013-05-09T19:42:26.982-1000] [glassfish 4.0] [INFO] [] [org.glassfish.jersey.servlet.init.JerseyServletContainerInitializer] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546982] [levelValue: 800] [[
  Registering the Jersey servlet application, named com.example.main.Life, at the servlet mapping /rest/*, with the Application class of the same name.]]

[2013-05-09T19:42:26.988-1000] [glassfish 4.0] [INFO] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164546988] [levelValue: 800] [[
  Loading application [singleton] at [/singleton]]]

[2013-05-09T19:42:27.003-1000] [glassfish 4.0] [INFO] [] [javax.enterprise.system.core] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164547003] [levelValue: 800] [[
  singleton was successfully deployed in 332 milliseconds.]]

[2013-05-09T19:42:27.006-1000] [glassfish 4.0] [INFO] [NCLS-DEPLOYMENT-00035] [javax.enterprise.system.tools.deployment.autodeploy] [tid: _ThreadID=59 _ThreadName=AutoDeployer] [timeMillis: 1368164547006] [levelValue: 800] [[
  [AutoDeploy] Successfully autodeployed : /usr/local/glassfish4/glassfish/domains/domain1/autodeploy/singleton.war.]]

------------------在第一次 HTTP 调用之后------------- ------------------

[2013-05-09T19:42:44.940-1000] [glassfish 4.0] [INFO] [] [] [tid: _ThreadID=21 _ThreadName=Thread-3] [timeMillis: 1368164564940] [levelValue: 800] [[
  hello world!]]

[2013-05-09T19:42:44.940-1000] [glassfish 4.0] [INFO] [] [org.glassfish.jersey.server.ApplicationHandler] [tid: _ThreadID=21 _ThreadName=http-listener-1(4)] [timeMillis: 1368164564940] [levelValue: 800] [[
  Initiating Jersey application, version Jersey: 2.0-rc2 2013-04-23 12:04:25...]]

[2013-05-09T19:42:44.956-1000] [glassfish 4.0] [INFO] [] [org.glassfish.jersey.gf.ejb.EjbComponentProvider] [tid: _ThreadID=21 _ThreadName=http-listener-1(4)] [timeMillis: 1368164564956] [levelValue: 800] [[
  The Jersey EJB interceptor is bound. JAX-RS EJB integration support is enabled.]]

【问题讨论】:

    标签: jakarta-ee glassfish ejb jersey jax-rs


    【解决方案1】:

    <update> 这是 Glassfish 错误 https://java.net/jira/browse/GLASSFISH-20505 </update>

    @Singleton@ApplicationPath + extends Application 似乎相处得不好。也许行为是正确的,因为 JAX-RS 需要实例化 Application 类一次,而 EJB 需要实例化 @Singleton 一次,但在有人指出标准的相关部分之前,最好将其视为漏洞。 Jersey 应该识别 @Singleton 注释并寻找 extends Application 类而不是创建自己的类。

    解决可能的 Jersey 错误的解决方法是不要使用与 @Singleton 和 Jersey Application 类相同的类。

    【讨论】:

    • 这不是错误。您基本上是在一个类中将 Web 服务和业务服务紧密耦合在一起。您最终会得到同一个类的两个完全独立的实例,它们用于两个完全不同的目的。换句话说,只有糟糕的设计手段。只需将 webservice 逻辑和 businessservice 逻辑拆分为两个单独的类,并将 businessservice 作为@EJB 注入 webservice。
    • @BalusC 你的意思是@Application + @Singleton 耦合吗?还是@ApplicationPath + @Path 耦合?或@Singleton + @Path。我完全同意糟糕的设计,但糟糕的设计很可能会暴露 Glassfish 实现错误。我认为将@Path 分成一个类,将@Singleton + @ApplicationPath 放在一个类中显着改进了设计,但我敢打赌,它仍然会暴露 Glassfish 实现错误,当实例已经存在时,它会创建实例化一个新的extends Application 类。感谢您的评论!
    • 查看这些注释来自的包。 javax.ws.rs 是 JAX-RS 网络服务 API。 javax.ejb 是 EJB 业务服务 API。
    • @BalusC 这是来自 Oracle 本身的一个非常权威的参考,它展示了如何将 web 服务注释和业务服务注释放在同一个类上。请参阅oracle.com/technetwork/articles/java/jaxrs20-1929352.html 中的清单 4,因此您的那部分论点没有说服力。
    • Adam Bien 是 Java EE 布道者。将他的文章作为“最佳实践”,加点盐。他在这类文章中的唯一目的是炫耀 Java EE 6 的“圆滑”,摆脱 Java EE “沉重”的普遍共识。事实是,您通过这种方式本质上创建了 2 个完全不同的实例,它们不以任何方式共享它们的状态。您是否认为这明智取决于您,但 IMO 并非如此。这显然是紧耦合。
    猜你喜欢
    • 1970-01-01
    • 2014-02-03
    • 2013-04-21
    • 1970-01-01
    • 2012-12-12
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 2012-02-23
    相关资源
    最近更新 更多