A diferença entre CDI e EJB Singleton

A diferença entre CDI e EJB Singleton

1. Visão geral

Neste tutorial, daremos uma olhada mais de perto em dois tipos desingletons disponíveis no Java EE. Vamos explicar e demonstrar as diferenças e ver os usos adequados para cada um.

Primeiro, vamos ver o que são os singletons antes de entrar em detalhes.

2. Padrão de Design Singleton

Lembre-se de que uma maneira comum de implementarSingleton Pattern é com uma instância estática e um construtor privado:

public final class Singleton {
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

Mas, infelizmente, isso não é realmente orientado a objetos. E tem algunsmulti-threading issues.

No entanto, os containers CDI e EJB nos fornecem uma alternativa orientada a objetos.

3. CDI Singleton

ComCDI (Contexts and Dependency Injection), podemos criar singletons facilmente usando a anotação@Singleton. Esta anotação faz parte do pacotejavax.inject. Ele instrui o contêiner parainstantiate the singleton oncee passa sua referência para outros objetos durante a injeção.

Como podemos ver, a implementação de singleton com CDI é muito simples:

@Singleton
public class CarServiceSingleton {
    // ...
}

Nossa turma simula uma oficina de automóveis. Temos várias instâncias de váriosCars, mas todas usam a mesma loja para manutenção. Portanto, Singleton é um bom ajuste.

Podemos verificar se é a mesma instância com um teste JUnit simples que solicita o contexto para a classe duas vezes. Observe que temos um método auxiliargetBean aqui para facilitar a leitura:

@Test
public void givenASingleton_whenGetBeanIsCalledTwice_thenTheSameInstanceIsReturned() {
    CarServiceSingleton one = getBean(CarServiceSingleton.class);
    CarServiceSingleton two = getBean(CarServiceSingleton.class);
    assertTrue(one == two);
}

Because of the @Singleton annotation, the container will return the same reference both times. Se tentarmos isso com um bean gerenciado simples, entretanto, o contêiner fornecerá uma instância diferente a cada vez.

E embora isso funcione da mesma forma parajavax.inject.Singleton oujavax.ejb.Singleton, there’s a key difference between these two.

4. EJB Singleton

Para criar um singleton EJB, usamos a anotação@Singleton do pacotejavax.ejb. Desta forma, criamos umSingleton Session Bean.

Podemos testar essa implementação da mesma maneira que testamos a implementação do CDI no exemplo anterior, e o resultado será o mesmo. Singletons EJB, como esperado, fornecem a instância única da classe.

No entanto,EJB Singletons also provide additional functionality in the form of container-managed concurrency control.

Quando usamos esse tipo de implementação, o contêiner EJB garante que todos os métodos públicos da classe sejam acessados ​​por um único encadeamento por vez. Se vários threads tentarem acessar o mesmo método, apenas um thread poderá usá-lo enquanto outros aguardam sua vez.

Podemos verificar esse comportamento com um teste simples. Apresentaremos uma simulação de fila de serviço para nossas classes singleton:

private static int serviceQueue;

public int service(Car car) {
    serviceQueue++;
    Thread.sleep(100);
    car.setServiced(true);
    serviceQueue--;
    return serviceQueue;
}

serviceQueue é implementado como um inteiro estático simples que aumenta quando um carro “entra” no serviço e diminui quando ele “sai”. Se o contêiner fornecer um bloqueio adequado, essa variável deverá ser igual a zero antes e depois do serviço e igual a uma durante o serviço.

Podemos verificar esse comportamento com um teste simples:

@Test
public void whenEjb_thenLockingIsProvided() {
    for (int i = 0; i < 10; i++) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                int serviceQueue = carServiceEjbSingleton.service(new Car("Speedster xyz"));
                assertEquals(0, serviceQueue);
            }
        }).start();
    }
    return;
}

Este teste inicia 10 threads paralelos. Cada thread instancia um carro e tenta repará-lo. Após o atendimento, afirma que o valor deserviceQueue voltou a zero.

Se, por exemplo, executarmos um teste semelhante no CDI singleton, nosso teste falhará.

5. Conclusão

Neste artigo, passamos por dois tipos de implementações singleton disponíveis no Java EE. Vimos suas vantagens e desvantagens e também demonstramos como e quando usar cada um.

E, como sempre, o código-fonte completo está disponívelover on GitHub.