EJB Genérico

34 respostas
J

Já postei um tópico sobre a utilização de um único EJB para a aplicação toda.
Pensei e tive uma ideia e gostaria de ver a opinião de voces.
Não testei e o código tem vários erros, mas é apenas para exemplificar a ideia.
Gostaria de saber quais os problemas que posso ter.
Performance, se eu utilizo a transação do container, etc.

ex:

class GenericEJB implements SessionBean
{
  public Object callMethod(String className, String methodName, Object object)  
  {
     Class targetClass  = Class.forName(className);	
     Object target = targetClass.newInstance();
     return targetClass.getMethod(methodName,new Class[] { object.getClass }).invoke(target,new Object[] { object });
  }
}

class Delegate 
{
   protected Object callMethod(String className, String methodName, Object object)
   {
      GenericEJB  ejb = ... pega o ejb todo mundo sabe como;
      ejb.callMethod(className,  methodName, object);
   }
}

class FuncionarioDelegate extends Delegate
{
  public Funcionario consultarFuncionario(FuncionarioDTO funcionarioDTO)
  {
     return (Funcionario) callMethod("FuncionarioService",  "consultarFuncionario", funcionarioDTO);
  }
}

class FuncionarioService
{
  public Funcionario consultarFuncionario(FuncionarioDTO funcionarioDTO)
  {
     // consulta o funcionario
  }
}

class Cliente
{
 public void chama()
 {
    FuncionarioDTO fd = new FuncionarioDTO ();
    fd.setCodigo(1);
    fd.setNome("Maria");

    FuncionarioDelegate f = new FuncionarioDelegate();
    Funcionario func = f.consultarFuncionario(f);
 }
}

Como podem ver é um negócio louco, mas que pode ter fundamento…

34 Respostas

cv1

Tem fundamento, sim, e a gente ja usou num projeto aqui - mas desse jeito que vc esta fazendo ta muuuuuuito fraquinho. Recomendo dar uma olhada em dynamic proxies :wink:

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Proxy.html

J

Mas para ter esse proxy aí deve-se informar a classe em tempo de desenvolvimento.
Mas seria interessante informa-la em tempo de execução através de uma string.

Class.forName(classe);

Achei muito elaborado para apenas fazer uma chamada dinamica.
Não vi utilidade nesse código todo.
Não é mais fácil dar invoke no método.

Mas pela sua experiência isso ajudou com a manipulação de EJBs ?
Pois com essa solução teoricamente resolveria esse problema, pois teria um único EJB para toda aplicação.
O deploy seria bem mais fácil.

Você continua usando essa técnica ?

mcampelo

jprogrammer,

você anda trabalhando em algum projeto aqui no Rio?

No último projeto Java por onde eu passei, tinhamos uma GenericEJB MUITO similar ao que você propôs.

O deploy realmente era mais simples e quando queríamos adicionar um novo serviço, precisávamos apenas escrever POJOs e acertar a configuração no preferences (que poderia ser XML, .properties, whatever).

O GenericEJB sabia o que chamar a partir dessa configuração.

Acho que há uma certa perda de performance por conta de utilizar reflection. Mas não sei a que ponto essa perda chega a ser significativa.

Como no nosso caso o objetivo do EJB era apenas o de disponibilizar chamadas remotas aos serviços, não nos deixava muito amarrados. Mas acho que se para cada service você tiver requisitos transacionais diferentes, pode começar a complicar a história.

Outro ponto que você tem que prestar atenção é que se você tem apenas 1 GenericEJB deployado que pode atender a N services, você estará utilizando apenas 1 único pool de Sessions. Então a configuração/tuning tem que levar isso em consideração também.

Abraços,
Marco Campêlo

J

Sou de SP.
Mas isso gerou resultados satisfatórios ?

Explique melhor:

E bom saber disso.
legal.

mcampelo

Sim. Era produtivo deployar novos serviços porque o EJB estava pronto. Era apenas uma questão de escrever sua classe de negócios e fazer a configuração necessária.

Imagine que você usa 1 Session para 10 Services. Será apenas 1 EJB deployado que atende a 10 services.

Agora imagine que você recebe 15 requests/segundo em cada um desses services.

O seu pool de EJB tem que dar conta de atender 150 requests/segundo.

Se você tem services com características muito distintas que necessitam de configurações muito diferentes, ter tudo isso em um único pool vai ser um complicador.

Ex.:

Service precisa de transação? Sim ou não?
Qual timeout necessário para cada service?

[]'s
Marco Campêlo

J

Isso é uma das minhas dúvidas.
No caso de transação o método invocado pelo reflection participa.
Mas a maior parte das transações seriam controladas pelo banco.

O pool atende apenas uma requisição por vez ?
Eu pensei que o container criasse instancias do sessionbean sob demanda.

mcampelo

Cria sob demanda. Atende a tantas requisições quantos beans você tiver no pool.

O problema é que se cada service possui características diferentes, um trabalho de fine tuning fica muito mais difícil, não acha? Afinal, você possui um EJBGenérico que atende a 10 services com características distintas.

[]'s
Marco Campêlo

louds

Nesse caso não seria apenas fazer o deploy do mesmo EJB usando um nome JNDI diferente? Isso permitiria configurações diferentes.

mcampelo

Exato, louds. Essa era a estratégia adotada. A vantagem é ficar livre para configurar a sua maneira. A desvantagem é que você volta a ter que fazer o deploy de N EJBs e manter N deployment descriptors.

Tem que colocar na balança e ver para o seu caso, o que é melhor.

[]'s
Marco Campêlo

louds

Se precisa de N configurações diferentes não vejo como não usar N artefatos EJBs. Mas como você mesmo falou, isso é para o tunnig da aplicação, se só isso já for suficiente não é de se reclamar.

J

Mas já seria uma vantagem ou não ?
Vc teria que apenas que usar a mesma classe genericEJB com nomes JNDI diferentes, não criar várias classes identicas.
Isso pode ?

Agora outra dúvida.
O container pode administrar apenas uma instancia porque eu posso invocar um método de uma instancia simultaneamente por várias threads ?
Não é o que o Web container faz com os servlets ?
Não seria o mesmo com os EJB containers ?

mcampelo

jprogrammer:
Mas já seria uma vantagem ou não ?
Vc teria que apenas que usar a mesma classe genericEJB com nomes JNDI diferentes, não criar várias classes identicas.
Isso pode ?

Pode tudo. Depende do seu cenário! :slight_smile: Se houvesse uma resposta definitiva para tudo, nossa profissão seria moleza e nós não teríamos salários de milhões que temos! :smiley:

Não entendi nada da sua pergunta. Sorry! :frowning:

[]'s
Marco Campêlo

J

Tá mesmo embassada essa pergunta…
Vamos lá.

Um container Web como Tomcat tenta administrar no máximo uma instancia de um servlet.
Qualquer requisição para o servlet faz a invocação do método service.
Várias requisições simultaneas podem invocar o service sem problemas.

A mesma coisa não seria com o EJB container ?
Ele administraria as instancias ou a instancia e invocaria o método deste objeto para várias requisições simultaneamente.
Esse negócio de pool me parece mais apropriado com statefull sessions bean.

louds

Não, EJBs são threadsafe, a idéia de um pool é exatamente para isso. Um EJB fica ativo em somente uma thread por vez.

J

Quer dizer que ele espera uma requisição acabar para atender outra para o mesmo EJB.

mcampelo

jprogrammer:
Quer dizer que ele espera uma requisição acabar para atender outra para o mesmo EJB.

Aí que entra a configuração do seu pool de EJBs.

Se você configurar que o número de EJBs no pool no start será 1 e o máximo será 1, sim, isso irá acontecer.

Se você configurar que o inicial será 10 e o máximo é 30, você consegue atender até 30 requests simultâneos.

[]'s
Marco Campêlo

louds

Não confunda o EJB com as instancias dele.

EJBs são feitos para processamento paralelo massivo, mas cada instancia de um EJB é usada em uma thread por vez.

J

Pelo que ouvi falar ele cria instancias sob demanda, ou seja, ele tem 10 instancias no pool, pelo que o louds disse , cada instancia atende uma requisição.
Se tiver 15 requisições ele cria mais 5 instancias.
O pool é só para ter uma chache.
É isso ?

No caso do EJB genérico que vcs fizeram (mcampelo) como ficou isso ?
Porque dá na mesma eu ter um EJB só que atende 100 e ter 10 EJB que atendem 10 cada um. Ou não ?

Se possível me exemplifique…

louds

Se for o mesmo EJB com nomes diferentes, deve dar na mesma. A questão que o marco levanto é quando um dos comandos executados pelo seu EJB precisar de tunning diferente. Se ele for mais importante de repente merece um pool a parte do resto, ou então se tiver requisitos transacionais diferentes.

mcampelo

Se você tem apenas 1 EJB no seu pool para atender 100 requests, você vai atender 1 request e deixar 99 aguardando na fila.

Se você tem 10 EJBs no seu pool para atender 10 requests cada 1, você vai atender 10 requests de cada vez (10 EJBs x 1 request) e deixar 90 requests na fila (9 requests em cada uma das 10 filas).

[]'s
Marco Campêlo

mister_m

jprogrammer, o genesis implementa exatamente essa solução, mas de forma totalmente não intrusiva. Você pode ter um POJO e chamar seus métodos normalmente e aqueles que devem ser executados dentro de um EJB são :slight_smile:

Algo mais ou menos assim:

public class POJO {
    /** @Remotable */
    public void metodo() {
        System.out.println("Metodo remoto");
    }
}

// Codigo cliente
POJO pojo = new POJO();
// Executa o metodo remotamente
pojo.metodo();
J

Então a questão do desempenho não seria o problema mas a transação.
Entendi.
Se depender de uma transação especial para o service é melhor criar uma EJB para ele. Caso contrário poderia deixar no genérico.

Mas que caso a transação teria um tratamento especial ?
Cada requisição geraria uma transação.
O container consegue tratar isso.
ex:

class FuncionarioService{
  public void cadastrar(FuncionarioDTO)
  {
      // faz  uma acao
     // faz outra
    // se falhar volta
  }
}

Mas esse método é chamado via reflection.
Se falar a chamada volta tudo.

edit:
Já me falaram que o Genesis parece suprir essa necessidade. Mas gostaria de saber se tem como fazer na raça para eu aprender.
É lógico que em um projeto eu adotaria ele.

mcampelo

Você já leu sobre os tipos diferentes de controle de transação que o container EJB oferece?

Imagine que você tem o serviço A que precisa do controle X e do serviço B que precisa do controle Y. Não vai ter como colocar esses dois serviços embaixo do mesmo GenericEJB.

Controle X poderia ser por exemplo criar uma nova transação sempre.
Controle Y poderia ser por exemplo aproveitar a transação já existente sempre.

[]'s
Marco Campêlo

J

Entendi.
Mas no seu caso a performance ficou legal ?

mister_m

Então dê uma olhada no código que está no CVS e veja se consegue implementar você mesmo depois de fazer isso.

J

Se tá doido cara !
Não chega a tanto.
Eu to falando com essa estratégia que a gente está comentando.

Quando coloco posts como esse é simplesmente para gerar discussões que aumentem nosso conhecimento.
Só nessa história eu já estou entendendo bem mais como o container trabalha as instancias de EJB.
Não necessariamente eu irei usar isso.

Se a gente ficar use isso, use aquilo, pegue aquilo pronto nunca iremos entender como as coisas funcionam.
Agora não quer dizer que quero entender em níveis de bits.

mister_m

Eu disse pra você não implementar? Eu realmente quis dizer: veja como foi feito, se você consegue entender e pergunte depois.

A melhor forma de evoluir em algo assim, se você não quer usar algo pronto, é ver como foi implementado, tentar entender a razão e questionar quais outras opções seriam possíveis.

Eu não sou tão sarcástico assim como você pensa… :stuck_out_tongue:

cv1

Sim, vamos, pq a gente pega as coisas prontas e olha como elas foram feitas caso quiser aprender. Aceite o fato de que vc nao precisa inventar coisas - voce pode muito bem ler sobre elas, pq praticamente todas as pequenas pecas que sao relevantes pra base do desenvolvimento de um sistema ja foram inventadas e estao amplamente documentadas e implementadas por ai. Se nao estao, ai sim voce tem uma oportunidade. Do contrario, lembre-se que codigo tambem eh literatura :wink:

Nesse caso, da proxima ja avise antes “ei, eu tou com essa duvida, mas eu nao quero saber muito nao, quero so uma resposta nas coxas, bem mais ou menos, mesmo, pq eu nao tenho saco de entender o que voces dizem!” :mrgreen:

J

Cv eu sei porque vc está mogoado comigo.
É por causa do virtual proxy que eu disse que era um monte de código “inútil”.
Não falei isso por mal, apenas não vi a utilidade mas por ignorancia minha.
O intuito era saber qual era a a vantagem daquele código em relação ao Method.invoke.

Percebi que depois daquele post vc ficou magoado…
:oops:

cv1

Algumas correcoes:

  • Eu nao sou sua namorada pra ficar magoado.
  • Dynamic proxies, nao “virtual proxies”.

E, agora, o conteudo do post:

A vantagem de usar Dynamic Proxies eh que voce nao precisa ficar passando os nomes dos servicos como Strings pra la e pra ca, jogando a checagem de tipos do compilador fora: voce pode usar interfaces de verdade, e testar o codigo mais facil tanto em Unit Isolation quanto em Unit Integration, alem de poder jogar o EJB fora e rodar os servicos localmente, se der na telha.

Alias, chamar isso de “EJB Generico” eh meio feinho. Nomes mais apropriados seriam InvokerEJB ou ServiceExecutorEJB.

J

Valeu cara.
Estou a berto a correções.

Não sou arquiteto de software.
Estou aprendendo e estou tentando formar minha própria “cabeça” em relação as metologias e quando um dia for arquiteto poderia fazer meu trabalho com qualidade e propriedade.
Porque tem muita gente com título de arquiteto que não sabe nada.
Faz um cursinho de UML e já sai dizendo que é analista/arquiteto.
Ve se isso pode ?
Sou programador.
Estou acostumado a fazer apenas coisas que me mandam.

_fs

DualRpc! DualRpc!
DUAL RPC!

mcampelo

LIPE:
DualRpc! DualRpc!
DUAL RPC!

Legal. Não conhecia.

Mas li o FAQ e não senti muita firmeza no esquema de balanceamento e falha.

Parece que o foco da solução é para RPCs que precisam manter o estado. Não sei se há vantagens em utilizá-lo no caso de Stateless.

[]'s
Marco Campêlo

fmeyer

tenho trauma de RPC … mas gostei do projeto … tobookmarks

Criado 3 de maio de 2005
Ultima resposta 4 de mai. de 2005
Respostas 34
Participantes 7