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

时间:2017-10-04 07:42:02

标签: java java-ee cdi hazelcast

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

@ApplicationScoped
public class Producer {

    private HazelcastInstance instance;

    @PostConstruct
    public void afterCreate() {
        instance = Hazelcast.newHazelcastInstance();
    }

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

修改

此解决方案:

  1. 确保生成的是应用程序作用域。
  2. 提供优雅的Hazelcast关闭。
  3. @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;
        }
    }
    

3 个答案:

答案 0 :(得分:4)

Producer bean将是应用程序作用域,这很清楚。 但是, HazelnutInstance bean将为@Dependent

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

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

但是,请留意豆生命周期!当注入它们的bean被销毁时,将销毁@Dependent个bean。所以现在假设它涉及到这样的破坏尝试 - Weld将尝试销毁你的依赖bean并将调用@PreDestroy(在"经典" bean)或@Disposes(在有生产者的bean上)方法就可以了。

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

如果你使HazelcastInstance应用程序作用域,你会更好。 E.g。

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

答案 1 :(得分:1)

我想通过单元测试来证明预期的行为。

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

<强> 环境

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。依赖类和生成器,后构造实例:FAIL

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

instance

单元测试

@Dependent
public class Producer {

    private HazelcastInstance instance;

    private Producer() {}

    @PostConstruct
    public void afterCreate() {
        instance = Hazelcast.newHazelcastInstance();
    }

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

<强> arquillian.xml

@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));
    }
}

<强> hazelcast.xml

<?xml version="1.0"?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://jboss.org/schema/arquillian"
    xsi:schemaLocation="http://jboss.org/schema/arquillian http://www.jboss.org/schema/arquillian/arquillian_1_0.xsd">
    <container qualifier="wls-remote" default="true">
        <configuration>
            <property name="wlHome">PATH_TO_WLSERVER_DIRECTORY</property>
            <property name="adminUrl">ADMIN_URL</property>
            <property name="adminUserName">USER_NAME</property>
            <property name="adminPassword">PASSWORD</property>
            <property name="target">TARGET_SERVER</property>
        </configuration>
    </container>
</arquillian>

为了完整性,POM

<强>的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<hazelcast
        xsi:schemaLocation="http://www.hazelcast.com/schema/config
        http://www.hazelcast.com/schema/config/hazelcast-config-3.5.xsd"
        xmlns="http://www.hazelcast.com/schema/config"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <group>
        <name>producer</name>
        <password>producer_pass</password>
    </group>

    <network>
        <port auto-increment="false">10710</port>
        <join>
            <multicast enabled="false" />
            <tcp-ip enabled="true">
                <member>localhost</member>
            </tcp-ip>
        </join>
    </network>

</hazelcast>

答案 2 :(得分:-2)

是的,制作人将收到您使用注释test class应用的范围。这将导致整个CDI应用程序只有一个实例。对类<agm-map #gm [fitBounds]="latlngBounds" [zoom]="15"> <agm-marker *ngFor="let m of markers; let i = index" [latitude]="m.geoCode.latitude" [longitude]="m.geoCode.longitude" (mouseOver)="onMouseOver(infoWindow,gm)" > <agm-info-window [disableAutoPan]="false" #infoWindow> <div> {{m.name}} {{m.rating}} </div> <div> <a (click)="onClickInfoView({id:m.id})" class="btn btn-attention pull-right">Daje <i class="fa fa-angle-double-right"></i></a> </div> </agm-info-window> </agm-marker> </agm-map> onMouseOver(infoWindow, gm) { if (gm.lastOpen != null) { gm.lastOpen.close(); } gm.lastOpen = infoWindow; infoWindow.open(); } 的每个请求都将来到该类的同一个实例,因为它只会被初始化一次然后保持活动状态。由于Producer是应用程序范围的,@ApplicationScoped的实例不会改变,只要你不在类本身中更改它(例如setter)

  

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

取自here