使用生成器创建应用程序范围的类成员

是否正确地说,在下面的代码中,Hazelcast实例将是应用程序作用域?

@ApplicationScoped public class Producer { private HazelcastInstance instance; @PostConstruct public void afterCreate() { instance = Hazelcast.newHazelcastInstance(); } @Produces public HazelcastInstance getInstance() { return instance; } } 

编辑

这个解决方案

  1. 确保生产的应用范围。
  2. 提供优雅的Hazelcast关闭。
 @ApplicationScoped public class Producer { private HazelcastInstance instance; private Producer() {} @PostConstruct public void afterCreate() { instance = Hazelcast.newHazelcastInstance(); } @PreDestroy public void beforeDestroy() { if(instance != null) { instance.shutdown(); } } @Produces @ApplicationScoped public HazelcastInstance getInstance() { return instance; } } 

你的Producer bean将是应用程序作用域,那很清楚。 但是, HazelnutInstance bean将是@Dependent

因此,如果您在代码中的某处执行@Inject HazelnutInstance ,它将从CDI视点注入一个依赖实例。

但是你总是返回相同的实例,从不在你的制作人中创建新的对象,所以理论上 ,你正在共享那个实例。

但是,请留意豆生命周期! @Dependent bean在被注入的bean被销毁时将被销毁。 因此,现在假设它涉及到这样的破坏尝试–Weld将尝试销毁您的依赖bean并将调用@PreDestroy (在“经典”bean上)或@Disposes (在使用生产者的bean上)方法。

因此,在您的情况下,如果某个处理HazelcastInstance的处理器方法可能会导致麻烦,因为每次Weld尝试销毁/处置该依赖bean时都会调用它。

IMO如果你制作HazelcastInstance应用程序,你会更好。 例如

 @Produces @ApplicationScoped public HazelcastInstance getInstance() { return instance; } 

我想得到一个unit testing来certificate预期的行为。

代码和结果可以在下面找到。

环境

UT使用arquillian针对WebLogic 12.2.1远程容器启动

1. ApplicationScoped类和生产者,新实例 :PASS

正如预期的那样,测试传递:生成的bean是应用程序作用域,因此注入相同的实例。

 @ApplicationScoped public class Producer { private Producer() {} @Produces @ApplicationScoped public HazelcastInstance getInstance() { return Hazelcast.newHazelcastInstance(); } } 

2. ApplicationScoped类和Dependent生成器,新实例 :FAIL

正如预期的那样,测试失败:生成的bean是@Dependent ,注入了不同的实例。 (注意: @Dependent是默认范围,它可以存在也可以不存在,相同的结果将是相同的)。

 @ApplicationScoped public class Producer { private Producer() {} @Produces public HazelcastInstance getInstance() { return Hazelcast.newHazelcastInstance(); } } 

3. ApplicationScoped类和Dependent生成器,post构造实例 :PASS

正如预期的那样,测试传递:生成的instance bean是@Dependent 。 但是,它的生命周期间接绑定到Producer生命周期(通过@PostConstruct调用一次),因此,每次调用时返回相同的实例,并在销毁生产者bean时取消引用。

注意 :Hazelcast在此实现中没有被正常关闭。

 @ApplicationScoped public class Producer { private HazelcastInstance instance; private Producer() {} @PostConstruct public void afterCreate() { instance = Hazelcast.newHazelcastInstance(); } @Produces public HazelcastInstance getInstance() { return instance; } } 

4. ApplicationScoped类和ApplicationScoped生成器,post构造实例 :PASS

正如预期的那样,测试传递:生成的bean是@ApplicationScoped并且在应用程序生命周期中返回相同的实例。

 @ApplicationScoped public class Producer { private HazelcastInstance instance; private Producer() {} @PostConstruct public void afterCreate() { instance = Hazelcast.newHazelcastInstance(); } @Produces @ApplicationScoped public HazelcastInstance getInstance() { return instance; } } 

5.依赖类和ApplicationScoped生成器,post构造实例 :PASS

这个结果令人惊讶:Producer被注释为@Dependent ,它的生产者是@ApplicationScoped ,结果是每个Producer实例返回相同的实例。 原因:CDI使用作用域上下文

 @Dependent public class Producer { private HazelcastInstance instance; private Producer() {} @PostConstruct public void afterCreate() { instance = Hazelcast.newHazelcastInstance(); } @Produces @ApplicationScoped public HazelcastInstance getInstance() { return instance; } } 

6.依赖类和生成者,post构造实例 :FAIL

正如预期的那样,测试失败:生成的bean是@Dependent ,注入了不同的实例。 (注意: @Dependent是默认范围,它可以或不存在,相同的结果将是相同的)因为每个Producer实例将调用它自己的afterCreate方法,导致不同的instance实例

 @Dependent public class Producer { private HazelcastInstance instance; private Producer() {} @PostConstruct public void afterCreate() { instance = Hazelcast.newHazelcastInstance(); } @Produces public HazelcastInstance getInstance() { return instance; } } 

unit testing

 @RunWith(Arquillian.class) public class ProducerTest { @Deployment public static WebArchive createDeployment() { // Import Maven runtime dependencies File[] files = Maven.resolver() .loadPomFromFile("pom.xml") .importRuntimeDependencies() .resolve() .withTransitivity() .asFile(); // Create deploy file WebArchive war = ShrinkWrap.create(WebArchive.class, ProducerTest.class.getName() + ".war") .addClass(Producer.class) .addClass(ProducerTest.class) .addAsLibraries(files); // Show the deploy structure System.out.println(war.toString(true)); return war; } @Inject private HazelcastInstance hzInstance1; @Inject private HazelcastInstance hzInstance2; @Before @After public void cleanup() { Hazelcast.shutdownAll(); assertEquals(emptySet(), getAllHazelcastInstances()); } @Test public void producerTest() { assertTrue(hzInstance1.equals(hzInstance2)); } } 

arquillian.xml

     PATH_TO_WLSERVER_DIRECTORY ADMIN_URL USER_NAME PASSWORD TARGET_SERVER    

hazelcast.xml

    producer producer_pass   10710    localhost     

为了完整性,POM

的pom.xml

  4.0.0 HeyStackExchange cdi-test 0.0.1-SNAPSHOT jar https://stackoverflow.com/questions/46559523/scoped-instance Arquillian WLS 12.1.x/12.2.x - CDI Example  UTF-8 UTF-8 1.8 1.8 1.8 3.6.1 1.1.5.Final  1.1.0.Final  1.0.1.Final  3.8.3  4.8.2  1.7.25 1.7.9     maven-compiler-plugin ${maven-compiler-plugin.version}  ${maven.compiler.source} ${maven.compiler.target}        org.jboss.arquillian arquillian-bom ${arquillian.version} import pom       org.jboss.spec jboss-javaee-7.0 ${jboss-javaee-7.0.version} pom provided    com.hazelcast hazelcast ${hazelcast.version}    org.jboss.shrinkwrap.resolver shrinkwrap-resolver-impl-maven test   org.jboss.arquillian.junit arquillian-junit-container test   org.jboss.arquillian.container arquillian-wls-remote-12.1.x   junit junit ${junit.version} test    org.slf4j slf4j-api ${slf4j-api.version}   org.slf4j slf4j-log4j12 ${slf4j-log4j12.version}    

是的,制作人将收到您使用注释@ApplicationScoped应用的范围。 这将导致整个CDI应用程序只有一个实例。 对Producer类的每个请求都将来到同一个类的实例,因为它只会被初始化一次然后保持活动状态。 由于Producer是应用程序作用域, Hazelcast的实例不会改变,只要你不在类本身中更改它(例如setter)

定义为@ApplicationScoped的对象在应用程序的持续时间内创建一次。

取自这里

Interesting Posts