Será que o Struts 1 estava certo?

Só para você não estranhar. O blog é sobre Spring e os exemplos usados durante o post são baseados no Spring MVC. Só que esse realmente é um post de um tema mais geral.

Há muito tempo atrás tínhamos o Struts1 e o seu jeito pouco automático de fazer as coisas. Recebíamos request response como argumentos e, além disso, recebíamos também um outro parâmetro que, se não me engano, era do tipo ActionForm. Esse bendito/maldito desse ActionForm fazia o povo agonizar. Você basicamente tinha que copiar os atributos da sua classe para lá e, se tudo chegasse como deveria, você criava seu objeto de domínio e seguia com sua vida. Ele até “evoluiu” e permitiu que você tivesse atributos do mesmo tipo do seu domínio, para minimizar a duplicidade.

    public class AutorForm extends ActionForm {
      private Autor autor = new Autor();

      public void setAutor(Autor autor) {
        this.autor = autor;
      }

      public Autor getAutor(){
        return this.autor;
      }
    }

E talvez essa tenha sido a pior contribuição do Struts para os frameworks web do mundo Java. Todo mundo começou a achar que os formulários da aplicação deveriam mapear para objetos de classes do seu domínio. Claro temos os casos felizes, como o que segue abaixo.

    public String novo(@Valid Autor autor,BindingResult bindingResult){
      if (bindingResult.hasErrors()) {
        return form(autor);
      }   

      autorDao.save(autor);
      return "redirect:/autores";
    }

Só que, o meu sentimento, é que na maioria das vezes o caso não é feliz, como esse aqui.

    public String novo(@Valid Livro livro,BindingResult bindingResult){
      if (bindingResult.hasErrors()) {
        return form(livro);
      }   

      autorDao.save(livro);
      return "redirect:/livros";
    }

Você pode até parar e pensar: calma ê, isso daí é um cadastro de um livro com autor, então faz sentido criar um objeto Livro  direto. Só que é isso mesmo que o framework faz para você? O objeto do tipo Livro que foi criado, está em perfeito estado para uso? Vamos ver.

    if(livro.getAutor().getEstado().equals(Estado.BLA)) {
      ...
    }

O resultado desse código é um belo de um NPE. O estado do autor não foi preenchido automaticamente e o programador, olhando apenas para essa parte do código, não tem como saber disso. Dessa situação começam a proliferar as verificações de null no código. Ah, então vou fazer com que o método retorne Optional! Só que o estado é obrigatório, essa solução não deveria passar num código review.

Os exemplos não param aqui. Agora temos uma tela onde é necessário atualizar apenas o email do autor. E o que acontece muito é o código acabar com esse método no controller.

    public String atualizaEmail(Autor autor,BindingResult bindingResult){
      if (bindingResult.hasErrors()) {
        return form(livro);
      }   

      ...
    }

E agora? Como você vai validar que o email não veio em branco? O @Valid vai tentar aplicar a validação no objeto inteiro e ele não está completamente preenchido. Você pode até buscar uma saída e ter perfis de validação na Bean Validation. Uma outra solução que eu já vi, é a de retirar as anotações de validação do modelo e criar métodos que fazem validações específicas. Perceba, uma simples tela afetou a definição do seu modelo!

Para finalizar, quero que você note que eu nem falei do fato de você ter um monte de setter e getter no seu domínio que você não necessariamente quer. E uma parte importante, eu também era meio que a favor de fazer a maioria das coisas que eu estou criticando no post. Para mim parecia um tradeoff ok. Deixou de ser quando eu percebi o quanto de problema básico a gente tinha nos sistemas.

  1. NPE por conta de objetos inconsistentes
  2. Validações falhando por conta de ficar preso ao lance de usar a classe de domínio
  3. Métodos claramente de view explodindo nos domínios. Você tenta buscar pelo método na sua IDE e um monte só é achado na view.
  4. Dificuldade em montar um fluxo de uma tela porque você fica dependente de já ter o modelo escrito. Aí, já que vai escrever o modelo, já mapeia para o ORM e por aí vai.
  5. Uso quase nulo do construtor, potencializando a criação de objetos que não possuem a consistência exigida pelo negócio.

Talvez existam até mais motivos, mas esses foram o que vieram direto na minha mente.

Já faz um bom tempo que não associo mais formulários diretamente com domínio. E eu agradeço o Struts1 por isso! Os caras eram visionários, de verdade. Podemos agradecer também ao livro DDD, mas prefiro agradecer ao Struts mesmo :P. Está definido na minha vida que a parte web da aplicação é algo separado do domínio e faço de tudo para que as coisas não se misturem. Pegando o primeiro exemplo que eu dei aqui, que já o caso feliz. Eu faria assim:

    public String novo(@Valid NovoAutorForm form,BindingResult bindingResult){
      if (bindingResult.hasErrors()) {
        return novoForm(form);
      }   

      Autor autor = form.toAutor();
      ...
    }

Agora pegando o exemplo do cadastro de autor.

    public String novo(@Valid NovoLivroForm form,BindingResult bindingResult){
      if (bindingResult.hasErrors()) {
        return novoForm(form);
      }   

      Livro livro = form.toLivro(autorDao);
      ...
    }

Para fechar, o exemplo da atualização do cadastro do email.

    public String atualizaEmail(@Valid AtualizaEmailAutorForm form,BindingResult bindingResult){
      if (bindingResult.hasErrors()) {
        return novoForm(form);
      }   

      Autor autor = autorDao.findById(form.getId());
      autor.setEmail(form.getEmail());

      ...
    }

Para todos os exemplos eu crio objetos que representam o formulário, até para o caso super feliz. Tive uma diminuição absurda em erros bobos na aplicação, como validações simples que falhavam e NPEs. As classes de domínio ficaram bem mais enxutas, apenas com métodos que realmente precisam ser acessados. Depois de um tempo usando, posso dizer que o lance da duplicidade é coisa pequena perto dos ganhos. E para ser sincero, não é bem uma duplicação. É apenas uma incrível coincidência e, muitas vezes, uma “forçada de coincidência” por parte do programador(a) .

As classes que representam forms, em geral, tem os atributos que devem ser mapeados do formulário html(id do autor é criado como um Integer ou Long) e também possuem um método que pegam as informações e criam os objetos em questão. E aí, por exemplo, já temos um belo de um uso para o construtor das classes de domínio. Outro ponto possivelmente ruim é essa passagem do DAO como argumento do método toYYY.  Eu considero má prática, mas acho pior ainda criar uma outra classe de conversão para isso. Entre duas ruins, fui com a que eu achava menos deprimente.

Claro que agora temos alguma duplicidade e precisamos também escrever mais código. Só que os ganhos tem sido tão bons, que estou bem ok com isso. Você agora tem uma classe super coesa em relação ao formulário em questão e, se precisar, pode criar quantos métodos quiser específicos para aquele cenário.

Pelo que eu vejo no mercado, o padrão é atrelar com o domínio mesmo. Eu não tenho feito mais assim e voltei para os velhos ActionForms :).  E você, como faz? Fique a vontade, deixe o seu comentário e enriqueça a discussão.

Advertisements

Repository mais perto do Model

Há 11 anos atrás era escrito no blog da caelum um post sobre como seria legal que os nossos modelos tivessem acesso, de alguma forma, a um conjunto de objetos onde eles poderiam fazer queries. Essa ideia, também conhecida como Repository, já foi discutida zilhares de vezes por aí. Inclusive a discussão recai que, na maioria das vezes, a versão de Repository da aplicação na verdade é um simples Dao.

Independente da nomenclatura, eu acho legal dar mais poder para os models desde que não ferre o design/performance/xpto do projeto como um todo.

Para ficar mais fácil de visualizar, vamos pensar num exemplo de código. Preciso escrever uma funcionalidade que, dado um cliente, eu preciso agora buscar a lista de orçamentos dele desde um ano xpto. Algo assim:

    Cliente cliente = recuperaCliente();
    List<Orcamento> orcamentosCliente = orcamentos.buscaTodosAPartirDeDeterminadoAno(2000);

Esse é o fluxo normal, você tem um objeto cliente, mas para buscar informações sobre ele você precisa acessar o Dao. Caso clássico de comportamento separado de estado…  Eu queria que isso funcionasse da seguinte forma:

    Cliente cliente = recuperaCliente();
    cliente.orcamentosAPartirDeDeterminadoAno(2000);

O meu desejo veio a tona, mas como que eu vou conseguir navegar na lista de orçamentos? Um primeiro pensamento pode ser o seguinte:

    public class Cliente {
      ...
      @OneToMany(mappedBy="cliente")
      private List<Orcamento> orcamentos;

      public List<Orcamento> orcamentosAPartirDeDeterminadoAno(int ano){
        return orcamentos.stream()
          //o metodo que verifica o ano pode ficar dentro do orcamento...
          .filter(orcamento -> orcamento.getAno() >= ano)
          .collect(Collectors.toList());
      }
    }

O problema é que aqui estamos violando a regra de não ferrar o projeto. A depender do número de orçamentos, é muito mais rápido fazer uma query no banco e trazer o resultado. De fato então precisamos do Repository/Dao dentro do nosso modelo, já que uma query mais esperta é realmente necessária. Uma possível solução seria essa:

    public class Cliente {
      ...

      public List<Orcamento> orcamentosAPartirDeDeterminadoAno(int ano){
        return this.clienteRepository.buscaOrcamentosAPartirDoAno(this,ano);
      }
    }

Aqui vem o código que é ok para o DDD, mas que causa angustia nos nossos olhos. Não somos acostumados a isso, mesmo que o tema já tenha sido blogado, em português, faz mais de 10 anos :P. Uma vez que você supere isso e queira se aventurar, vem o segundo problema: como fazer para a instância do Repository aparecer dentro do meu model? Abaixo temos uma primeira abordagem.

    public class OrcamentoController{

      @GetMapping(...)
      @ResponseBody
      public List<Orcamento> orcamentosAPartirDeDeterminadoAno(Model model,int ano,@AuthenticationPrincipal Cliente cliente){
        cliente.setRepository(this.clienteRepository);
        return this.orcamentoRepository.buscaOrcamentosAPartirDoAno(this,ano);
      }
    }

Eu não acho ruim essa solução, só não gosto que ela fique exposta no meio do controller, service ou qualquer outra camada que não seja exatamente onde o objeto foi carregado. Como costumo usar o Spring Data JPA, e não queria escrever delegates para adicionar a lógica de setar o Repository, tentei uma outra solução.

    
    @Entity
    @EntityListeners(RepositoryAwareListener.class)
    public class Cliente {

      ...
    	
      private transient ClienteRepository repository;

      public List<Orcamento> orcamentosAPartirDeDeterminadoAno(int ano){
        return this.repository.buscaOrcamentosAPartirDoAno(this,ano);
      }

    }




    public class RepositoryAwareListener {

    	@PostLoad
    	public void postLoad(Object entity) throws Exception {

    		Repositories repositories = new Repositories(ApplicationContextHolder.getInstance());
    		Optional<Object> repository = repositories.getRepositoryFor(entity.getClass());

    		try {
    			Field repositoryField = entity.getClass().getDeclaredField("repository");
    			repositoryField.setAccessible(true);
    			repositoryField.set(entity, repository.get());
    		} catch (NoSuchFieldException noSuchFieldException) {
    			throw new RuntimeException(
    					"é necessário definir o atributo com nome **repository** na classe "
    							+ entity.getClass(),
    					noSuchFieldException);
    		}

    	}
    }

Caso eu precise do Repository disponível no meu modelo, eu anoto ele com um EntityListener da JPA e aí tem um listener que eu escrevi responsável por descobrir o Repository correto e setar na entidade via reflection. Esse não é um código fácil de ler, mas também ele deve ser pouco alterado durante o desenvolvimento e manutenção do sistema, por isso que não me dói muito. Uma parte legal dele é que o Spring Data já fornece uma abstração onde você pode buscar pelo Repository específico de uma entidade :).

    		Repositories repositories = new Repositories(ApplicationContextHolder.getInstance());
    		Optional<Object> repository = repositories.getRepositoryFor(entity.getClass());

Sempre vale a pena dar uma olhada/pesquisada por classes mais internas do Spring, geralmente tem algo que funciona bem para a sua necessidade do momento.

Para conseguir o ApplicationContext, eu usei a mesma tática já citada aqui no blog. Por sinal, eu só fiz isso porque não consegui achar um jeito do Spring gerenciar o Listener… Quem souber, me avise!!

Eu acho esse jeito legal e realmente não me incomoda acessar o Dao/Repository daquele ponto do código. Dado que achei um jeito razoável de fazer a injeção, consigo viver bem. E para mim o benefício claro é que você da mais contexto ao uso dos métodos do seu Repository, minimizando a chance de passar parâmetros inapropriados. A parte ruim, claramente, foi essa volta que eu tive de dar para jogar o objeto lá dentro, sem contar que é uma solução não padrão(pelo menos eu acho). Um outro ponto que exige observação é que múltiplas invocações do método vão gerar diversas queries, coisa que não aconteceria usando um lazy load do Hibernate por exemplo.

E você, em 2018, o que acha? 11 anos depois ela continua estranha? Será que vale a pena testar?

Como seu sistema envia email?

Mandar email é uma tarefa bem rotineira em nossos projetos. Mandamos email de boas vindas quando um novo usuário se cadastra, email para recuperar senha etc. Uma coisa que geralmente todas essas features tem em comum, é que o email deve ser enviado em HTML.

Existem alguns projetos para facilitar a escrita do template do email e carregá-lo dentro do projeto, o Freemarker é um desses. Mais antigamente, o Velocity também era uma opção muito usada no mercado. O objetivo do post é justamente mostrar que podemos implementar essas features com algo que já está presente no seu projeto, sem a necessidade de aprender uma nova tecnologia ou adicionar uma dependência nova no seu projeto.

Pensando no código que você escreveria com o Freemarker, seria algo mais ou menos assim:

		@Controller
		public class HomeController {
		
			@PostMapping("/usuario")
			public String novoUsuario(Usuario usuario) {
		
				usuarioDao.salva(usuario);
  
				HtmlEmail email = new HtmlEmail();
				Freemarker template = new Freemarker();
				String body = template.resolve(HomeController.class.getResourceAsStream("/boasvidas.ftl"),usuario);
				email.setBody(body);
				...
			}
		}

A ideia é que agora a gente tem que carregar o HTML de uma outra forma. Pensando que nosso projeto é web, meio que já temos isso pronto. Dê uma olhada no controller que temos abaixo:

		@Controller
		public class TemplateController {
		
			@GetMapping("/template/boas-vindas")
			public String boasVindas(Integer idUsuario,Model model) {
				Usuario usuario = usuarioDao.carrega(idUsuario);
				model.addAttribute("usuario", usuario);
				return "templates/boasvindas";
			}
		}

Este é um controller que serve como gerador de HTML para emails que precisam ser enviados pelo sistema. Agora só precisamos acessar o endereço no momento de envio dos emails.

		@Controller
		public class HomeController {
		
			@GetMapping("/")
			public String novoUsuario(Usuario usuario) {
				RestTemplate restTemplate = new RestTemplate();
				ResponseEntity<String> entity = restTemplate.getForEntity("http://localhost:8080/template/boas-vindas/"+usuario.getId(), String.class);
				String body = entity.getBody();
				
				HtmlEmail email = new HtmlEmail();
				email.setBody(body);
				
				return "home/index";
			}
		}

Dessa forma resolvemos o problema de geração do conteúdo do email. Como o acesso é feito via localhost, não interfere quase nada no desempenho. Além disso você pode continuar escrevendo seu HTML da mesma maneira que sempre escreveu, o que também é um bom ganho.

O post em si não tem muito haver com o universo do Spring, mas achei legal compartilhar porque é uma solução que tenho usado bastante nos projetos e acho que tem funcionado bem. E aí, o que achou? Muita gambiarra?

Projections com Spring Data JPA

No primeiro post aqui do blog foi explicado o objetivo e como usar o projeto Spring Data JPA. Desde então já usei ele em diversos projetos e não tenho como falar o tanto de tempo que foi economizado :). Falando especificamente em relação ao post de hoje, a ideia é mostrar uma característica interessante do projeto, que é a possibilidade de fazer queries trazendo apenas uma parte dos seus objetos.

Para tentar deixar mais claro, imagine a seguinte situação: existe um projeto que eu mantenho chamado setupmyproject. Nele eu gero vários projetos dos mais variados tipos e todos eles tem um tipo, data de criação, tecnologias escolhidas, tempo que levaria para fazer na mão etc. Agora eu quero fazer um relatório só mostrando o tipo e a data de criação dos projetos. Normalmente faríamos uma JPQL da seguinte maneira:

  select p from Project p;

O código acima traz todas as informações dos objetos, mas só exibimos uma parte deles. Pensando no melhor cenário, a ideia é trazer apenas as informações necessárias, algo parecido com o que segue.

  select p.type,p.creationDate from Project p;

O problema é que isso não vai voltar em forma de List<Project> e sim em forma de List<Object[]>, já que a implementação da JPA não sabe no que transformar esse pedaço de informação. Basicamente o problema é que a JPA não tem suporte a queries parciais. Uma solução, já presente na especificação é a utilização das constructor expressions. Uma alternativa é a utliza das projections do Spring Data JPA.

A primeira coisa é modificar o método na sua interface que representa o DAO genérico no Spring Data JPA. Vamos fazer ele retornar uma List<TipoDataCriacao>.

   public interface ProjectDao extends Repository<Project,Integer>{
      @Query("select p.type,p.creationDate from Project p")
      public List<TypeCreationDate> all();
   }

Perceba que não modificamos a nossa query! Agora só precisamos criar uma interface com os getters relativos aos atributos que especificamos e o Spring Data JPA se encarrega de já criar uma implementação em execução.

  interface TypeCreationDate {
     public Type getType();
     public DateTime getCreationDate();
  }

A parte legal dessa abordagem é que você só deixa acessível o que realmente precisa e não precisa deixar a query mais complexa adicionando o new na query.

E aí, já utilizou esse recurso com o Spring Data JPA? Fique a vontade para comentar aqui no post :).

Entrevista com Arjen Poutsma, commiter do Spring!

Eu estava esperando ansiosamente para escrever este post, ele contém uma rápida entrevista com um dos principais commiters do Spring, Arjen! Ele respondeu algumas perguntas que fiz sobre o mundo que nos espera com a nova versão do framework, com o suporte integral ao conceito de Reactive Programming. Já vou deixar aqui a versão em inglês, depois posto a tradução.

Alberto: Just to introduce to our readers, could you talk a little bit about you and your role in the Spring Framework?

Arjen:  My name is Arjen Poutsma. I have been working on Spring for over ten years. I started out with Spring Web Services, then worked on Spring MVC – specifically the REST features, then Spring Scala, and for the last two years I have been working on Spring Reactive, together with Brian Clozel, Sebastien Deleuze, Stephane Maldini, abd Rossen Stoyanchev.

In this project, our team has been creating a new reactive foundation for Spring. We have essentially looked at the Spring MVC module, evaluated the code therein, and rewrote those pieces we need over to a non-blocking, event-driven style. We used Reactor as a foundation for this. The resulting code lives in the new spring-web-reactive module, next to the existing spring-webmvc module. The two modules share many concepts, but do not share any code. This is because Spring Web Reactive runs on a Reactive Streams HTTP adapter layer that’s fully non-blocking and reactive all the way down to the HTTP runtime. So while Spring MVC is built for and runs on Servlet containers, Spring Web Reactive runs also on non-Servlet runtimes such as Netty.

On top of the Spring Web Reactive module, we have two programming models. One is the existing annotation-based model, with @Controller, @RequestMapping and so on. These are the exact same annotations you use in Spring Web MVC. The other model is a recently introduced functional model, with RouterFunctions and HandlerFunctions.

I’ve attached a picture which hopefully makes this clearer.

architecture

Alberto: So, we are all excited about the new version of Spring, with the Reactive support. Could you tell us how this update will affect our way of programming?

Arjen: Just to be clear: upgrading to Spring 5 alone will not require any changes any changes to your code. As with previous major version upgrades, we have made sure that Spring 5 is backward compatible with Spring 4. So if you have a Spring 4 MVC application running on a Servlet engine, you will not have to change anything.

However, if you choose to use the new Reactive features, you will have to reconsider your architecture, as there any many differences. For instance, the guarantee that a HTTP request will be handled in a single thread is no longer the case: request will be handled by many threads, each doing a piece of the work when there is need for it (i.e. backpressure). Essentially, you are switching from a model a big thread pool, where most threads are waiting (either for incoming HTTP request, or waiting on a blocking datastore) to a model with a smaller thread pool, where each thread switches between requests many times and is effectively . Fortunately, you will not have to deal with these threads yourself, as this is where Reactor comes in. Reactor allows you to define your request handling pipeline in a functional, high-level abstraction through Flux and Mono. So rather than returning a List<Person> from your controller, for instance, you would return a Flux<Person>. However, this does also mean that relying on ThreadLocals will no longer work, and there are quite a number of frameworks and libraries (including Spring) that rely on these for some of their functionality.

Alberto: A lot of frameworks and libraries do not support this style of programming, Hibernate is an example. How can we combine our most used frameworks and Reactive Programming? The stack will evolve to support? I really like Spring Data JPA and I was thinking about that.

Arjen: Indeed, another difference between a traditional architecture and a reactive one is data stores. Obviously, in Reactive environments, there is a strong preference for non-blocking, asynchronous data stores. For some data stores, this is a great fit; for others it is not. There are a couple of NoSQL data stores that do reactive support: Couchbase, and MongoDB come to mind. For other, more traditional data access APIs, such as JDBC and JPA, there is no reactive support yet, so if you rely on them, there is no other choice than to wrap these synchronous, blocking APIs, and give them access to their own thread pool. Oracle is actually working on a non-blocking version of JDBC, but details are very sparse at this point. For JPA, the question is whether a session-based model actually makes sense in a reactive world.

Alberto: Could you explain how the Reactive Programming will help our applications to scale? Is there this relation between Reactive Programming and scalibility?

Arjen: I like to compare the two programming styles with an analogy. Imagine you are eating in a restaurant, and want to order food. The moment you make your order with the waiter, he goes off to the kitchen and prepare it. When the food is done, he will come back from the kitchen to serve it to you. After that, he will look around to see if there are any other customers in need of his attention. Now imagine the owner of the restaurant wants to have more tables, i.e. he wants to scale up. If he wants to make sure every table does not have to wait for too long, he would have to hire as many waiters as he added tables, adding a lot of cost. This is the traditional, one-thread-per-request Servlet model, where the customers are HTTP clients, and the waiters represent threads.

A reactive model would operate more like a real-life restaurant, where the waiters just relay the orders to kitchen staff, and many people (i.e. threads) are working on your order before it is served to you. Looking at it this way, it becomes quite obvious why the reactive model scales better: you are using the resources available more efficiently.

That said, the reactive model does come with a certain cost. It is harder to write asynchronous code, and it is harder to debug. So Reactive Programming will definitely help *certain* application to scale; for others I would simply say that the effort is simply not worth it. There will always be many cases where imperative is just fine for the task at hand and others where reactive and non-blocking are a must. And with Spring 5, you can do both.

Espero que você tenha gostado da entrevista! Arjen foi muito solícito e acho que nos forneceu boas respostas.

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.

 

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.