Como vai ser seu código com o Spring 5?

Faz mais ou menos 1 mês que saiu o primeiro milestone do Spring 5 com o suporte a tão comentada Reactive Programming. Não vou me alongar explicando os conceitos de programação reativa, porque já o fiz em outro post, aqui no blog mesmo. A ideia desse post é mostrar as configurações necessárias para você ter o seu projeto usando o Spring 5 e também ter um exemplo funcionando e que esteja linkado com os código que fazemos no dia a dia.

A primeira coisa que você pode fazer é clonar o projeto que eu disponibilizei no github. Lá dentro você vai encontrar o pom.xml.

		<properties>
			...
			<reactor.version>3.0.0.RC1</reactor.version>
			<spring.version>5.0.0.M1</spring.version>		
		</properties>
		<dependencyManagement>
			<dependencies>
				<dependency>
					<groupId>org.springframework.boot.experimental</groupId>
					<artifactId>spring-boot-dependencies-web-reactive</artifactId>
					<version>0.1.0.M1</version>
					<type>pom</type>
					<scope>import</scope>
				</dependency>
			</dependencies>
		</dependencyManagement>	
		<dependencies>
			<dependency>
				<groupId>org.springframework.boot.experimental</groupId>
				<artifactId>spring-boot-starter-web-reactive</artifactId>
			</dependency>		

Perceba que usamos um novo starter do Spring Boot chamado spring-boot-starter-web-reactive. Ele contém justamente todas as dependências que precisamos, algumas delas são:

  1. Project Reactor
  2. Adapters para os servidores

Outro detalhe importante é definir que queremos a versão 5 do Spring. Isso foi feito através da propriedade spring.version.

Pronto, com o projeto configurado, podemos dar uma olhada no código em si. A nossa ideia aqui é ter um endpoint que retorna um JSON representando uma lista de autores. Um código normal para isso seria assim:


	@Repository
	public class AutorDao {
		
		@Autowired
		private EntityManager manager;

		public List<Autor> listaTodos(){		
			return manager.createQuery("select a from Autor a").getResultList())				
		}
	}



	@RestController
	public class AutoresController {
		
		@Autowired
		private AutorDao autoresDao;

		@RequestMapping("/autores")
		public List<Autor> index() {
			List<Autor> result = autoresDao.listaTodos();		
			return result;
		}
	}

O problema desse código é que quando o Spring delega a execução para seu método, ele perde completamente o controle da situação. Você escreve a lógica que quiser aí dentro e ela vai ser executada até o fim. É o código que chamamos de imperativo.

A grande sacada do Spring 5 é trazer um pouco de programação funcional para nossas soluções do dia a dia. Antes de detalhar o código, vamos apenas dar uma olhada nele.

	@Repository
	public class AutorDao {
		
		@Autowired
		private EntityManager manager;

		public Mono<List<Autor>> listaTodos(){		
			Mono<List<Autor>> query = Mono.fromSupplier(() -> manager.createQuery("select a from Autor a").getResultList());
			return query;
			
		}
	}

	@RestController
	public class AutoresController {
		
		@Autowired
		private AutorDao autoresDao;

		@RequestMapping("/autores")
		public Mono<List<Autor>> index() {
			Mono<List<Autor>> result = autoresDao.listaTodos();
			System.out.println("ainda não vai ter feito a query");
			return result;
		}
	}	

Agora que você já viu, espero que tenha respirado fundo também, podemos debater um pouco do que aconteceu. A primeira coisa é que em vez de retornar uma List<Autor>, você retornou uma Mono<List<Autor>>. Lembre que Mono é um evento que emite apenas um item, nesse caso uma lista de autores. Uma variação dessa solução é a que segue abaixo.

	@Repository
	public class AutorDao {
		
		@Autowired
		private EntityManager manager;

		public Flux<Autor> listaTodos(){		
			Mono<Query> query = Mono.fromSupplier(() -> manager.createQuery("select a from Autor a"));
			Flux<Autor> list = query.flatMap((q) -> Flux.fromIterable(q.getResultList()));
			return list;
			
		}
	}

	@RestController
	public class AutoresController {
		
		@Autowired
		private AutorDao autoresDao;

		@RequestMapping("/autores")
		public Flux<Autor> index() {
			Flux<Autor> result = autoresDao.listaTodos();
			System.out.println("ainda não vai ter feito a query");
			return result;
		}
	}



Em vez do nosso DAO ter um evento só, nós dividimos os passos do método em criar um evento que emite uma Query e aí aplicamos uma transformação para ele gerar um evento que emite vários autores, no caso Flux<Autor>Não estou explicando os tipos, já que isso já está explicado no outro post.

A grande mudança aqui é que você declara os comportamentos em vez de executá-los e, fazendo isso, você delega para o Spring a responsabilidade de executar os seus códigos. A ideia é que a sua aplicação vai ter a chance de usar melhor os recursos da máquina onde ela está executando. Já que o framework parece ser mais competente para isso do que nós, desenvolvedores do código de negócio.

No exemplo que eu usei, entretanto, o maior problema é que usamos o Hibernate e ele não tem nada de reativo dentro dele. O ideal era que o método que executa a query com Hibernate retornasse a Flux e por aí vai. Quando a stack de tecnologias inteira da nossa aplicação for para esse lado, aí sim, vamos realmente tirar proveito.

 

Facilidades com Mapping no Spring MVC 4.3

Olá pessoal, tudo bem? Me chamo Alex Felipe, sou editor de conteúdo na Alura com mais foco no blog da Alura, e também, sou desenvolvedor! A partir de agora e eventualmente, estarei escrevendo alguns posts sobre Spring, ou seja, novidades do framework, dicas que fazem toda diferença no nosso dia-a-dia como desenvolvedor entre diversos tópicos super bacanas! Espero que gostem 🙂

Uma das maiores rotinas para nós, desenvolvedores que usam o Spring, é justamente mapear um método para disponibilizarmos um recurso no sistema. Como fazemos isso no Spring MVC? Basicamente utilizamos a annotation @RequestMapping, como por exemplo, para exibir a home do nosso sistema:

@Controller
public class HomeController {

	@RequestMapping("/")
	public String home() {
	    return "home";
	}

}

E então, quando acessamos o endereço "/" do nosso sistema, ele exibe o conteúdo da nossa página home. Porém, existe casos em que estamos dentro de um controller e queremos acessar a mesma URL, porém, dependendo do verbo HTTP, queremos que o nosso sistema tenha um comportamento diferente.

Por exemplo, em um sistema que eu estava desenvolvendo, continha o controller ProdutoController e dentro tinha duas funcionalidades a gravar() e a listar():

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("produtos")
public class ProdutoController {

	@RequestMapping(method = RequestMethod.POST)
	public String gravar(Produto produto) {
		// recebe produto e salva
		return "redirect:/produtos";
	}

	@RequestMapping(method = RequestMethod.GET)
	public ModelAndView listar() {
		ModelAndView mav = new ModelAndView("/produtos/lista");
		// pega produtos do banco e lista
		return mav;
	}

    //métodos

}

Note que ambos os métodos estão mapeados para o mesmo endereço, "/produtos". Porém, para que isso seja possível no controller, diferenciamos cada método pelo request method do HTTP. Em outras palavras, quando acessamos o endereço "produtos" com GET entramos no método listar() e quando acessamos com POST entramos no método gravar().

Por enquanto não há muita novidade, mas e se ao invés de ficar acessando @RequestMapping(method=AlgumaCoisa), pudéssemos fazer algo como @GetMapping para GET, ou então, @PostMapping para POST? Seria super bacana, né? Pois é, a partir da nova release 4.3 do Spring que saiu agora em Julho de 2016, já podemos fazer isso!

Então aquele mesmo controller, com essas novas annotations, ficaria da seguinte forma:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("produtos")
public class ProdutoController {

	@PostMapping
	public String gravar(Produto produto) {
		// recebe produto e salva
		return "produtos/salvo";
	}

	@GetMapping
	public ModelAndView listar() {
		ModelAndView mav = new ModelAndView("/produtos/lista");
		// pega produtos do banco e lista
		return mav;
	}

	//métodos

}

Veja que agora o nosso mapeamento é muito mais objetivo! Em outras palavras, não precisamos mais nos preocupar em ficar passando o parâmetro method para indicar a qual tipo de request method o método irá funcionar. Além do @GetMapping e @PostMapping, temos também os seguintes métodos do HTTP:

Lembrando que essas novas annotations não são implementações totalmente novas, pois, por de trás dos panos, elas ainda fazem uso da annotaton @RequestMapping. Por exemplo, a implementação do @GetMapping:

@Target(value=METHOD)
 @Retention(value=RUNTIME)
 @Documented
 @RequestMapping(method=GET)
public @interface GetMapping

Isso significa que ainda podemos utilizar os mesmos atributos que utilizamos no @RequestMapping com exceção do method que já não é mais necessário 😉

Guia das annotations do Spring

O leitor Vinicius Silva escreveu um email dizendo que seria legal ter um post, meio que de referência, sobre várias das annotations mais comuns utilizadas em projetos com Spring. A seguir fiz uma lista das que vieram na minha cabeça e que realmente eu já utilizei nos projetos. Caso tenha faltado alguma, ou exista alguma outra que você queira saber, fique a vontade para perguntar :). Então vamos lá!

@Configuration

É uma annotation que indica que determinada classe possui métodos que expõe novos beans.

@Controller

Associada com classes que possuem métodos que processam requests numa aplicação web.

@Repository

Associada com classes que isolam o acesso aos dados da sua aplicação. Comumente associada a DAO’s.

@Service

Associada com classes que representam a ideia do Service do Domain Driven Design. Para ficar menos teórico pense em classes que representam algum fluxo de negócio da sua aplicação. Por exemplo, um fluxo de finalização de compra envolve atualizar manipular o carrinho, enviar email, processar pagamento etc. Este é o típico código que temos dificuldade de saber onde vamos colocar, em geral ele pode ficar num Service :).

@Component

A annotation básica que indica que uma classe vai ser gerenciada pelo container do Spring. Todas as annotations descritas acima são, na verdade, derivadas de @Component. A ideia é justamente passar mais semântica.

@ComponentScan

Em geral você a usa em classes de configuração(@Configuration) indicando quais pacotes ou classes devem ser scaneadas pelo Spring para que essa configuração funcione.

@Bean

Anotação utilizada em cima dos métodos de uma classe, geralmente marcada com @Configuration, indicando que o Spring deve invocar aquele método e gerenciar o objeto retornado por ele. Quando digo gerenciar é que agora este objeto pode ser injetado em qualquer ponto da sua aplicação.

@Autowired

Anotação utilizada para marcar o ponto de injeção na sua classe. Você pode colocar ela sobre atributos ou sobre o seu construtor com argumentos.

@Scope

Annotation utilizada para marcar o tempo de vida de um objeto gerenciado pelo container. Pode ser utilizada em classes anotadas com @Component, ou alguma de suas derivações. Além disso também pode usada em métodos anotados com @Bean. Quando você não utiliza nenhuma, o escopo default do objeto é o de aplicação, o que significa que vai existir apenas uma instância dele durante a execução do programa. Você alterar isso, anotando o local e usando alguma das constantes que existem na classe ConfigurableBeanFactory ou WebApplicationContext.

@RequestMapping

Geralmente utilizada em cima dos métodos de uma classe anotada com @Controller. Serve para você colocar os endereços da sua aplicação que, quando acessados por algum cliente, deverão ser direcionados para o determinado método.

@ResponseBody

Utilizada em métodos anotados com @RequestMapping para indicar que o retorno do método deve ser automaticamente escrito na resposta para o cliente. Muito comum quando queremos retornar JSON ou XML em função de algum objeto da aplicação.

@Primary

Caso você tenha dois métodos anotados com @Bean e com ambos retornando o mesmo tipo de objeto, como o Spring vai saber qual dos dois injetar por default em algum ponto da sua aplicação? É para isso que serve a annotation @Primary. Indica qual é a opção padrão de injeção. Caso você não queira usar a padrão, pode recorrer a annotation @Qualifier.

@Profile

Indica em qual profile tal bean deve ser carregado. Muito comum quando você tem classes que só devem ser carregadas em ambiente de dev ou de produção. Essa eu utilizo bastante e acho uma ideia simples, mas super relevante dentro do Spring.

@SpringBootApplication

Para quem usa Spring Boot, essa é uma das primeiras que você. Ela engloba a @Component, @ComponentScan e mais uma chamada @EnableAutoConfiguration, que é utilizada pelo Spring Boot para tentar advinhar as configurações necessárias para rodar o seu projeto.

Bom, acho que é isso aí. Adoro escrever posts que foram solicitados diretamente pela galera que acompanha o meu trabalho, é uma motivação bem grande. Querendo de outros temas, é só avisar por aqui ou pelo meu twitter.

@EnableAsync

Essa aqui não é tão comum, mas muitas vezes você precisa ações no sistema em background(outra thread). Essa annotation deve ser colocada em alguma classe marcada com @Configuration, para que o Spring habilite o suporte a execução assíncrona.

@Async

Uma vez que seu projeto habilitou o uso de execução de métodos assíncronos com a @EnableAsync, você pode marcar qualquer método de um bean gerenciado do projeto com essa annotation. Quando tal método for invocado, o Spring vai garantir que a execução dele será em outra thread.

Spring 5 e Reactive programming parte 1

Antes que você continue a ler este post, preciso deixar um aviso, ainda estou formando a minha opinião sobre o real uso do conceito da programação reativa em nosso contexto de trabalho. Por mais que eu ache super importante saber as teorias, pelo menos para mim, elas não são tão relevantes se eu não consigo encaixar no meu dia a dia. Caso eu escreva alguma coisa que você não concorde, ficarei mais do que feliz de debater na parte dos comentários :).

Dada a condição que eu gosto de tentar aplicar as teorias nos projetos que eu participo, vamos pegar um exemplo real aqui. No meu tempo extra, tenho pego alguns projetos com Rasa, inclusive já mencionei ele num post anterior, e um desses projetos é um site que centraliza a venda de outros produtos.  Basicamente, no fluxo final da compra do usuário os seguintes passos são executados:

  1. Gravo um objeto que representa a compra do usuário no banco
  2. Faço uma requisição HTTP para o sistema do produto sendo comprado, avisando do novo usuário
  3. Mando um email para o usuário informando os dados de acesso para o produto que foi adquirido

Abaixo segue um exemplo de código invocado dentro do controller:

	@RequestMapping(value = "/confirma/{idCompra}")
	public String callbackPagseguro(
			@PathVariable("idCompra") String idCompra,
			@RequestParam("code") String notificationCode,
			HttpServletRequest request) {
		
		Compra compra = tentaAcharACompraPeloIdCustomizado(idCompra);
		
		customEnv.indicaAmbientePagSeguro();

		RespostaNotificacaoAssinatura resposta = customEnv.
			getRespostaNotificacaoTransacao(notificationCode);
		
		finalizaPagamento.finaliza(compra,resposta);
		

		return "redirect:/pagseguro/fim/"+compra.getTransacaoId();
	}

E aqui temos o nosso ponto a ser resolvido. Até a invocação do método no controller, o Spring tem o controle sobre tudo. Não precisamos nem ficar imaginando o que acontece lá dentro, mas sabemos que entre chegar um request no Servlet do Spring MVC e ele invocar o método correto no seu controller, muita coisa pode acontecer, seguem alguns passos.

  1. Descoberta do classe/método que deve ser invocado
  2. Conversão de parâmetros do request para os tipos esperados pelos parâmetros
  3. Execução da validação da entrada dos dados convertidos

Depois que seu método é invocado, ele ainda tem trabalho a fazer.

  1. Caso você não use o @ResponseBody, ele vai te jogar para a view em questão
  2. Caso você use o @ResponseBody no método, ele vai pegar o retorno e serializar, usando alguma biblioteca em questão, como o Jackson.

Todos esses passos são implementados do jeito que ele quiser. Atualmente a maioria deles, pelo menos eu acho, ocorre de forma serial. Tudo é executado em apenas um core do seu servidor, mesmo que ele tenha 4, 8 ou 16 núcleos. Além disso, tudo também é implementado de forma síncrona, com um passo sempre esperando o outro, antes do fluxo evoluir.

Essa vai ser uma das grandes mudanças na próxima versão do framework! Todo o core vai ser remodelado para que o framework possa tirar proveito da super infraestrutura provida pelos servidores. Execução de código em paralelo(já provido pelos parallel streams no Java 8), assíncrono, lazy etc. A ideia é que consigamos escalar o máximo nossa app dentro de uma máquina só!

Só que para sua aplicação tirar realmente proveito desse modelo, a ideia é que ela também seja escrita seguindo a mesma ideia. Para dar suporte a tudo isso, é que um dos alicerces da próxima versão do Spring vai ser o Project Reactor. Ele traz implementado as ideias de Reactive Programming e você vai ter que gastar um tempo para aprender, se quiser embarcar na aventura :P.

Agora eu vou tentar resumir ao máximo o princípio. A ideia é que tudo seja baseado em eventos, basicamente uma implementação de um Observer. Quem já conhece o pattern, talvez fique um pouco mais confortável. Vamos pegar o mesmo fluxo que tinha escrito lá em cima e fazer usando o novo modelo.

	@RequestMapping(value = "/confirma/{idCompra}")
	public Mono<ModelAndView> callBackPagseguro(@PathVariable("idCompra") 
			String idCompra,
			@RequestParam("code") String notificationCode, 
			HttpServletRequest request) {

		Mono<Compra> eventoBuscaCompra = 
			tentaAcharACompraPeloIdCustomizado(idCompra);
		
			
		Mono<Mono<NotificacaoLiberacao>> eventoNotificaLiberacao = 
			eventoBuscaCompra.map(c -> {
				customEnv.indicaAmbientePagSeguro();
				RespostaNotificacaoAssinatura resposta = customEnv
						.getRespostaNotificacaoTransacao(notificationCode);
				return finalizaPagamento.finaliza(c, resposta);
		});
		
		
		Mono<ModelAndView> eventoGeracaoModelAndView = eventoNotificaLiberacao.
			map(notificacao -> {
				return new ModelAndView("redirect:/pagseguro/fim/");			 
			});

		return eventoGeracaoModelAndView;
	}

Antes de entrar no detalhe da implementação, o que precisamos entender é o seguinte: quando o Spring MVC chamar nosso método, ainda não vamos executar nenhuma chamada para o banco de dados, nem para o outro sistema e muito menos mandar um email. Simplesmente criamos um fluxo de eventos que devem ser executadas nessa ordem e gerar o resultado esperado.

E quem vai executar? Esse é o pulo do gato, o framework! Sei lá se ele vai executar de maneira serial, paralela, síncrona ou assíncrona. Aqui você pode pensar do mesmo jeito que já pensamos em relação a chamada do Garbage Collector. Deixamos a JVM invocar ele, porque ela sabe qual é o melhor momento! Na apresentação do Spring One(instante 21:26) é comentado justamente isso, Reactive Programming não significa, necessariamente, executar tudo de maneira assíncrona, mesmo que o manifesto até passe essa ideia.

Para fechar, vamos olhar de novo o código para tentar entender como que isso foi implementado.

	@RequestMapping(value = "/confirma/{idCompra}")
	public Mono<ModelAndView> callBackPagseguro(@PathVariable("idCompra") 
			String idCompra,
			@RequestParam("code") String notificationCode, 
			HttpServletRequest request) {

		Mono<Compra> eventoBuscaCompra = 
			tentaAcharACompraPeloIdCustomizado(idCompra);
		
			
		Mono<Mono<NotificacaoLiberacao>> eventoNotificaLiberacao = 
			eventoBuscaCompra.map(c -> {
				customEnv.indicaAmbientePagSeguro();
				RespostaNotificacaoAssinatura resposta = customEnv
						.getRespostaNotificacaoTransacao(notificationCode);
				return finalizaPagamento.finaliza(c, resposta);
		});
		
		
		Mono<ModelAndView> eventoGeracaoModelAndView = eventoNotificaLiberacao.
			map(notificacao -> {
				return new ModelAndView("redirect:/pagseguro/fim/");			 
			});

		return eventoGeracaoModelAndView;
	}

Olhando com atenção, você vai perceber que o nome das minhas variáveis sempre tem a palavra evento. Como eu tinha dito, essa é a ideia. Precisamos criar vários eventos que, em algum momento do tratamento da requisição, vão ser executados. A classe Mono, representa a idea de um evento que gera(emite) apenas uma saída.

	public abstract class Mono<T> implements Publisher<T>,Backpressurable, 
	Introspectable,Completable {

	...

	}

Dentre as várias interfaces que ela implementa, está a Publisher<T>. Ela indica que determinado objeto é um produtor de eventos(sinais). Essa é uma das interfaces principais da especificação Reactor Streams. A ideia é que o tempo inteiro você esteja criando produtores de eventos. Aqui podemos dar um zoom em outro pedaço de código específico:

		Mono<Mono<NotificacaoLiberacao>> eventoNotificaLiberacao = 
			eventoBuscaCompra.map(c -> {
				customEnv.indicaAmbientePagSeguro();
				RespostaNotificacaoAssinatura resposta = customEnv
						.getRespostaNotificacaoTransacao(notificationCode);
				return finalizaPagamento.finaliza(c, resposta);
		});

Usamos o método map, tipicamente usado, nas aplicações tradicionais, para transformar coleções de um tipo para coleções de outro tipo. Só que pensando pelo lado funcional da coisa, a ideia é que o map seja uma função que recebe uma entrada X e retorna uma saída Y. No caso aqui vamos transformar um evento que gera uma compra em um evento de evento(Mono<Mono<…) que gera uma NotificacaoLiberacao.  Evento de evento? É o que? Quando temos uma sequência de produtores de eventos, dizemos que temos uma Flux! Para obter o Flux, podemos usar o flatMap :).

	Flux<NotificacaoLiberacao> eventosQueVaoGerarUmaNotificaco = 
		eventoBuscaCompra.flatMap(c -> {
			RespostaNotificacaoAssinatura resposta = customEnv
					.getRespostaNotificacaoTransacao(notificationCode);
			return finalizaPagamento.finaliza(c, resposta);
	});
	
	
	Flux<ModelAndView> eventosQueVaoGerarOModelAndView = 
		eventosQueVaoGerarUmaNotificaco.map(notificacao -> {
			return new ModelAndView("redirect:/pagseguro/fim/");			 
	});

Um outro exemplo de geração de Flux, que vai ficar para o próximo post, é quando você quiser retornar uma lista de objetos do seu DAO :).

Nesse ponto você pode estar pensando, já tem o produtor do evento, mas cadê o consumidor!? O seu pensamento não podia estar mais certo.

	Flux<ModelAndView> eventosQueVaoGerarOModelAndView = 
		eventosQueVaoGerarUmaNotificaco.map(notificacao -> {
			return new ModelAndView("redirect:/pagseguro/fim/");			 
	});
	
	ConsumerSubscriber<ModelAndView> consumer = 
		new ConsumerSubscriber<ModelAndView>();
	eventosQueVaoGerarOModelAndView.subscribe(consumer);

A classe ConsumerSubscriber é apenas uma das zilhares de implementações da interface Subscriber. Você pode associar quantos consumidores quiser, a um produtor de evento, exatamente do mesmo jeito que o Observer nos ensina. Inclusive o ConsumerSubscriber, possui um construtor para você passar os callbacks de tratamento dos eventos.

	public ConsumerSubscriber(Consumer<? super T> consumer,
			Consumer<? super Throwable> errorConsumer,
			Runnable completeConsumer) {
		this.consumer = consumer;
		this.errorConsumer = errorConsumer;
		this.completeConsumer = completeConsumer;
	}

Só que fique atento. Em geral, quando você tiver dentro do Spring 5, você não vai criar os subscribers, já que isso será trabalho do framework. Do mesmo jeito que hoje não é você que injeta as dependências nos seus objetos, e sim o container. Para fechar as interfaces importantes, quando você liga um interessado no evento(Subscriber) em um gerador de eventos(Publisher) você cria a chamada Subscription. 

Este post foi para tentar passar a ideia do novo modelo que muitos de nós teremos que lidar. Como disse no inicio, o meu entendimento ainda está em construção, o uso exagerado do método map até indica isso :).  Para facilitar o seu estudo, segue alguns links que eu usei.

  1. http://www.reactivemanifesto.org/
  2. https://www.youtube.com/watch?v=fec9nEIybp0&list=PLgGXSWYM2FpPuIFvbv6U_5cKLJB6PQbN4&index=35
  3. https://github.com/spring-projects/spring-reactive
  4. http://projectreactor.io/core/docs/reference/
  5. http://spring.io/blog/2016/02/09/reactive-spring
  6. https://github.com/reactor/lite-rx-api-hands-on

Nos próximos posts, eu vou tentar dar um zoom em outras partes do Project Reactor, além de associar com os casos de uso do nosso dia a dia. Apenas para fim de estudo, também criei um projeto no github que tenta demonstrar esse modelo de programação.

Como você disponibiliza os mesmos objetos para várias views?

Nos últimos tempos, no meu tempo extra, desenvolvi um sistema administrativo junto com um amigo meu de aulas na CaelumRasa Lariguet. Como vários destes sistemas, existem elementos dinâmicos que devem aparecer em toda santa tela que é carregada pela aplicação. No nosso caso, tínhamos que exibir sempre os últimos agendamentos e um calendário com o número de agendamentos para determinado dia. Abaixo segue um print:

componentes

Para fazer isso, uma das maneiras é adicionar esses objetos em todo request tratado pela aplicação.

	@Controller
	@RequestMapping("/cliente")
	public class ClienteController {

		@Autowired
		private ProximosServicos proximosServicos;
		@Autowired
		private CalendarioDia calendario;		
		
		@RequestMapping("/form")
		public ModelAndView form(Cliente cliente) {
			ModelAndView modelAndView = new ModelAndView("cliente/form-add");
			modelAndView.addAttribute("proximosServicos",proximosServicos);
			modelAndView.addAttribute("calendario",calendario);
			return modelAndView;

		}

		//outros métodos
	}

Como você já pode imaginar, essa solução ia ficar um pouco complicada. E se a gente precisasse colocar mais um objeto na tela? Teríamos que alterar diversos controllers! Um paliativo seria criar uma classe que faria esse trabalho para a gente.

	@Controller
	@RequestMapping("/cliente")
	public class ClienteController {

		@Autowired
		private ComponentesComunsViews componentes;
		
		@RequestMapping("/form")
		public ModelAndView form(Cliente cliente) {
			ModelAndView modelAndView = new ModelAndView("cliente/form-add");
			componentes.adicionaNaView(modelAndView);
			return modelAndView;

		}

		//outros métodos
	}

Mesmo assim, vamos ter que receber um objeto dessa classe injetado em todos os controllers e aí vamos ter que invocar um método nele para colocar tudo necessário no request. Uma segunda alternativa seria criar um interceptor. Dessa forma podemos interceptar todas as requisições, como se fosse um filtro de Servlet, e já disponibilizar esses objetos para a view.

Todas essas são formas são válidas, mas eu estou aqui para sugerir mais uma, que talvez você até já conheça. Ao invés de fazer com que todo controller ou que algum interceptor faça este trabalho, podemos simplesmente disponibilizar um objeto especializado em toda a view, de maneira automática! Vamos pegar especificamente o componente que busca os próximos serviços.

@Component
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST)
public class ProximosServicos {

	@Autowired
	private AgendamentoDao agendamentoDao;
	@Autowired
	private DataSolicitadaAgendmento dataSolicitada;

	public List<Agendamento> lista() {		
		List<Agendamento> agendamentos = agendamentoDao
				.buscaAgendamentosDoDiaAPartirDeUmHorario(dataSolicitada.get());
		return agendamentos;
	}
}

Na página, para listar os agendamentos, basta que a gente continue fazendo como já estava sendo feito.

  	<c:forEach var="agendamento" items="${proximosServicos.lista()}">
		...
	</c:forEach>

O único problema que falta resolver é: como que esse objeto foi parar na jsp? Para ensinar ao Spring MVC, basta que invoquemos mais um método na hora de configurar o nosso objeto do InternalResourceViewResolver. 

	@Bean
	public InternalResourceViewResolver internalResourceViewResolver() {
		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
		resolver.setPrefix("/WEB-INF/views/");
		resolver.setSuffix(".jsp");
		//aqui faz a mágica
		resolver.setExposeContextBeansAsAttributes(true);
		return resolver;
	}

Pronto, o objeto do tipo ProximosServicos sempre vai estar disponível em qualquer página da sua aplicação. O método setExposeContextBeansAsAttributes, como o próprio nome informa, faz com que qualquer objeto gerenciado pelo Spring fique acessível nas páginas. Caso você ache que isso pode fazer com que a gente fique usando tudo que é objeto direto na jsp, fique tranquilo, você também pode usar o setExposedContextBeanNames e passar o nome do bean que deve ser disponibilizado.

Mesmo enxergando o perigo de um acesso indiscriminado aos objetos na view, eu gosto dessa abordagem e tenho usado em meus projetos. Acho que deixamos as classes mais coesas, tanto nos controllers quanto nos objetos específicos para a camada de visualização.

Chegou até o fim do post? Conta para mim o que você achou :). Baseado nas discussões, muitas vezes, já surge a ideia para um próximo!

Saiba um pouco mais sobre os proxies do Spring

Outro dia no grupo de discussões sobre o livro de Spring MVC apareceu uma dúvida que tenho uma impressão que é um tanto recorrente. O leitor explicou mais ou menos assim: “Tenho a classe UserDAO que implementa a interface UserDetailsService. Possuo um ponto de injeção onde declaro um atributo do tipo UserDAO e marco o mesmo com @Autowired. Quando subo a minha aplicação, recebo uma exception”. Pensando no código, a situação é a que está descrita abaixo.

	@Repository
	public class UserDAO implements UserDetailsService {

		@PersistenceContext
		private EntityManager em;

		@Override
		public UserDetails loadUserByUsername(String username) 
			throws UsernameNotFoundException {
			//implementacao
		}
	}
	@EnableWebSecurity
	@Configuration
	public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

		@Override
		protected void configure(HttpSecurity http) throws Exception {
			//implementacao
		}	
		
                //injeção problemática
		@Autowired
		private UserDAO users;
		
		@Override
		protected void configure(AuthenticationManagerBuilder auth)
				throws Exception {
			//implementacao
		}
		
		
	}

A exception lançada é a seguinte:

Caused by: java.lang.IllegalArgumentException: Can not set br.com.casadocodigo.loja.daos.UserDAO field br.com.casadocodigo.loja.conf.SecurityConfiguration.users to com.sun.proxy.$Proxy49

Em uma primeira olhada talvez não faça muito sentido. Como não podemos injetar um objeto cuja classe é a mesma do ponto de injeção? Aí você começa a pesquisar e descobre que se trocar pela interface a injeção funciona corretamente.

	@Autowired
	private UserDetailsService users;

Para que isso fique mais claro, é necessário entender como que o Spring instância o seu objeto quando a classe dele implementa alguma interface.

	UserDAO delegate = new UserDAO();
	InvocationHandler handler = new InvocationHandler() {

		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			System.out.println("interceptando a invocação do metodo " + method.getName());
			return method.invoke(delegate, args);
		}
	};

        ClassLoader classLoader = //pega um classLoader;
	UserDAO instance = (UserDAO) Proxy.newProxyInstance(
			classLoader, 
			new Class[] { UserDetailsService.class }, handler);

	//invocando o método como se fosse no objeto real		
	instance.loadUserByUsername("alberto");	

A classe Proxy do pacote java.lang.reflect.Proxy é a classe padrão do Java quando necessitamos criar um objeto que segue esse design pattern. Sempre que você recebe algum objeto injetado em seu projeto com Spring, na verdade está recebendo um Proxy. O que vai causar a exception é justamente a maneira como o Proxy está sendo criado. Por exemplo, no código acima, caso tentemos executá-lo será lançada a seguinte exception.

Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to br.com.casadocodigo.loja.daos.UserDAO

Parecida com a que foi lançada quando você subiu o seu projeto :). Por default, quando implementamos alguma interface, o Spring vai criar o Proxy usando o mecanismo padrão do Java. Só para tentar deixar claro. Basicamente a implementação de um Proxy exige que uma classe seja construída em tempo de execução, herdando da classe base ou/e implementando as interfaces dessa mesma classe base. O mecanismo padrão do Java só fornece a segunda opção. Essa é a razão da exception ser lançada, não temos uma filha de UserDAO, e sim uma implementação da interface UserDetailsService.

Caso você realmente queira receber a injeção pela classe concreta, você pode configurar o Spring para criar o Proxy em função da classe concreta.

	@Repository
	@Scope(value=ConfigurableBeanFactory.SCOPE_SINGLETON,
		proxyMode=ScopedProxyMode.TARGET_CLASS)
	public class UserDAO implements UserDetailsService {
                 ...
        }

Para possibilitar esse estilo de criação de Proxy, o Spring recorre a uma biblioteca chamada cglib. Para não ficarmos curiosos, abaixo segue um exemplo de código de criação de Proxy usando o cglib.

	Enhancer enhancer = new Enhancer();
	enhancer.setSuperclass(UserDAO.class);
	UserDAO delegate = new UserDAO();
	org.springframework.cglib.proxy.InvocationHandler handler = new org.springframework.cglib.proxy.InvocationHandler() {

		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			System.out.println("interceptando a invocação do metodo " + method.getName());
			return method.invoke(delegate, args);
		}
	};
	enhancer.setCallback(handler);
	UserDAO proxy = (UserDAO) enhancer.create();
	proxy.loadUserByUsername("alberto");

A ideia desse post foi desmistificar a maneira como seus objetos são criados e injetados dentro do Spring. Em geral, toda exception faz bastante sentido. Precisamos ficar atentos e tentar sempre procurar o real motivo dela. Dessa forma nossa produtividade só cresce em cada novo projeto que pegamos, já que vamos passando cada vez menos por erros de infraestrutura.

Para que servem os qualifiers do Spring?

Atualmente na Caelum, estou participando de um projeto pequeno, bem focado em tirar relatórios de um dos nossos sistemas. Para ficar um pouco mais simples manipular os dados, pelo menos para mim, a gente criou uma aplicação que trata as informações das tabelas do sistema original e cria views ou o que for necessário em outro banco de dados, específico para os relatórios. Para completar a brincadeira, usamos um pouco do R para fazer as consultas nesse novo banco e brincar de gerar saídas para esses relatórios. Apesar do R ser legal, a utilização dele foi mais para preencher aquela vontade de brincar com algo ainda desconhecido para mim.

Como já é de praxe, a aplicação foi escrita usando o Spring Boot, mesmo ela não sendo uma aplicação web. Lembre-se disso, você pode usar o Spring para qualquer tipo de projeto, não só web :). Como ela tem que falar com dois bancos de dados, foi necessário configurar dois datasources.

	@Bean
	public DataSource dataSourceSistemaAntigo() {
		//codigo aqui
	}
	
	@Bean	
	public DataSource dataSourceRelatorios() {
		//codigo aqui
	}

Só que na hora de subir a aplicação eu tomei a seguinte exception:

	Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException:
	No qualifying bean of type [javax.sql.DataSource] is defined: expected single
	matching bean but found 2: ds_relatorios,ds_cweb

Talvez você já tenha visto a exception NoUniqueBeanDefinitionException. O nome dela não podia ser mais expressivo, o Spring encontrou dois candidatos para injetar em certo ponto do sistema.

	@Autowired
	public GeraDadosAnaliseComentarios(GeracaoRelatorioDao dao,DataSource dataSource) {
		super();
		this.dao = dao;
		this.template = new JdbcTemplate(dataSource);
	}

Como ele vai saber qual DataSource usar aqui? Para resolver essa questão, é necessário que você ensine para ele qual dos dois você quer.

	@Autowired
	public GeraDadosAnaliseComentarios(GeracaoRelatorioDao dao,
			@Qualifier("dataSourceSistemaAntigo") DataSource dataSource) {
		super();
		this.dao = dao;
		this.template = new JdbcTemplate(dataSource);
	}

Esse é o objetivo da annotation @Qualifier, ela permite que você referencie pelo nome o objeto que está injetado. Quando você anota um método com @Bean,  o Spring vai registrar o objeto retornado pelo método no container de IoC usando o mesmo nome do seu método. No caso o nome seria dataSourceSistemaAntigo. Nada também impede de você solicitar um registro com um nome diferente, basta que seja utilizado o atributo name da annotation @Bean. 

	@Bean(name="ds_cweb")	
	public DataSource dataSourceSistemaAntigo(Environment environment) {
		//codigo aqui
	}
	@Autowired
	public GeraDadosAnaliseComentarios(GeracaoRelatorioDao dao,
			@Qualifier("ds_cweb") DataSource dataSource) {
		super();
		this.dao = dao;
		this.template = new JdbcTemplate(dataSource);
	}

Mesmo com essas alterações, nossa aplicação ainda continua dando a mesma exception. O problema aqui é que a classe de auto configuração do DataSource, do Spring Boot, espera que apenas um objeto deste tipo esteja configurado(até onde sei). O trecho de código abaixo, da última versão estável do Spring Boot, mostra exatamente isso.

	if (this.applicationContext.getBeanNamesForType(DataSource.class, false,
			false).length > 0) {
		this.dataSource = this.applicationContext.getBean(DataSource.class);
	}

Precisamos agora ensinar ao Spring que ele sempre deve preferir um dos objetos, quando o lookup for feito sem o uso dos qualifiers.

	@Bean(name="ds_relatorios")	
	@Primary
	public DataSource dataSourceRelatorios(Environment environment) {
		//codigo aqui
	}

É justamente para isso que serve a annotation @Primary. Ela indica qual dos métodos produtores de objetos deve ser priorizado.

Esse post talvez não tenha sido muito avançado, mas é um erro que chega bastante nos fóruns e que muitas vezes as pessoas ficam em dúvida. Espero que ela tenha sido útil para você 🙂