Desenvolvendo Beans de Sessão Singleton
Crie uma classe de implementação de bean para um bean de sessão singleton, introduzida pela especificação Enterprise JavaBeans (EJB) 3.1. O contêiner EJB inicializa somente uma instância de um bean de sessão singleton, e essa instância é compartilhada por todos os clientes. Como uma única instância é compartilhada por todos os clientes, os beans de sessão singleton possuem ciclo de vida especial e semânticas de simultaneidade.
Antes de Iniciar
Sobre Esta Tarefa
public interface Configuration {
Object get(String name);
void set (String name, Object value);
}
@Singleton
public class ConfigurationBean implements Configuration {
private Map<String, Object> settings = new HashMap<String, Object>();
public Object get(String name) {
return settings.get(name);
}
public void set(String name, Object value) {
settings.put(name,value);
}
}
Como com outros tipos de enterprise bean, também é possível declarar metadados para beans de sessão singleton no descritor de implementação, em vez de usar anotações; por exemplo:
<?xml version="1.0"?>
<ejb-jar
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1"
>
<enterprise-beans>
<ejb-name>ConfigurationBean</ejb-name>
<business-local>com.ibm.example.Configuration</business-local>
<ejb-class>com.ibm.example.ConfigurationBean</ejb-class>
<session-type>Singleton</session-type>
</enterprise-beans>
</ejb-jar>
Procedimento
- Codifique os métodos de inicialização e destruição, entendendo como eles se
relacionam às suas opções para configurar o contexto de transação. Durante a inicialização, a instância é criada, ocorre a injeção de dependência e
os retornos de chamada do interceptor do ciclo de vida PostConstruct são iniciados. Os retornos de chamada do interceptor do ciclo de vida PreDestroy são iniciados para um bean de sessão singleton quando os aplicativos de contenção são parados.
Pode ser útil concluir as atividades transacionais durante os retornos de chamada do interceptor do ciclo de vida PostConstruct e PreDestroy. Por essa razão, os retornos de chamada do interceptor do ciclo de vida do bean de sessão singleton possuem um contexto de transação bem definido. Os seguintes valores de contexto de transação são semelhantes para os métodos @Timeout: apenas REQUIRED (padrão), REQUIRES_NEW e NOT_SUPPORTED podem ser usados e REQUIRED é convertido para REQUIRES_NEW.
Os atributos de transação são reconhecidos apenas quando estiverem especificados nos métodos do interceptor do ciclo de vida na classe de bean. O mesmo contexto de transação é usado para todos os interceptores do ciclo de vida. O exemplo a seguir ilustra um bean de sessão singleton com os atributos de transação especificados para os retornos de chamadas do interceptor de ciclo de vida PostConstruct e PreDestroy.
@Singleton public class ConfigurationBean implements Configuration { @PostConstruct @TransactionAttribute(REQUIRED) // o padrão; especificado para ilustração public void initialize() { // ... } @PreDestroy @TransactionAttribute(NOT_SUPPORTED) public void destroy() { // ... } // ... }
Em vez de usar uma anotação, é possível especificar os mesmos metadados usando o descritor de implementação XML. Se você especificar atributos de transação no descritor de implementação XML, os metadados obtidos a partir da anotação @TransactionAttribute serão ignorados. O exemplo a seguir usa o descritor de implementação XML para especificar os mesmos metadados do exemplo anterior.
<assembly-descriptor> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>initialize</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>destroy</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> </assembly-descriptor>
- A menos que seja especificado de maneira diferente, a instância do bean de sessão
singleton geralmente é inicializada quando o bean é usado pela primeira vez por meio de uma de suas
visualizações de cliente, que é a mesma de qualquer outro bean de sessão. Use a anotação @Startup ou o descritor de
implementação XML correspondente para marcar um bean como um bean de inicialização. Marcar um bean singleton como um
bean de inicialização significa que o contêiner EJB deve executar o método PostConstruct antes de ele
suportar quaisquer solicitações do cliente externas feitas no aplicativo para ser executado.
Um método PostConstruct em
um bean singleton pode criar um cronômetro EJB, incluir uma mensagem em uma fila ou um
tópico JMS, chamar um método EJB assíncrono ou iniciar outros mecanismos
assíncronos que chamam um EJB.
No entanto, para evitar um conflito, o método
PostConstruct não deve aguardar que um cronômetro EJB seja executado, um método de bean acionado
por mensagens seja chamado ou um método EJB assíncrono seja concluído.
Os desenvolvedores de aplicativo podem colocar a lógica de negócios nos métodos PostConstruct dessas instâncias singleton de inicialização para concluir as tarefas que devem ser executadas antes que qualquer trabalho do cliente seja iniciado pelo contêiner, como pré-carregar os caches ou inicializar o trabalho assíncrono no aplicativo.
O exemplo a seguir ilustra um bean de sessão singleton com a inicialização:
@Singleton @Startup public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // 1. Crie a tabela de banco de dados se ela não existir. // 2. Inicialize as configurações a partir da tabela de banco de dados. // 3. Carregue um cache. // 4. Inicie o trabalho assíncrono (por exemplo, trabalho para um fila de mensagens ou para // chamadas para métodos de bean de sessão assíncronos. } // ... }
Em vez de usar uma anotação, é possível especificar os mesmos metadados usando o descritor de implementação XML. Especifique true para marcar esse bean singleton como um singleton de inicialização. De modo contrário, especifique false, e anotação @Startup é substituída, se ele existir no arquivo de classe.
<session> <ejb-name>ConfigurationBean</ejb-name> <init-on-startup>true</init-on-startup> </session>
- Determine se o método de inicialização do bean de sessão
singleton possui uma dependência implícita em outro bean de sessão
singleton.
Se existir uma dependência implícita, use os metadados de dependência para torná-la explícita. O contêiner assegura que os beans singleton de dependência sejam inicializados antes da inicialização de seus beans dependentes e que sejam destruídos após a destruição de seus beans dependentes. O seguinte exemplo ilustra um bean de sessão singleton com metadados de dependência:
@Singleton public class DatabaseBean { @PostConstruct public void initialize() { // Criar tabelas de banco de dados. } } @Singleton @DependsOn({"DatabaseBean"}) public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // Inicializar configurações a partir de uma tabela de banco de dados. } // ... }
Além disso, é possível criar dependências de módulo cruzado usando a sintaxe ejb-link module.jar#bean. Dependências circulares não são suportadas e fazem com que o aplicativo falhe.
Em vez de usar uma anotação, é possível especificar os mesmos metadados usando o descritor de implementação XML. Se você especificar metadados de dependência no descritor de implementação XML, os metadados da anotação @DependsOn serão ignorados.
<session> <ejb-name>ConfigurationBean</ejb-name> <depends-on> <ejb-name>DatabaseBean</ejb-name> </depends-on> </session>
- Decida se deseja usar a simultaneidade gerenciada por contêiner ou a simultaneidade
gerenciado por bean. As anotações @Lock e @AccessTimeout não são aplicáveis quando a simultaneidade
gerenciada por bean for usada.
É possível implementar a anotação @ConcurrencyManagement apenas na classe do bean de sessão singleton. Ela não pode ser usada na classe que estende ou em nenhuma classe superior na árvore de herança de classe.
O exemplo de código a seguir ilustra um singleton com simultaneidade gerenciada por bean:@Singleton @ConcurrencyManagement(BEAN) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); synchronized public Object get(String name) { return settings.get(name); } synchronized public void set(String name, Object value) { settings.put(name, value); } }
Em vez de usar uma anotação, é possível especificar os mesmos metadados usando o descritor de implementação XML. Se os metadados forem especificados no descritor de implementação XML e ao usar a anotação @ConcurrencyManagement, o valor deverá corresponder ou o aplicativo falhará. O exemplo a seguir usa o descritor de implementação XML para especificar os mesmos metadados do exemplo anterior.
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrency-management-type>Bean</concurrency-management-type> </session>
O contêiner não executa nenhum bloqueio para cada método chamado. Em vez disso, o bean real é responsável para o bloqueio que é necessário. No exemplo, o provedor do bean escolheu implementar os métodos usando a palavra-chave sincronizada. Isso é suportado para os beans de sessão singleton com a simultaneidade gerenciada por bean, mas não é suportado para outros tipos de componentes de EJB. Não é necessário para o provedor de bean usar a palavra-chave para fornecer a simultaneidade. Por exemplo, o provedor do bean pode usar a classe java.util.concurrent.locks.ReentrantReadWriteLock que está localizada no JDK 5 e superior.
As semânticas de bloqueio necessárias para a especificação EJB 3.1 para a simultaneidade gerenciada por contêiner corresponde ao comportamento da classe java.util.concurrent.locks.ReentrantReadWriteLock.
- Se você estiver usando a simultaneidade gerenciada por contêiner, use a notação
@Lock para gerenciar a simultaneidade de métodos. O seguinte exemplo de código ilustra o singleton com simultaneidade gerenciada por contêiner.
@Singleton public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); @Lock(READ) public Object get(String name) { return settings.get(name); } public void set(String name, Object value) { settings.put(name, value); } }
Em vez de usar uma anotação, é possível especificar os mesmos metadados usando o descritor de implementação XML. Se os metadados forem especificados no descritor de implementação XML e na anotação @Lock, os metadados obtidos da anotação @Lock serão ignorados. O exemplo a seguir usa o descritor de implementação XML para especificar os mesmos metadados do exemplo anterior.
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> </concurrent-method> </session>
O exemplo também ilustra a anotação de um método com @Lock(READ) para indicar que o contêiner deve obter um bloqueio de leitura quando esse método é iniciado. Quando um método for anotado com @Lock, ele substituirá a anotação @Lock que é especificada no nível de classe. Quando não houver anotação @Lock no nível de classe, o padrão será um bloqueio de gravação. No exemplo, o @Lock(READ) no método será substituir o bloqueio de gravação padrão no nível da classe. Quando um método não estiver anotado no nível de método e não houver anotação no nível da classe, o padrão do bloqueio de gravação será usado pelo contêiner.
Como a maioria dos métodos requer um bloqueio de leitura, use @Lock(READ) no nível de classe para indicar que todos os métodos de negócios nesta classe requerem que o contêiner obtenha um bloqueio de leitura. Para métodos que requerem um bloqueio de gravação, anote os métodos com @Lock(WRITE) para mostrar que ele substitui o bloqueio de leitura que foi especificado no nível de classe.
O exemplo a seguir ilustra esta técnica:
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); public Object get(String name) { return settings.get(name); } @Lock(WRITE) public void set(String name, Object value) { settings.put(name, value); } }
A anotação @Lock aplica-se apenas a métodos declarados na mesma classe que está a anotação @Lock. Para uma determinada classe, os metadados para @Lock nunca são herdados de uma classe superior na árvore de herança de classe. Em vez de usar uma anotação no nível de classe, os mesmos metadados podem ser especificados no descritor de implementação XML usando o method-name * especial, que corresponde a todos os métodos.
- Se você estiver usando a simultaneidade gerenciada por contêiner, use a notação
@AccessTimeout para limitar o período que um método aguarda até que um bloqueio seja concedido. O seguinte exemplo de código ilustra os tempos limites de acesso simultâneo.
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) @AccessTimeout(1000) public Object get(String name) { // consultar o banco de dados } public void set(String name, Object value) { // atualizar o banco de dados } }
Se nenhuma anotação for fornecida, o método usará o padrão para aguardar até que um bloqueio seja concedido. Não há limite de tempo para o período que um cliente aguarda até que um bloqueio seja concedido. Como nada é codificado no nível da classe, não há limite de tempo de espera para que um bloqueio seja concedido para todos os métodos da classe. Se a anotação @AccessTimeout for usada e o contêiner não puder conceder o bloqueio no limite de tempo especificado, um javax.ejb.ConcurrentAccessTimeoutException será lançado no cliente. A anotação @AccessTimeout aplica-se apenas aos métodos declarados na mesma classe que está a anotação @AccessTimeout. Para uma determinada classe, os metadados para a anotação @AccessTimeout nunca são herdados de uma classe superior na árvore de herança de classe.
Como a anotação @Lock, também é possível especificar a anotação @AccessTimeout usando o descritor de implementação XML e, se você usar o descritor de implementação XML, os metadados da anotação @AccessTimeout serão ignorados. O exemplo a seguir usa o descritor de implementação XML para especificar os mesmos metadados do exemplo anterior.
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>1000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
- É importante saber que a codificação XML do concurrent-methodType
segue os três estilos descritos na especificação EJB para compor
o XML para elementos do método de transação do contêiner.
Lembre-se de que ambos os elementos, lock e access-timeout, são opcionais. Os três estilos estão descritos a seguir:
O estilo 1 usa o nome de método especial * para aplicar o tipo de bloqueio, o valor access-timeout, ou ambos, a todos os métodos de negócios do bean especificado.
<!-- Exemplo: Estilo 1 --> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
O estilo 2 é usado para se referir a um método de negócios com um nome específico e designar a ele o tipo de bloqueio especificado, o valor access-timeout, ou ambos. Se o nome do método estiver sobrecarregado, isto é, múltiplos métodos possuem o mesmo nome, mas assinaturas de método diferentes, todos os métodos com esse nome terão o tipo de bloqueio especificado, o valor access-timeout, ou ambos. O estilo 2 tem precedência sobre o estilo 1.
<!-- Exemplo: Estilo 2 --> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
O estilo 3 é usado para se referir a um método distinto que corresponde ao nome de método determinado e possui uma assinatura de método que corresponde aos parâmetros de método listados. O estilo 3 tem precedência sobre os estilos 1 e 2.
<!-- Exemplo: Estilo 3 --> <concurrent-method> <method> <method-name>businessMethod</method-name> <method-params> <method-param>long</method-param> <method-param>int</method-param> </method-params> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
Se o XML estilo 1 for usado para definir um tipo de bloqueio, todas as anotações @Lock no bean serão ignoradas. O mesmo ocorre para o tempo limite de acesso. Se o XML estilo 1 for usado para definir um valor de tempo limite de acesso, todas as anotações @AccessTimeout no bean serão ignoradas.
- É importante entender que as anotações @Lock e @AccessTimeout
são tratadas independentemente, assim como o código do descritor de
implementação XML correspondente de cada uma.
A implementação deste conceito possui múltiplos benefícios. Essa separação do tipo de bloqueio e do tempo limite de acesso ajuda a evitar que você não afete negativamente o código do aplicativo na caixa preta por não ser necessário conhecer o tipo de bloqueio. É possível ignorar o valor de tipo de bloqueio com segurança e ajustar o valor do tempo limite de acesso apenas de acordo com suas necessidades do ambiente e evitar possíveis situações de conflito ou outros problemas de simultaneidade.
Considere um cenário em que você tenha um aplicativo EJB fornecido pelo fornecedor em execução e, devido à lentidão do sistema, ele fique expirando. Você não quer alterar a lógica de bloqueio por temer uma situação de conflito, mas quer realmente modificar o tempo limite. É possível editar o descritor de implementação e especificar o valor de tempo limite de acesso necessário para os métodos que você deseja modificar.O seguinte exemplo mostra como é possível especificar apenas uma anotação @Lock(READ) de nível de método na implementação de bean e usar o estilo 2 para compor o XML para especificar o elemento de tempo limite de acesso para 2.000 milissegundos, não fornecendo o elemento de bloqueio opcional. O resultado é um método com um bloqueio de leitura que possui um tempo limite de acesso de 2.000 milissegundos.
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) public Object businessMethod(long value) { // ... } // ... }
De forma semelhante, é possível usar uma anotação de bloqueio no nível de classe e, em seguida, especificar o valor de tempo limite de acesso desejado no XML usando o estilo 2, o estilo 3, ou ambos, conforme mostrado no exemplo a seguir.<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } public Object businessMethod(long value, int i, Object value) { // ... } public Object businessMethod(long value, int i) { // ... } }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> <method-params> <method-param>long</method-param> <method-param>int</method-param> </method-params> </method> <access-timeout> <timeout>8000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
O exemplo de código anterior resulta em todos os métodos chamados “businessMethod” tendo um tipo de bloqueio de leitura e um tempo limite de acesso de 2.000 milissegundos. A exceção é uma instância do método “businessMethod” que possui uma assinatura de método com o primeiro parâmetro sendo do tipo long e o segundo sendo do tipo int. Esta instância do método "businessMethod" possui um tipo de bloqueio de leitura, mas possui um tempo limite de acesso de 8.000 milissegundos.
O mesmo princípio se aplica quando o estilo 1 XML for usado para definir apenas um tipo de bloqueio, mas não um valor de tempo limite de acesso. É possível incluir um valor de tempo limite de acesso para um método específico, ou para os métodos usando o estilo 2, estilo 3, ou ambos, para obter um tipo de bloqueio específico, e o resultado do valor de tempo limite de acesso. O seguinte exemplo ilustra este ponto:<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
O exemplo de código anterior resulta em todos os métodos de negócios tendo um tipo de bloqueio de leitura e o método indicado, businessMethod, tendo um tipo de bloqueio de leitura e um tempo limite de acesso de 2.000 milissegundos.
Também é possível ter uma anotação @Lock no nível de classe para configurar o tipo de bloqueio de todos os métodos e usar o estilo 1 para compor XML para configurar apenas o valor de tempo limite de acesso de todos os métodos. Consulte o exemplo a seguir:@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } // ... }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
O exemplo anterior resulta em todos os métodos de negócios de bean, ConfigurationBean, tendo um tipo de bloqueio de leitura e um valor de tempo limite de acesso de 2.000 milissegundos.
- Assegure-se de que entenda as regras de herança das anotações usadas.
- Evite o comportamento de bloqueio reentrante que poderá ocorrer se um
método de bloqueio de leitura chamar um método de bloqueio de gravação no mesmo
bean de sessão singleton.
Suponha que o método de negócios de um bean de sessão singleton, direta ou indiretamente, faça com que outro método de negócios do bean de sessão singleton seja iniciado. Se o primeiro método for um método de bloqueio de gravação, esse método poderá chamar qualquer outro método de negócios do bean de sessão singleton sem nenhuma consideração especial. Entretanto, é possível implementar com cuidado um método de bloqueio de leitura se tivesse que ser chamado outro método de negócios da mesma classe do bean de sessão singleton que possuir um método de bloqueio de gravação. Em seguida, ocorre uma exceção javax.ejb.IllegalLoopbackException.
Subtópicos
Alterando a Política de Bloqueio de Bean de Sessão Singleton
Use essa tarefa para substituir a política de bloqueio não justa padrão para todos os bloqueios de gravação de bean de sessão singleton no servidor. Essa tarefa destina-se para os usuários do WebSphere Application Server que não desejarem que as solicitações de bloqueio para as chamadas de método do bean de sessão Singleton sigam uma política não justa.Alterando a Política de Bloqueio de Bean de Sessão Singleton
Use essa tarefa para substituir a política de bloqueio não justa padrão para todos os bloqueios de gravação de bean de sessão singleton no servidor. Essa tarefa destina-se para os usuários do WebSphere Application Server que não desejarem que as solicitações de bloqueio para as chamadas de método do bean de sessão Singleton sigam uma política não justa.


http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tejb_ssb
Nome do arquivo: tejb_ssb.html