O documento discute três itens relevantes sobre EJB: 1) o uso de anotações para adicionar metadados às classes e métodos; 2) a utilização mínima de descritores XML; 3) a injeção de dependência, onde objetos necessários são injetados no código ao invés de serem localizados manualmente.
2. Três itens relevantes
• Anotações (metadados)
• Mínimo emprego de descritores
(documentos XML)
• Injeção de dependência
3. Anotações
• Adiciona informação a classe, interface,
método ou variável
• A classe abaixo é um POJO com
informação adicional para um contêiner:
@Stateless
public class X {...}
5. Descritores
• O nome formal é
deployment descriptors
• Documentos XML (ou seja, arquivos
contendo XML)
• Configuram serviços oferecidos pelo
contêiner (alternativa para anotações)
• Tem precedência sobre anotações
6. Trecho de um descritor
• <enterprise-beans>
<sessions>
<ejb-name>NomeDoMeuBean</ejb-name>
<local>pacote.MinhaInterface</local>
<ejb-class>pacote.MinhaClasse</ejb-class>
...
</sessions>
</enterprise-beans>
7. Injeção de dependência
• Em vez do seu código requisitar, criar,
localizar um objeto do qual ele depende,
um contêiner injeta esta dependência no
seu código
• Em vez do código localizar um recurso, ele
apenas diz que precisa dele. É função de
“outro” código fornecer o recurso.
8. DI (segunda-parte)
• Você “abre mão” de controle
• Você não mais decide, alguém decide o que
você irá usar
• Em geral, o que será empregado é definido
em um arquivo de configuração
• Ao olhar o código, não se sabe exatamente
quem fornecerá serviços
9. DI (terceira-parte)
• Você declara dependências
• Contêiner é responsável por instanciar
objetos necessários e fornecê-los a quem
precisa
• Seu código não cria uma instância da
interface X, um objeto que implementa esta
interface é declarado e o contêiner se
encarrega de instanciá-lo (quando preciso)
10. Exemplo
• public class Main {
@EJB
private static ServicoRemote srv;
public static void main(String... args) {
System.out.println(srv.toUpper(“casa”));
}
}
java.lang.NullPointerException
12. Qual a diferença?
• Session beans e message-driven beans
Lógica de negócio
✦
• Entity beans
Persistência
✦
13. Session beans e MDBs?
• Session beans
Requisições diretas de funções do cliente
✦
(calcule isto, faça aquilo, ...)
• @MessageDriven
Processam mensagens indiretas
✦
14. Requisições diretas!?
(session beans)
• Quanto custa tal carro?
• Qual o saldo desta conta?
• Dê-me o PDF do histórico deste aluno!
• Altere o endereço de entrega deste pedido!
• Acrescente esta disciplina à lista de
desejadas!
• Qual o próximo pedido a ser atendido?
15. Requisições indiretas!?
(MDBs)
• Cadastre requisição de emissão de diploma
para o aluno A!
Biblioteca verifica pendências
✦
Departamento verifica pendências
✦
DAA verifica pendências
✦
Software inteligente detecta legalidade
✦
• Quando todos sinalizarem “ok”, emissor de
diploma imprime propriamente dito o
diploma.
16. Requisições indiretas!
@MessageDriven
• Em geral as tarefas correspondentes não são
executadas de forma síncrona
Garçom (atende vários pedidos
✦
simultaneamente)
instalação de ADSL, requisição de serviços...
✦
• Contraste com (@Stateless, @Stateful)
Atendimento médico
✦
Reserva de voo
✦
Confirmação de inscrição, matrícula, ...
✦
17. Enfim, session beans ou
MDBs?
• São opções que visam mais adequadamente
tratar problemas distintos
• Use o que melhor atende o seu problema
• Não é preciso usar ambos
18. E quanto aos tipos de
Session beans?
• @Stateless
Funções atendidas por uma
✦
requisição
• @Stateful
Funções que exigem a manutenção de
✦
um diálogo com o cliente
19. Um exemplo trivial
• Conversão de letras minúsculas para letras
maiúsculas
Definitivamente este não é um exemplo
✦
que justifica o emprego de EJB
Registre isto no seu cérebro
✦
20. Exemplo (Cliente)
• public class Main {
@EJB
private static SessionRemote srv;
public static void main(String... args) {
System.out.println(srv.toUpper(“casa”));
}
}
Resultado esperado!!!??? CASA
21. Exemplo (EJB)
(interface)
public class Main {
@EJB
SessionRemote srv;
private static
public static void main(String... args) {
System.out.println(srv.toUpper(“casa”));
}
}
• @Remote
public interface SessionRemote {
String toUpper(String entrada);
}
22. Exemplo (EJB)
(stateless session bean)
• @Stateless(mappedName=”MeuEJB”)
public class SessionBean implements SessionRemote {
public String toUpper(String entrada) {
return entrada.toUpperCase();
}
} public class Main {
@EJB
private static SessionRemote srv;
public static void main(String... args) {
System.out.println(srv.toUpper(“casa”));
}
}
23. Visão geral do exemplo
Não há dependência de Main para SessionBean
(objeto de interesse será injetado pelo ACC)
24. ACC?
• Application Client Container
• Contêiner para o cliente? Sim! Veja o código!
public class Main {
@EJB
SessionRemote srv;
private static
public static void main(String... args) {
System.out.println(srv.toUpper(“casa”));
}
}
Quem poderia injetar um objeto que implementa
SessionRemote em srv? Observe que este código não
será executado pelo EJB contêiner!!!!!
25. Sou obrigado a usar um
ACC?
• Não! Contudo, abre-se mão da injeção de
dependência!!!
• Cliente que não é executado por um ACC
JNDI
InitialContext ctc = new InitialContext();
SessionRemote srv = (SessionRemote) ctx.lookup(“MeuEJB”);
System.out.println(srv.toUpper(“casa”));
26. Comparando clientes
Usa DI
public class Main {
@EJB
Exige contêiner
private static SessionRemote srv;
public static void main(String... args) {
(ACC)
System.out.println(srv.toUpper(“casa”));
}
}
Exige JVM convencional
InitialContext ctc = new InitialContext();
SessionRemote srv = (SessionRemote) ctx.lookup(“MeuEJB”);
System.out.println(srv.toUpper(“casa”));
Não usa DI (cliente conhece um tal de “MeuEJB”)
27. @Stateless
(atributo mappedName)
• Anotações possuem, em geral, atributos
• @Stateless possui, entre outros, o
atributo mappedName
• mappedName especifica o nome
empregado por JNDI
• Em tempo, JNDI é acrônimo de
Java Naming and Directory Interface
28. JNDI
• Associa nome a recurso
• Permite a uma aplicação Java descobrir e
recuperar um objeto de qualquer tipo
• Por exemplo, obter referência para EJB
InitialContext ctc = new InitialContext();
SessionRemote srv = (SessionRemote) ctx.lookup(“MeuEJB”);
System.out.println(srv.toUpper(“casa”));
30. @Stateful
• Um diálogo (ou sessão) é mantido
Seleciona o modelo
✦
Seleciona o ano
✦
Seleciona a cor
✦
Seleciona opcionais
✦
• Cliente define um estado e, em requisições
posteriores, aquele estado está lá
31. @Stateful
• Primeiro momento
Cliente requisita um modelo específico
✦
• Segundo momento
Cliente requisita um ano específico (esta
✦
requisição se aplica ao modelo
selecionado anteriormente)
• Ou seja, em um @Stateful bean, o estado
anteriormente obtido é mantido em
chamadas posteriores
32. @Stateful
(mantendo estando)
• Obser ve a classe abaixo (POJO)
public class Carro {
private String modelo;
private int ano;
// Métodos get/set para modelo e ano
}
• Transformado em stateful bean
(sufixo Bean é uma convenção)
@Stateful
public class CarroBean {...}
33. Cliente
public class Main {
@EJB
private static CarroRemote carro;
public static void main(String... args) {
exibeCarro(carro);
carro.setModelo(“Fusca”);
carro.setAno(1969);
exibeCarro(carro);
}
}
Ocorre NullPointerException? Não!
O modelo se perde após setModelo? Não
O ano se perde após setAno? Não!
O bean que recebe a mensagem setModelo é o
mesmo que responde ao método setAno? Sim!
O mesmo bean responde todas as msgs? SIM!
34. Cliente e beans
• Se existe um único cliente e um único bean,
então não há como chamar outro bean!
• Se existem vários clientes, então um cliente
pode alterar o estado de um stateful bean
consultado por outro cliente? Não!
• Para cada cliente um correspondente
stateful bean? Sim!
• Quem mantém a correta associação entre
clientes e beans? O EJB contêiner!
35. Clientes de @Stateless
• Requisições são tratadas em uma única
chamada, ou seja, instâncias de stateless
beans podem ser compartilhadas em um pool
delas!
• Instâncias de stateful beans não podem ser
compartilhadas!
36. Exercício
• Qual o resultado da execução do comando
abaixo para o código fornecido?
java -cp classpath-aqui Main
public class Main {
@EJB
private static CarroRemote carro;
public static void main(String... args) {
exibeCarro(carro);
carro.setModelo(“Fusca”);
carro.setAno(1969);
exibeCarro(carro);
}
}
37. Exercício
• Código
s1.m1();
s1.m2();
• Um cliente C envia a mensagem m1 para o
stateful bean S1
• Em seguida, C envia a mensagem m2 para o
stateful bean S1
• Um único objeto, em execução no contêiner
EJB, recebe as mensagens m1 e m2?
38. Problema
• Se para cada cliente uma instância de um
stateful bean é criada, então teremos um
crescimento indefinido do número de
instâncias no contêiner EJB?
39. Resposta
• Não. Stateful beans permanecem pelo menos
enquanto durar a sessão (o que não é
razoável em alguns casos)
• Nestes casos, use a anotação
@Remove
para anotar método que, quando chamado,
demarca fim da sessão.
• Quando cliente chama método anotado por
@Remove, o cliente avisa o contêiner do fim
do workflow (sessão e bean podem ser
eliminados)
40. Ou seja
• Para este cliente, o contêiner não poderá
fazer nada até que a sessão expire, afinal,
como o contêiner poderia saber que não mais
requisições serão enviadas?
public class Main {
@EJB
private static CarroRemote carro;
public static void main(String... args) {
exibeCarro(carro);
carro.setModelo(“Fusca”);
carro.setAno(1969);
exibeCarro(carro);
}
}
41. Versão alterada
• Assumindo que o método fim() está anotado
com @Remove, temos abaixo um cliente bem
comportado e que respeita o contêiner!
public class Main {
@EJB
private static CarroRemote carro;
public static void main(String... args) {
exibeCarro(carro);
carro.setModelo(“Fusca”);
carro.setAno(1969);
exibeCarro(carro);
carro.fim();
}
}
43. Glassfish
(Java EE Application Server)
• Obtenha o jar file correspondente
https://glassfish.dev.java.net/public/downloadsindex.html
• Primeiro passo
java -Xmx256m -jar <glassfish-obtido>.jar
• Vá para o diretório criado
cd glassfish
• Se não for usar recursos de clustering
ant -f setup.xml
46. Demais passos
• Crie dois beans: um stateless e outro
stateful
• Criar cliente JNDI e cliente via ACC para
usufruir dos dois beans
• Realizar a implantação (deployment)
• Executar os clientes e obser var os
resultados
47. Refinamento dos
passos
• Criar classe anotada com @Stateful e @Remove
• Criar classe anotada com @Stateless
(serviço oferecido por chamada única)
• Efetuar o deployment no contêiner EJB
(exige instalar e iniciar)
• Criar cliente contendo anotação @EBJ (ACC)
• Criar cliente que faz uso de JNDI
(convém usar atributo mappedName tanto em
@Stateless quanto @Stateful)
49. Message-Driven Bean
(MDB)
Finalidade
• Integração
Sistema A envia mensagem para B
✦
• Processamento assíncrono
Serviço é requisitado (ação posterior)
✦
• Distribuição
Sistema A comunica-se com B
✦
50. Comparação
• Session bean
Processa requisição diretamente enviada
✦
pelo cliente
• Message-Driven Bean (MDB)
Processa mensagem
✦
(indiretamente recebida)
Cliente não sabe quem irá tratar
✦
51. Como funciona?
• Cliente envia msg
• “Middleman” encarrega-se de entregar a
msg ao destino
• “Middleman” é confiável, ou seja, a msg será
entregue, mesmo que o destino não esteja
disponível no momento em que o cliente
envia a msg.
52. Alguns detalhes
• Troca de msgs em Java ocorre via JMS
• JMS
Java Message Service
• MDBs dependem de JMS
53. Cenário de uso
• Lembra-se da compra de automóvel?
• Você seleciona o carro desejado, com a
configuração desejada e requisita proposta de
financiamento.
• Requisição pode ser enviada a várias
financiadoras (análise pode envolver
atividade manual)
54. Parte do processo...
• Coleta dados p/ aquisição (stateful)
• Requisita proposta financiamento
(pode levar dias a análise, certo?)
ou seja, requisição deve ser assíncrona
• MDB recebe proposta, avalia risco por perfil
e, de forma assíncrona, avalia parecer de
profissional (ser humano)
• Profissional avalia e autoriza contato de
“vendedores” (de forma assíncrona), ...
55. Graficamente...
A partir deste ponto outra aplicação sinalizaria
pedido de análise de proposta que, após concluída
seria enviada a outro MDB para “despacho” (seria
consumida por pessoal de “venda”)
56. Como é um MDB?
• @MessageDriven(mappedName=”jms/Queue”)
public class X implements MessageListener {
public void onMessage(Message msg) {
try {
TextMessage txt = (TextMessage) msg;
// Processa mensagem...
}
}
}
57. Como é o “cliente”?
• @Resource(mappedName=”jms/Queue”)
private Destination geraProposta;
@Resource(mappedName=”jms/ConnectionFactory”)
private ConnectionFactory cf;
// Segue código que
// CRIA CONEXÃO
// CRIA SESSÃO JMS API
// CRIA PRODUTOR DE MENSAGENS
// finalmente, ENVIA A MENSAGEM
58. JMS API!?
• Sim!
• Qual o package?
javax.jms
• Onde obter mais informações?
http://java.sun.com/products/jms/
✦
59. Não esqueça!
• Para obter a fábrica de conexões
@Resource(mappedName=”x”)
✦
• Para obter o destino da mensagem
@Resource(mappedName=”x”)
✦
• Para tratar msgs para um dado destino
@MessageDriven(mappedName=”x)
✦
60. Qual é o processo?
• MDBs, quando são criados, dizem qual o
destino a partir do qual receberá mensagens
• Cliente envia mensagem para destino
(destination)
• EJB contêiner dispacha (via middleman, o
message-orientedmiddleware) a mensagem
para o MDB
• MDB recebe msg via método onMessage
onMessage?
61. MDBs implementam...
• javax.jms.MessageListener
(usado para receber msgs assíncronas)
• Possui um único método
void onMessage(Message msg)
62. Trate um MDB como
• um stateless session bean, ou seja,
• não assuma a manutenção de estado
63. Falta JPA!
• Exemplo
Isto é suficiente se atributos forem primitivos e
todos devem ser persistidos!
@Entity
public class Aluno {
@ID
@GeneratedValue
private long id;
private String nome;
...
}
64. Como usar?
• Em algum lugar...
• aluno.setNome(“Fulano”);
entityManagerInstance.persist(aluno);
Cabe ao persistence provider recuperar os atributos
de aluno a serem persistidos, gerar um valor único
para chave, montar uma sentença SQL compatível
com o SGBD empregado e requisitar a execução.
65. O que foi visto?
• Visão geral de conceitos
• Visão geral de como funciona
Falta uma quantidade significativa de
informação que diz como usar!
67. Sequência Zero
• Instale o Glassfish e o inicie
asadmin start-domain
• Verifique (http://localhost:8080)
• Vá para a página do administrador
http://localhost:4848
• Efetue login
admin/adminadmin
(conta padrão)
68. Sequência Um
• Crie um stateless session bean
(retorna uma frase sorteada dentre um
conjunto de pelo menos 5 frases)
• Crie um stateful session bean
(retorna o valor de um contador que é
incrementado a cada chamada)
• Crie um MDB
(exibe “RECEBI” para cada msg
recebida)
69. Sequência dois
• Crie um cliente (ACC) que exercite os
três beans criados (um único cliente)
• Execute o cliente e observe os
resultados
70. Parabéns,
se você está lendo este slide, é porque
sobreviveu à iniciação em EJB.
Esteja preparado para usufruir do que EJB
pode oferecer!
Notas do Editor
Curiosamente, java não possui POINTERs, mas references.
Tais tarefas não são síncronas
Na nova grafia, voo em vez do antigo vôo.
Vamos comparar os clientes?
Onde foi fornecido tal MeuEJB?
O que é exatamente JNDI?
Vamos ilustrar
Vamos entender isto melhor, a relação entre clientes e beans.
Isto para stateful beans. E para stateless?
NullPointerException. Observe a DI (exige contêiner).
Sim.
Resposta a seguir.
Vejamos o exemplo anterior
Veja a nova versão...
Veja a nova versão...
Apenas a sequência (não os executaremos). Veja um refinamento dos passos.
Slides anteriores ilustram partes desta solução.