使用生成器创建应用程序范围的类成员
是否正确地说,在下面的代码中,Hazelcast实例将是应用程序作用域?
@ApplicationScoped public class Producer { private HazelcastInstance instance; @PostConstruct public void afterCreate() { instance = Hazelcast.newHazelcastInstance(); } @Produces public HazelcastInstance getInstance() { return instance; } }
编辑
这个解决方案
- 确保生产的应用范围。
- 提供优雅的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的对象在应用程序的持续时间内创建一次。
取自这里