É claro que uma ChatRoom morreria por falta de memória conforme o número de usuários e posts lotassem a memória do servidor de aplicação. Seria bom usar algum tipo de mecanismo de expiração. Apenas para demonstração, vamos imaginar um coletor de lixo periódico que varre os posts da ChatRoom e remove os posts usando um algoritmo de LRU (ou, talvez, usando JPA e o EntityManager.persist e depois) destruindo dados velhos do chat.
O EJB já possui um mecanismo de Timer desde a versão 2.1. Entretanto, ele sempre funcionou em intervalos de milissegundos e sempre foi muito chato de configurar. A situação melhorou parcialmente com a versão 3.0, mas o fato é que os timer continuavam sendo essencialmente construídos de forma totalmente procedural, e baseados apenas em intervalos. Se você quiser que alguma tarefa seja agendada para o começo da semana, por exemplo, poderia considerar isto como um grande desafio. EJB 3.1 melhora isso fornecendo um serviço de timer declarativo e flexível que tira o melhor de vários outros agendadores de tarefas, como o Quartz ou Flux. Para as mais simples necessidades de agendamento, incluindo os agendamentos do tipo CRON, EJB 3.1 é uma solução interessante. Vamos rever nossa sala de chat. Queremos agendar um bean para fazer a varredura e limpeza de dados mais antigos de nossa sala de chat.
Escrevemos um método que varrerá e verificará os dados, e conforme a necessidade, eliminará os dados velhos ou irrelevantes do chat, de maneira que possamos manter o volume de dados em um estado gerenciável. Aqui, utilizamos um modelo declarativo para nos assegurarmos que o método será executado de hora em hora. Logicamente, poderíamos ter injetado o TimerService do EJB 3.0.
No EJB 3.0, os beans deveriam obrigatóriamente ter pelo menos uma interface (local ou remota) que seria usada para expor as operações do bean para os clientes. Enquanto indireção via interfaces é uma técnica poderosa, algumas vezes acaba por complicar código que poderia ser muito mais simples. No EJB 3.1, você pode construir um bean que não possua interfaces. Neste caso, os métodos públicos do bean serão expostos ao cliente.
A maneira mais simples de lidar com problemas de escalabilidade é simplesmente... não tratá-los! (enquanto recursos de máquina estiverem disponíveis) Essa abordagem é caracterizada pelo padrão SEDA, onde os gargalos são evitados enfileirando tarefas. Isso permite o enfileiramento de tarefas de maneira que o cliente consiga prosseguir na utilização do sistema, até que o servidor termine o processamento e devolva uma resposta. Se um componente na fila demorar muito tempo para ser processado, e o sistema estiver sob forte carga, esse padrão se certifica que o processo lento não levará o sistema a um estado de indisponibilidade.
Outra abordagem para escalonamento é não bloquear as invocações de clientes na troca de mensagens de uma via, ou simplesmente trabalhar de forma assíncrona, deixando a execução no cliente prosseguir até que um resultado seja retornado. Todas essas abordagens foram incorporadas no novo suporte a serviços assíncronos do EJB 3.1. Uma classe de um session bean, ou métodos individuais, podem ser anotados com @javax.ejb.Asynchronous, então todos métodos no bean serão deferidos para processamento posterior; Caso contrário, só os métodos anotados com @Asynchronous serão deferidos. Métodos assíncronos podem retornar void, ou uma instância de java.util.concurrent.Future<V>. O cliente pode consultar essa instância procurando o resultado a qualquer momento posteriormente, mas o resultado da invocação é devolvido imediatamente à thread do cliente, e não bloqueia. Desta forma, se o EJB levar uma hora ou duas, não importa - o cliente não será afetado. Conceitualmente é a mesma coisa do que chamar um serviço cuja única tarefa é mandar a requisição para uma fila JMS.
A instância de Future<V> pode ser usada para cancelar a tarefa, ou esperar pelo resultado. O contexto transacional de um cliente não é propagado a um método assíncrono. REQUIRED, então, efetivamente REQUIRES_NEW para o método assíncrono.
Vamos ver um exemplo: Queremos fazer um serviço que se integre com diversos outros webservices e agregue os resultados. Queremos os resultados, mas não podemos deixar a requisição do cliente (uma página web, talvez?) congelada. Um serviço desses seria mais ou menos desta forma:
O EJB 3.1 também marca a primeira versão da especificação que fornece um paradigma radicalmente simples de implantação dentro de um arquivo .WAR. Uma classe com uma anotação de definição de componentes se torna um enterprise bean quando empacotado dentro de WEB-INF/classes ou em um arquivo .jar dentro de WEB-INF/lib. Enterprise beans podem também ser definidos usando um arquivo WEB-INF/ejb-jar.xml. Beans empacotados dentro de um arquivo .WAR compartilham um único namespace, e se tornam parte do ambiente do arquivo .WAR. Empacotar um .jar dentro de WEB-INF/lib é portanto semânticamente equivalente a colocar as classes em WEB-INF/classes.