Continuando o artigo sobre as novidades na Especificação EJB 3.1, nesta segunda parte vamos abordar o invoções assíncronas e EJB sem interface.
Na nova especificação um cliente pode invocar um session bean de maneira síncrona ou assíncrona. Invocações assíncronas que é a novidade nos permite efetuar uma chamada a um método remoto (assíncrono) e não precisamos esperar o seu retorno, neste caso a assinatura do método deve ser void, ou o método pode retornar um objeto Future
Exemplo:
@AsynchronousOutra novidade é o que todos já esperavam "O Fim das Interfaces", ou pelo menos agora elas são opcionais. Antes que alguém se empolgue é bom deixar claro que isso só funciona para objetos LOCAIS, ou seja, o cliente que irá chamar o método deve estar na mesma JVM. :-(Na verdade um session bean sem interface é uma variação do EJB local, mas expõe os métodos públicos da classe bean sem utilizar uma interface de negócio separada.
public FutureexecutarMetodo() {
String resultado = "Executando Método";
return new AsyncResult(resultado);
}
A referência para o Bean sem interface pode ser passada como um parâmetro, como valor de retorno de qualquer interface de negócio local ou como método de uma classe ejb sem interface.
A implementação do contêiner para Beans sem interface é o mesmo que nós fazemos quando acessamos um método qualquer de uma classe qualquer pela referência, o método de negócio da instancia do session bean e seus interceptors são invocados conforme a necessidade.
Somente os métodos públicos da classe bean (e qualquer super-classe) pode ser invocado através do Bean sem interface. Qualquer tentativa de invocação a métodos com modificadores de acessos diferente de público, irá lançar um javax.ejb.EJBException.
Vejamos a evolução da especificação EJB, dando o mesmo exemplo nas versões 2.1, 3.0 e finalmente 3.1.
Versão 2.*
Até a versão 2.* a comunidade reclamava muito da complexidade dos EJBs, para a criação de um método simples era preciso criar as interfaces (remota e local), a interface home e finalmente a classe de negócio...
Interface Local
import javax.ejb.EJBLocalObject;
public interface SayHelloRemote extends EJBLocalObject{
public void hello();
}
Interface Home
import javax.ejb.CreateException;Session Bean
import javax.ejb.EJBLocalHome;
public interface SayHelloHome extends EJBLocalHome {
SayHello create() throws CreateException;
}
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class SayHelloBean implements SessionBean {
public void sayHello() {
System.out.println("Hello");
}
public SayHelloBean() {}
public void ejbCreate() {}
public void ejbRemove() {}
public void ejbActivate() {}
public void ejbPassivate() {}
public void setSessionContext(SessionContext sc) {}
}
Cliente Session Bean 2.1
import javax.naming.Context;Versão 3.0
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
public class SayHelloClient {
public static void main(String[] args) {
try {
Context initial = new InitialContext();
Context myEnv = (Context)initial.lookup("java:comp/env");
Object objref = myEnv.lookup("ejb/SayHello");
SayHelloHome home = (SayHelloHome) PortableRemoteObject.narrow(objref,
SayHelloHome.class);
SayHello papagaio = home.create();
papagaio.sayHello();
papagaio.remove();
System.exit(0);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Vemos que até a versão 2.1 era muito trabalho criar um simples Hello World com EJB, a Sun vendo que o EJB estava perdendo espaço para frameworks comunitários, como Hibernate para persistência e outras alternativas para Session Beans, decidiu fazer uma mudança radical na especificação, descontinuando os Entity Beans e apresentando o JPA, e tirando a obrigatoriedade de criar a classe Home, eliminando a criação de deployment descriptors, usando e abusando da IoC com o uso extensivo de annotations. A especificação facilitou muito o desenvolvimento e a especificação EJB voltou a ser o supra sumo do Java, vejamos um exemplo
Interface de Negócio Local
import javax.ejb.Local;
@Local
public interface SayHelloLocal {
void hello();
}
Session Bean
import javax.ejb.Stateless;Cliente que executa o EJB
@Stateless
public class SayHelloBean implements SayHelloRemote, SayHelloLocal{
public void hello() {
System.out.println("Hello");
}
}
public class SayHelloClient {
private static Properties prop = new Properties();
private static Context c;
public SayHelloClient(){
prop.put("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
prop.put("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
prop.put("java.naming.provider.url","localhost");
}
public static void main(String[] args) {
SayHelloClient main = new SayHelloClient();
SayHelloRemote remote = main.lookupSayHelloBean();
remote.sayHello();
}
private SayHelloRemote lookupSayHelloBean() {
try {
c = new InitialContext(prop);
return (SayHelloRemote) c.lookup("SayHelloBean/remote");
} catch (NamingException ne) {
throw new RuntimeException(ne);
}
}
}
Versão 3.1 Draft
Com a eliminação da classe home não precisamos mais fazer o narrow no código cliente. Agora basta efetuar um lookup na classe Bean.
Classe de implementação de negócio
// Sem Interfaces Remota ou Local
import javax.ejb.Stateless;
@Stateless
public class SayHelloBean implements SayHelloRemote, SayHelloLocal{
public void hello() {
System.out.println("Hello");
}
}
Cliente que executa o EJB
public class SayHelloClient {
// Se o cliente estiver no conteiner, Injeção nele !!!
// Veja que estamos referenciando ao session bean
// SayHelloBean e não SayHelloRemote.
@EJB SayHelloBean falaAi;
@Resource SessionContext c;
public SayHelloClient(){}
public static void main(String[] args) {
falaAi.hello();
SayHelloClient main = new SayHelloClient();
SayHelloBean sayAgain = main.lookupSayHelloBean();
sayAgain.hello();
}
// Ou podemos fazer via JNDI
private SayHelloRemote lookupSayHelloBean() {
try {
return (SayHelloBean) c.lookup("sayHello");
} catch (NamingException ne) {
throw new RuntimeException(ne);
}
}
}
Podemos observar que esta muito mais simples criar EJBs, sem as interfaces o código fica muito mais limpo e temos uma programação muito próximo de objetos POJO, entretanto, por motivos já conhecidos não é possível instanciar um objeto com o operador new, somente via injeção ou jndi. Para a especificação 2.1 por exemplo, tínhamos que criar 4 objetos para um simples hello world (local), na especificação 3.0 não é obrigatório implementar a interface SessionBean na classe session bean ou a interface Serializable, assim como as classes Interceptors. Viva a injeção de dependência !!!
Veja que ainda precisamos de 3 objetos (sai a interface home) mas o processo já simplifica com a entrada das annotations. Agora na versão 3.1 foi eliminada a necessidade de interfaces (lembre-se, apenas para objetos locais)..
Para criar um EJB sem utilizar a interface, ela deve seguir algumas seguintes regras, ela deve expor os métodos sem interface via definição de classe ou pelo deployment descriptor. E ... :
- Se o bean não expor nenhuma outra interface(s) e não implementar nenhuma interface, então o bean define uma EJB sem interface.
- As seguintes interfaces são excluídas quando implementamos um EJB sem interface : java.io.Serializable, java.io.Externalizable; E qualquer outra interface definida no pacote javax.ejb.
- Todos os métodos da classe bean e qualquer superclasse são expostos como métodos de negócios através de um bean sem interface. E isto inclui os métodos de callback (muito cuidado !!!).
- Os métodos expostos da classe bean sem interface não devem lançar a exceção java.rmi.RemoteException.
Ainda tem várias coisas legais para discutir, provavelmente será possível rodar EJB no TomCat :D, com o pacote light do EJB, no próximo post vou cobrir o calendário para o Timer e concorrência !!!
0 comentários:
Postar um comentário