CDI do básico ao avançado

3,006 views
2,828 views

Published on

CDI do básico ao avançado

  1. 1. CDI, do básico ao avançado Thursday, September 5, 13
  2. 2. Alberto Souza • @alberto_souza • github.com/asouza Thursday, September 5, 13
  3. 3. Usar ou criar? @ManagedBean public class ProdutosBean { @PostConstruct public void carregaProdutos(){ ProdutoDAO produtos = new ProdutoDAO(); produtos.setConnection(ConnectionFactory.createConnection()); this.lista = dao.lista(); } } Thursday, September 5, 13
  4. 4. Usar! @ManagedBean public class ProdutosBean { private ProdutoDAO produtos; private ProdutosBean(ProdutoDAO produtos){ this.produtos = produtos; } @PostConstruct public void carregaProdutos(){ this.lista = dao.lista(); } } Thursday, September 5, 13
  5. 5. Injeção de Dependências • JAVAEE 6/7 • CDI 1.0/1.1 • WELD 2 Thursday, September 5, 13
  6. 6. Uso fácil @ManagedBean public class ProdutosBean { @Inject private ProdutoDAO produtos; @PostConstruct public void carregaProdutos(){ return dao.lista(); } } Thursday, September 5, 13
  7. 7. Injeção de Dependências • E como configura? Thursday, September 5, 13
  8. 8. Injeção de Dependências • Não precisa mais Thursday, September 5, 13
  9. 9. Outro exemplo class ProdutoDAO{ @Inject private EntityManager em; public List<Produto> lista(){ return em.createQuery("select p from Produto p"); } } Thursday, September 5, 13
  10. 10. Criação de EntityManager EntityManagerFactory emf = Persistence. createEntityManagerFactory("loja"); EntityManager em = emf.createEntityManager(); Thursday, September 5, 13
  11. 11. Tem que ensinar class EntityManagerProducer{ private EntityManagerFactory emf = Persistence.createEntityManagerFactory("loja"); @Produces public EntityManager create(){ return factory.createEntityManager(); } } Thursday, September 5, 13
  12. 12. Escopo? class EntityManagerProducer{ private EntityManagerFactory emf = Persistence.createEntityManagerFactory("loja"); @Produces @RequestScoped public EntityManager create(){ return factory.createEntityManager(); } } Thursday, September 5, 13
  13. 13. Escopo? class EntityManagerProducer{ private EntityManagerFactory emf = Persistence.createEntityManagerFactory("loja"); //outro método aqui... public void close(@Disposes EntityManager entityManager){ entityManager.close(); } } Thursday, September 5, 13
  14. 14. Qual é o remetente? public class FinalizadorDeCompra{ private String remetente; public void envia(){ mailer.send(remente,...); } } Thursday, September 5, 13
  15. 15. Trocar a injeção de String? public class FinalizadorDeCompra{ @Inject private String remetente; public void envia(){ mailer.send(remente,...); } } Thursday, September 5, 13
  16. 16. Só quero para determinada String public class FinalizadorDeCompra{ @Inject @RemetenteCompra private String remetente; public void envia(){ mailer.send(remente,...); } } Thursday, September 5, 13
  17. 17. Qualifier //outras annotations chatas @Qualifier @interface RemetenteCompra{ } Thursday, September 5, 13
  18. 18. Qualifier @ApplicationScoped class RemetentesProducer { @Produces @RemetenteCompra public String remetenteCompra(){ return properties.getProperty("remetente.compra"); } @Produces @RemetenteNewsletter public String remetenteNewsletter(){ return properties.getProperty("remetente.newsletter"); } } Thursday, September 5, 13
  19. 19. Indo além • VRaptor CDI e integração com o Container Thursday, September 5, 13
  20. 20. Injeção de coisas do container • Quero usar um EJB, EntityManager... Thursday, September 5, 13
  21. 21. Injeção de coisas do container @Component public class ProdutoDAO { @Inject private final EntityManager entityManager; public void salva(Produto produto) { entityManager.persist(produto); } Thursday, September 5, 13
  22. 22. Injeção de coisas do container @Stateless @Component public class ProdutoDAO { @Inject private final EntityManager entityManager; public void salva(Produto produto) { entityManager.persist(produto); } Thursday, September 5, 13
  23. 23. Injeção de coisas do container @Resource public class ProdutosController { //@EJB @Inject private ProdutoDAO produtoDAO; ... } Thursday, September 5, 13
  24. 24. EJB? • Por sinal o DAO é um EJB porque? Thursday, September 5, 13
  25. 25. EJB? @Component public class ProdutoDAO { @Inject private final EntityManager entityManager; @Transactional public void salva(Produto produto) { entityManager.persist(produto); } Thursday, September 5, 13
  26. 26. Exemplo de uso • Coloco no interceptor e tá tudo certo! Thursday, September 5, 13
  27. 27. Componente padrão @RequestScoped public class DefaultPathResolver implements PathResolver { public String pathFor(ResourceMethod method) { String format = resolver.getAcceptFormat(); String suffix = ""; if (format != null && !format.equals("html")) { suffix = "." + format; } //WEB-INF/jsp/controller/metodo.jsp String name = method.getResource().getType().getSimpleName(); String folderName = extractControllerFromName(name); return getPrefix() + folderName + "/" + method.getMethod().getName() + suffix + "."+getExtension(); } Thursday, September 5, 13
  28. 28. Componente customizado class CustomPathResolver implements PathResolver{ public String pathFor(ResourceMethod method) { String format = resolver.getAcceptFormat(); String suffix = ""; if (format != null && !format.equals("html")) { suffix = "." + format; } //WEB-INF/resources/controller/metodo.jsp String name = method.getResource().getType().getSimpleName(); String folderName = extractControllerFromName(name); return "WEB-INF/resources" + folderName + "/" + method.getMethod().getName() + suffix + "."+getExtension(); } } Thursday, September 5, 13
  29. 29. Alternative @Alternative class CustomPathResolver implements PathResolver{ public String pathFor(ResourceMethod method) { String format = resolver.getAcceptFormat(); String suffix = ""; if (format != null && !format.equals("html")) { suffix = "." + format; } //WEB-INF/jsp/controller/metodo.jsp String name = method.getResource().getType().getSimpleName(); String folderName = extractControllerFromName(name); return "WEB-INF/resources" + folderName + "/" + method.getMethod().getName() + suffix + "."+getExtension(); } } Thursday, September 5, 13
  30. 30. Registra no beans.xml <?xml version="1.0" encoding="UTF-8"?> <beans> <alternatives> <class>br.com.caelum.vraptor.view.CustomPathResolver</class> </alternatives> </beans> Thursday, September 5, 13
  31. 31. ilhazinha • Alternative habilitado só no bean archive Thursday, September 5, 13
  32. 32. ilhazinha • VRaptor não enxergava Thursday, September 5, 13
  33. 33. Prioridade @Alternative @Priority(Interceptor.Priority.APPLICATION) class CustomPathResolver implements PathResolver{ public String pathFor(ResourceMethod method) { String format = resolver.getAcceptFormat(); String suffix = ""; if (format != null && !format.equals("html")) { suffix = "." + format; } //WEB-INF/jsp/controller/metodo.jsp String name = method.getResource().getType().getSimpleName(); String folderName = extractControllerFromName(name); return "WEB-INF/resources" + folderName + "/" + method.getMethod().getName() + suffix + "."+getExtension(); } } Thursday, September 5, 13
  34. 34. Prioridade • Podemos sempre sobreescrever! Thursday, September 5, 13
  35. 35. Servidor já injeta Request • Request doVRaptor é modificado Thursday, September 5, 13
  36. 36. Aproveita o que já existe public class VRaptorRequest implements MutableRequest,HttpServletRequest { private final Hashtable<String, String[]> extraParameters = new Hashtable<String, String[]>(); //qual que ele vai injetar? @Inject private HttpServletRequest request; } Thursday, September 5, 13
  37. 37. Aproveitamos o existente @Decorator public class VRaptorRequest implements MutableRequest,HttpServletRequest { @Delegate private HttpServletRequest delegate; @Override public String getParameter(String name) { if (extraParameters.containsKey(name)) { String[] values = extraParameters.get(name); if (values.length == 1) { return values[0]; } else { return Arrays.toString(values); } } return delegate.getParameter(name); } Thursday, September 5, 13
  38. 38. Configuramos <decorators> <class>br.com.caelum.vraptor.http.VRaptorRequest</class> </decorators> Thursday, September 5, 13
  39. 39. Priority • Pode usar Priority também! Thursday, September 5, 13
  40. 40. Injetar Requests public class DefaultFormatResolver implements FormatResolver { private final HttpServletRequest request; private final AcceptHeaderToFormat acceptHeaderToFormat; @Inject public DefaultFormatResolver(HttpServletRequest request, AcceptHeaderToFormat acceptHeaderToFormat) { this.request = request; this.acceptHeaderToFormat = acceptHeaderToFormat; } public String getAcceptFormat() { String format = request.getParameter("_format"); if (format != null) { return format; } format = request.getHeader("Accept"); Thursday, September 5, 13
  41. 41. Trocar o request o tempo todo @Inject private CDIHttpServletRequestFactory requestFactory; @Inject private CDIHttpSessionFactory sessionFactory; public <T> T provideForRequest(RequestInfo request) { //configurando produtores requestFactory.setRequest(request); sessionFactory.setSession(request); return execution.insideRequest(container); } Thursday, September 5, 13
  42. 42. Notifica o povo @Inject private Event<HttpServletRequest> eventosDeRequest; public <T> T provideForRequest(RequestInfo requestInfo, Execution<T> execution) { //configurando produtores eventosDeRequest.fire(requestInfo.getRequest()); return execution.insideRequest(container); } Thursday, September 5, 13
  43. 43. Quero ser notificado public class CDIHttpServletRequestFactory implements ComponentFactory<HttpServletRequest>{ private HttpServletRequest request; public void handle(@Observes HttpServletRequest request){ this.request = request; } public HttpServletRequest getInstance(){ return request; } } Thursday, September 5, 13
  44. 44. VRaptor já tem @RequestScoped public @interface RequestScoped { } Thursday, September 5, 13
  45. 45. Eu sou você! @Stereotype @javax.enterprise.context.RequestScoped @Named public @interface RequestScoped { } Thursday, September 5, 13
  46. 46. VRaptor não usa @Inject @Resource public class ProdutoDAO { private final EntityManager entityManager; public CDIResourceComponent(EntityManager entityManager) { this.entityManager = entityManager; } } Thursday, September 5, 13
  47. 47. Oxi, sem @Inject? • Cadê o @Inject? Thursday, September 5, 13
  48. 48. Pedimos a ele para colocar public class AddInjectToConstructorExtension implements Extension{ public void processAnnotatedType(@Observes final ProcessAnnotatedType pat) { AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder(); builder.readFromType(pat.getAnnotatedType()); if (hasArgsConstructorAndNoInjection) { Constructor constructor = constructors.get(0); //pulo do gato builder.addToConstructor(constructor,new AnnotationLiteral<Inject>() {}); //trocando a configuração original pat.setAnnotatedType(builder.create()); } } Thursday, September 5, 13
  49. 49. VRaptor já tem Factories @Component public class CDIComponent implements ComponentFactory { private final MyRequestComponent component; public CDIComponent(MyRequestComponent component) { this.component = component; } public ComponentToBeProduced getInstance() { return new ComponentToBeProduced(); } } Thursday, September 5, 13
  50. 50. Oxi, e o @Produces? • E o @Produces? Thursday, September 5, 13
  51. 51. @Produces em cima do método public class ComponentFactoryExtension implements Extension{ public void addProduces(@Observes ProcessAnnotatedType pat) { builder.readFromType(pat.getAnnotatedType()); if (ComponentFactory.class.isAssignableFrom(javaClass)) { builder.addToMethod(getInstance,new ProducesAnnotion()); } } } class ProducesAnnotion extends AnnotationLiteral<Produces>{ } Thursday, September 5, 13
  52. 52. Configura extensão • META-INF/services/ javax.enterprise.inject.spi.Extension Thursday, September 5, 13
  53. 53. Configura extensão br.com.caelum.vraptor.ioc.cdi.extensions.AddInjectToConstructorExtensi on br.com.caelum.vraptor.ioc.cdi.extensions.ComponentFactoryExtension Thursday, September 5, 13
  54. 54. E para testar? • E para testar? Thursday, September 5, 13
  55. 55. Arquillian @RunWith(Arquillian.class) public class CDIProviderRegisteringComponentsTest { @Deployment public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(DefaultPathResolver.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); } Thursday, September 5, 13
  56. 56. Arquillian public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addPackage("com.thoughtworks.xstream") } Thursday, September 5, 13
  57. 57. Problemas • Falta de controle sobre o container Thursday, September 5, 13
  58. 58. DeltaSpike cdiContainer = CdiContainerLoader.getCdiContainer(); cdiContainer.boot(); Thursday, September 5, 13
  59. 59. Controle do escopo public void start(Class<? extends Annotation> scope) { cdiContainer.getContextControl().startContext(scope); } Thursday, September 5, 13
  60. 60. Controle do escopo start(RequestScoped.class); start(SessionScoped.class); //logica stop(SessionScoped.class); stop(RequestScoped.class); Thursday, September 5, 13
  61. 61. Últimos detalhes • Funcionalidade com muitos passos Thursday, September 5, 13
  62. 62. Funcionalidade com vários passos @Controller public class PagamentoController implements Serializable{ private InformacoesDoComprador info = new InformacoesDoComprador(); @Inject public PagamentoController(Result result) { super(); this.result = result; } @Post("compra/endereco") public void associaEndereco(String endereco){ info.setEnderecoDeEntrega(endereco); } Thursday, September 5, 13
  63. 63. Funcionalidade com vários passos @Controller public class PagamentoController implements Serializable{ //resto que não coube e eu não soube ajeitar. @Post("compra/endereco") public void associaEndereco(String endereco){ info.setEnderecoDeEntrega(endereco); } @Post("compra/cartao") public void associaCartao(String numero){ //como mantém as informações do comprador? info.setNumeroDoCartao(numero); result.include("dadosComprador",info); } } Thursday, September 5, 13
  64. 64. Como implementar? • 2 Maneiras? Thursday, September 5, 13
  65. 65. Exemplo de implementação • Stateless? Thursday, September 5, 13
  66. 66. Outro exemplo • Stateful? Thursday, September 5, 13
  67. 67. Meio termo • Mangue moderado! Thursday, September 5, 13
  68. 68. Conversation @Controller @ConversationScoped public class PagamentoController implements Serializable{ @Inject private Conversation conversation; @Post("compra/endereco") public void associaEndereco(String endereco){ conversation.begin(); info.setEnderecoDeEntrega(endereco); result.redirectTo("/compra/cartao? cid="+conversation.getId()); } Thursday, September 5, 13
  69. 69. Conversation @Controller @ConversationScoped public class PagamentoController implements Serializable{ @Inject private Conversation conversation; @Post("compra/cartao") public void associaCartao(String numero){ info.setNumeroDoCartao(numero); //grava e vamo aí.. conversation.end(); result.include("dadosComprador",info); } Thursday, September 5, 13
  70. 70. Conversation @Controller @ConversationScoped public class PagamentoController implements Serializable{ @Inject public PagamentoController(Result result) { super(); this.result = result; } Thursday, September 5, 13
  71. 71. E esse result? • O Result tem que ser passivavel :( Thursday, September 5, 13
  72. 72. Não mais :) @Controller @ConversationScoped public class PagamentoController implements Serializable{ @Inject public PagamentoController(@TransientReference Result result) { super(); this.result = result; } Thursday, September 5, 13
  73. 73. Valeu! @alberto_souza github.com/asouza Thursday, September 5, 13

×