Feign uma forma simples para consumir serviços

Dificilmente uma aplicação “vive sozinha” e em algum momento pode surgir a necessidade de integrá-la com outras aplicações.

As necessidades podem ser diversas:

  • Consultar dados de um sistema legado
  • Retornar endereço a partir de um CEP
  • Efetuar pagamento online
  • Consultar o custo de envio de determinada mercadoria
  • Fazer autenticação através de alguma rede social ou qualquer

Hoje em dia muitas das integrações utilizam o modelo arquitetural REST, e não é uma tarefa muito difícil criar um cliente para consumir um serviço web.

Vamos usar como exemplo via cep, que é uma alternativa para pesquisar um endereço a partir de um CEP.

Para consumir o serviço este basta efetuar uma requisição GET no seguinte formato https://viacep.com.br/ws/NUMERO-DO-CEP/FORMATO. O formato pode ser: json,xml,piped,querty.

Se por exemplo efetuarmos uma requisição GET para https://viacep.com.br/ws/04101300/json, temos o seguinte retorno:

{
"cep": "04101-300",
"logradouro": "Rua Vergueiro",
"complemento": "de 2771 a 5049 – lado ímpar",
"bairro": "Vila Mariana",
"localidade": "São Paulo",
"uf": "SP",
"unidade": "",
"ibge": "3550308",
"gia": "1004"
}

Consumindo Serviço com RestTemplate

Para consumir um Web Service  no Spring podemos usar a classe RestTemplate que tem uma interface de uso bem simples.

Vamos criar uma aplicação com Spring Boot para consumir o serviço do via cep.

Vamos começar adicionando o parent do Spring Boot ao pom.xml:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>

E também o plugin para gerar o JAR auto-contido:

<build>
    <plugins>
       <plugin>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

Para representar o retorno do Web Service vamos criar a classe Endereco

public class Endereco {

    private String cep;
    private String logradouro;
    private String complemento;
    private String bairro;
    private String localidade;
    private String uf;

    //getters 

    @Override
    public String toString() {
        return "Endereco{" +
                "cep='" + cep + '\'' +
                ", logradouro='" + logradouro + '\'' +
                ", complemento='" + complemento + '\'' +
                ", bairro='" + bairro + '\'' +
                ", localidade='" + localidade + '\'' +
                ", uf='" + uf + '\'' +
                '}';
    }
}

Agora vamos criar a classe que inicializa o contexto do Spring:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Vamos encapsular o código para consumir o serviço em uma classe ViaCepCleient


@Component
public class ViaCEPClient {

    public Endereco buscaEnderecoPor(String cep){
        RestTemplate template = new RestRemplate();
        return template.getForObject("https://viacep.com.br/ws/{cep}/json",Endereco.class, cep);
    }
}

Como a ideia do projeto é bem simples vamos rodar tudo a partir da classe Application. A ideia é pegar o cep na variável args e através do cliente (ViaCepClient) retornar o endereço e logar no console.

O Spring Boot disponibiliza uma interface chamada CommandLineRunner que tem a declaração do método void run(String… args) throws Exception;.

Quando temos no nosso classpath algum Bean que produza CommandLineRunner, o Spring Boot após a inicialização pega o que foi recebido no método main e repassa para esse Bean.

Dessa forma conseguimos separar o código de inicialização e o código que deve ser executado baseado nos argumentos que foi passado para o Spring Boot.

Vamos alterar nossa classe Application para que ela tenha um Bean para CommandLineRunner.

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CommandLineRunner run(ViaCEPClient client){
        return args -> {
            if (args.length > 0) {
                String cep = args[0];

                Endereco endereco = client
                                     .buscaEnderecoPor(cep);

                System.out.println(endereco);
            }
        };
    }

}

Ao executarmos nossa classe Application com algum argumento veremos no console algo similar a isso:

Endereco{cep=’04101-300′, logradouro=’Rua Vergueiro’, complemento=’de 2771 a 5049 – lado ímpar’, bairro=’Vila Mariana’, localidade=’São Paulo’, uf=’SP’}

Consumindo serviço com Feign

Agora imagine em uma aplicação onde temos que consumir diversos serviços, ou em um arquitetura de micro serviços onde temos que nos integrar com diversos serviços para que a aplicação como um todo funcione. Pense em quantas vezes vamos ter que escrever um cliente usando o RestTemplate?

E geralmente se o programador teve que repetir uma tarefa mais de 3 vezes, ele automatiza essa tarefa de alguma forma.

Pensando nisso alguém teve a brilhante ideia de deixar ainda mais fácil a criação de clientes para consumir serviços. E então nasceu o projeto Feign.

O projeto Feign foi inspirado em: Retrofit, JAXRS-2.0, entre outras. Com ele podemos criar clientes de uma forma declarativa.

Então a galera do Spring incorporou o Feign dentro da sua própria stack. Mais especificamente abaixo do projeto Spring Cloud. Que é um projeto voltado para arquitetura de micro serviços, cloud e etc.

Vamos então migrar nosso cliente de RestTemplate para usar Feign. Primeiramente vamos adicionar as dependências do projeto Spring Cloud e do Feign.

O Spring Cloud segue a mesma linha do Spring Boot com as ideias dos Starters. Só que ao invés de usar um projeto base (parent) ele usa o conceito de dependências gerenciadas.

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Dalston.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Agora que temos o Spring Cloud no nosso projeto vamos adicionar a dependência do Feign

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
</dependency>

Para habilitar o Feign no projeto vamos anotar a classe Application com @EnableFeignClients

@SpringBootApplication
@EnableFeignClients
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CommandLineRunner run(ViaCEPClient client){
        return args -> {
            if (args.length > 0) {
                String cep = args[0];

                Endereco endereco = client.buscaEnderecoPor(cep);

                System.out.println(endereco);
            }
        };
    }
}

Como falei anteriormente com o Feign podemos criar clientes de uma forma declarativa. Ou seja só iremos declarar o cliente sem colocar nenhuma implementação.

Vamos começar convertendo nossa classe ViaCEPClient para uma interface (pois não queremos ter nenhuma implementação nela).

@Component
public interface ViaCEPClient {
    Endereco buscaEnderecoPor(String cep);
}

Vamos trocar a anotação @Component para @FeignClient e nela adicionar a URL do serviço.

@FeignClient(url="https://viacep.com.br/ws/")
public interface ViaCEPClient {
    Endereco buscaEnderecoPor(String cep);
}

Precisamos dizer qual o Endpoint o método Endereco buscaEnderecoPor(String cep); deve acessar.

Para isso vamos usar as anotações de mapeamento do Spring MVC:

  • @RequestMapping
  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping

Da mesma forma precisamos mapear os parâmetros:

    • @PathVariable
    • @RequestParam

.

@FeignClient(url="https://viacep.com.br/ws/")
public interface ViaCEPClient {

    @GetMapping("{cep}/json")
    Endereco buscaEnderecoPor(@PathVariable("cep") String cep);
}

Por ultimo o Feign pede que além da URL o nosso cliente de serviço tenha um nome (que nada mais é do que um identificador). Vamos adicionar o parâmetro name na anotação @FeignClient.

@FeignClient(url="https://viacep.com.br/ws/", name = "viacep")
public interface ViaCEPClient {

    @GetMapping("{cep}/json")
    Endereco buscaEnderecoPor(@PathVariable("cep") String cep);
}

Se rodarmos o código novamente teremos o mesmo resultado utilizando o RestTemplate. Com a diferença que o código real para consumir o serviço será gerado em tempo de execução. Ou seja nunca mais precisamos usar RestTemplate para gerar clientes.

E aí o que achou do Feign?

Advertisements

Spring Data Rest é vida

Fala aí galera, tudo bem? Meu nome é Fernando e sou instrutor e desenvolvedor na caelumalura.

Não é de hoje que o Spring vem facilitando nossa vida, e vamos combinar que os caras mandam muito bem!

Agora imagina só um mundo perfeito, onde declaramos nossas classes de modelo, repositórios e magicamente temos enpoints para fazermos todas as operações que declaramos nos nossos repositórios (por exemplo incluir, listar, alterar e remover).

Esse mundo perfeito existe e nele essa mágica se chama Spring data rest. Sim, ao utilizarmos ele só de declararmos nossos repositórios temos endpoints disponíveis.

Tá, legal saber que existe o Spring Data Rest.  Mas e como uso ele? (Show me the code!!!)

Bom galera eu montei um exemplo bem básico com Spring Boot Maven e está no meu Github. Nele você vai ver no arquivo pom.xml as seguintes declarações:

Spring Boot

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.4.2.RELEASE</version>
</parent>

E os staters do Spring Data e do Spring data Rest

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Além dos Starters tenho também o h2 como banco de dados em memória e o lombok.

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
</dependency>

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>

Para quem não conheçe o lombok, ele nos ajuda a escrever menos código repetitivo por exemplo: getter, setter, construtor, toString, equals/hashcode e etc...

Com ele anotamos nossos atributos com @Getter e/ou @Setter, anotamos nossa classe com @NoArgsConstructor ou @RequiredArgsConstructor, @AllArgsConstructor e ao compilarmos nosso código ele gera os byte-codes equivalentes.Vale a pena dar uma conferida!

No meu caso estou usando a anotação @Data (que engloba um monte dessas anotações) e @NoArgsConstructor (para ter um construtor sem parâmetros, por conta dos frameworks).

(OBS: Para rodar o projeto por dentro do IDE você precisa instalar o agent lombok, do contrário seu IDE não vai encontrar o getters, setters e afins.)

Em java temos duas classes de modelo Book e Author.

@Entity
@Data
@NoArgsConstructor
public class Author {

	@Id
	@GeneratedValue
	private Long id;

	@NotBlank
	private String name;

}
@Entity
@Data
@NoArgsConstructor
public class Book {

	@Id
	@GeneratedValue
	private Long id;

	@NotBlank
	private String title;

	@NotBlank
	private String description;

	@Min(50)
	private Integer numOfPages;

	@Valid
	@ManyToMany(fetch=FetchType.EAGER)
	private Set<Author> authors = new HashSet<>();

	public void add(Author author) {
		authors.add(author);
	}

}

Além do modelo tenho também um repositórios para cada, BookRepository e AuthorRepository

public interface BookRepository extends CrudRepository<Book, Long> {
}
public interface AuthorRepository extends CrudRepository<Author, Long>{
}

Para subir a aplicação tenho a classe Application que inicia o Spring Boot e salva um livro e um autor no banco de dados;

@SpringBootApplication
public class Application {

	public static void main(String[] args) throws Exception {
		SpringApplication.run(Application.class, args);
	}

	@Autowired
	private BookRepository bookRepository;

	@Autowired
	private AuthorRepository authorRepository;

	@PostConstruct
	@Transactional
	public void onLoad(){

		Author alberto = new Author();
		alberto.setName("Alberto");
		authorRepository.save(alberto);

		Book book = new Book();
		book.setTitle("Spring MVC");
		book.setDescription("Domine o principal framework web Java");
		book.setNumOfPages(237);

		book.add(alberto);

		bookRepository.save(book);

	}

}

E pronto! Temos uma endpoints para efetuarmos o CRUD de livros e autores. (Spring Data Rest é ou não é vida?)

Ao acessarmos http://localhost:8080, temos o seguinte retorno

{
"_links" : {
"authors" : {
"href" : "http://localhost:8080/authors&quot;
},
"books" : {
"href" : "http://localhost:8080/books&quot;
},
"profile" : {
"href" : "http://localhost:8080/profile&quot;
}
}
}

O Spring Data Rest usa fortemente os conceitos de HATEOAS que a grosso modo diz que através de um recurso disponível deve ser possível navegar pelo estado desse recurso através dos links. Por padrão o spring usa um modelo de apresentação chamado HAL para representação da resposta.

Bom os endpoints /authors e /books me parecem bem ok, o que deve ter neles, mas e o endpoint /profile?

Esse enpoint tem as meta-informações do seus serviços, por exemplo ao acessarmos http://localhost:8080/profile/authors temos o seguinte resultado

{
"alps":{
"version":"1.0",
"descriptors":[
{
"id":"author-representation",
"href":"http://localhost:8080/profile/authors&quot;,
"descriptors":[
{
"name":"name",
"type":"SEMANTIC"
}
]
},
{
"id":"create-authors",
"name":"authors",
"type":"UNSAFE",
"rt":"#author-representation"
},
{
"id":"get-authors",
"name":"authors",
"type":"SAFE",
"rt":"#author-representation"
},
{
"id":"patch-author",
"name":"author",
"type":"UNSAFE",
"rt":"#author-representation"
},
{
"id":"update-author",
"name":"author",
"type":"IDEMPOTENT",
"rt":"#author-representation"
},
{
"id":"get-author",
"name":"author",
"type":"SAFE",
"rt":"#author-representation"
},
{
"id":"delete-author",
"name":"author",
"type":"IDEMPOTENT",
"rt":"#author-representation"
}
]
}
}

Essas meta-informações estão associadas a qual representação temos no enpoint (no nosso caso)  authors e toda a definição dessa representação (os atributos e métodos). O endpoint profile é definido na RFC 6906.

Dentro da representação do author temos um objeto com id author-representation e nele temos um descritor com nome name e o tipo dele é SEMANTIC.
Esse tipo SEMANTIC indica um elemento que guarda um estado (atributo).

Além desse objeto temos um objeto com id create-authors, get-authors ou update-author ambos com nome author porém com tipos diferentes (nesse caso temos UNSAFE, SAFE e IDEMPOTENT). Esse objetos são as operações que podemos fazer sobre essa representação (methods).

Cada tipo tem um comportamento diferente:

SAFE – operações desse tipo são idempotentes e não alteram estado no servidor (GET, HEAD).

UNSAFE – operações desse tipo não são idempotentes e alteram estado no servidor (POST).

IDEMPOTENT – operações desse tipo são idempotentes e alteram estado no servidor (PUT, DELETE).

Uma operação é considerada idempotente se o resultado dele for bem sucedida indiferente do numero de vezes que ela for executada.

Agora sim, vamos para os endpoints mais “óbvieis“. Irei utilizar o programa curl para efetuar as chamadas para nosso endpoints.

Para listar nosso autores podemos efetuar a seguinte requisição:

curl -X GET http://localhost:8080/authors

(Deixei explicito o verbo GET somente por questões didáticas).

Nesse caso temos o seguinte resultado:

{
"_embedded" : {
"authors" : [ {
"name" : "Alberto",
"_links" : {
"self" : {
"href" : "http://localhost:8080/authors/1&quot;
},
"author" : {
"href" : "http://localhost:8080/authors/1&quot;
}
}]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/authors&quot;
},
"profile" : {
"href" : "http://localhost:8080/profile/authors&quot;
}
}
}

Nesse caso temos um autor com o nome Alberto e os links do autor levam ao recurso dele mesmo. E os links da representação como um todo levam a lista de autores ou ao profile de autores.

Vamos seguirmos o link para listar somente o autor Alberto.

curl -X GET http://localhost:8080/authors/1

E nesse caso temos o seguinte resultado:

{
"name" : "Alberto",
"_links" : {
"self" : {
"href" : "http://localhost:8080/authors/1&quot;
},
"author" : {
"href" : "http://localhost:8080/authors/1&quot;
}
}
}

E para criar um novo autor? bom para isso temos que usar o verbo POST.

curl -X POST -H "Content-type: application/json" -d '{"name": "Fernando"}' http://localhost:8080/authors

Agora temos dois autores, e para alterar? Fácil né, só usar outro verbo. Nesse caso o PATCH

 curl -X PATCH -H "Content-type: application/json" -d '{"name": "Fernando Willian"}' http://localhost:8080/authors/2

E para excluir vamos usar o verbo DELETE

curl -X DELETE http://localhost:8080/authors/2

Podemos usar as mesmas operações para os livros.

Para deixar um pouco mais interessante, vamos adicionar um pouco de segurança ao nossos endpoints.
Para isso vamos adicionar o starter do Spring Security no nosso arquivo pom.xml:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

E vamos configurar como será nossa autenticação e quais os endereços que queremos proteger:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication()
		.withUser("common").password("123").roles("USER").and()
		.withUser("admin").password("@dm1n").roles("ADMIN");
		
	}
	
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.httpBasic()
			.and()
				.authorizeRequests()
					.antMatchers(HttpMethod.POST, "/**").hasRole("ADMIN")
					.antMatchers(HttpMethod.PATCH, "/**").hasRole("ADMIN")
					.antMatchers(HttpMethod.DELETE, "/**").hasRole("ADMIN")
				.and()
					.csrf()
						.disable();
	}
	
}

Nessa configuração temos que nos autenticar com uma conta com permissão de ADMIN para efetuar qualquer requisição com os verbos POST, PATCH e DELETE.

Agora para incluir um novo autor devemos nos autenticar:

curl -X POST -H "Content-type: application/json" -d '{"name": "Fernando"}' http://localhost:8080/authors -u admin:@dm1n

O mesmo se aplica para alteração ou exclusão.

E aí o que achou do Spring Data Rest? Já o conhecia?

SetupMyProject open source!

Um pouco depois do meio do ano passado, foi lançado o SetupMyProject. De lá para cá podemos dizer que ele tem caminhado bem, já temos mais de 5000 downloads dos mais variados tipos de projetos. A ideia do SetupMyProject é facilitar a criação de novos projetos Java usando alguns dos frameworks mais conhecidos, como:

  1. Spring e Spring MVC
  2. Spring Boot
  3. VRaptor 4
  4. JSF 2.2
  5. JAX-RS(RestEasy)

Como a aceitação tem sido muito boa, achamos que um bom próximo passo era deixá-lo open source, e foi justamente isso que fizemos. Ele está disponível no github e todo mundo está convidado para ver nossas gambiarras, acertos e, se possível, contribuir para deixarmos o projeto ainda melhor. Tentei deixar o readme o mais convidativo possível, para que você baixe e tente até rodar na sua máquina.

Outro ponto que é legal de comentar é sobre a arquitetura do projeto, não é nada de outro mundo, mas vou deixar aqui registrado.

  1. Linguagem : Java
  2. Framework MVC : Spring MVC
  3. Spring Boot para facilitar setup e utilização de plugins do Spring
  4. ORM : Hibernate(bem pouca coisa para ser sincero)
  5. Engine para geração dos projetos : JBoss Forge 2

Olhando as tecnologias, tirando o JBoss Forge, não tem nada fora do normal. Além disso, pensando em design de código mesmo, tem bastante coisa legal. Usamos o Design Pattern Command para abstrair os passos necessários para geração de um projeto, além de um grafo ordenado, roubado do VRaptor 3, para que um comando possa informar se deve ser executado antes ou depois de outro. Da uma olhada, acho que você pode gostar :).

Caso você já tenha usado o SetupMyProject, gostaria de te pedir um pequeno favor, vai lá no github e da aquela estrela para gente :). É um jeito de sabermos o quanto a comunidade gostou e também é uma forma de incentivo. Outro ponto importante, vamos adorar que o maior número possível de issues sejam abertas. Tem um projeto que gostaria de gerar, ou algum plugin a mais que você quer ver configurado na geração do setup, nos avise por lá :).

 

 

 

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!

Access Control List: Protegendo o acesso a seus objetos

O Spring Security é um dos módulos mais usados do Spring e sem dúvida cumpre o seu papel muito bem. Ele é bastante usado para restringirmos o acesso aos métodos e urls da nossa aplicação baseado nos perfis dos usuários do sistema. Uma situação mais complicada pode aparecer quando dois usuários possuem um perfil que permite o acesso a uma mesma url, por exemplo um endereço que exibe o detalhe de uma prova dele em um sistema de provas online. Segue abaixo o exemplo:

  /prova/resolucao/1

E se o outro usuário logado também tentar acessar o mesmo endereço de detalhe? Como você vai negar o acesso? Provavelmente acabaríamos escrevendo um código parecido com o que segue.

	Usuario usuarioLogado = ...;
	ResolucaoProva resolucao = resolucaoProvaDao.carrega(idResolucao);
	if(!resolucao.pertence(usuarioLogado)){
		throw new SemAutorizacaoException("espertinho...");
	}

Essa é uma solução perfeitamente válida. O ponto negativo é que você não vai reaproveitar para os outros sistemas. Além do mais, esse sistema de permissões pode ficar mais complexo com usuários podendo ver detalhes de outros usuários, mas sem possibilidade edição por exemplo. Tudo vai depender do tipo de aplicação que você estiver desenvolvendo.

Para amenizar essa complexidade, o Spring Security tem um módulo chamado de ACL(Access Control List). O objetivo dele é justamente generalizar essa implementação nos dando a possibilidade de aplicar regras de acesso para qualquer tipo de objeto! Essa semana eu e Rafael Rollo utilizamos ele em um projeto dentro da Caelum. O objetivo do post é justamente mostrar o código necessário para deixar tudo funcionando. Respire bastante, porque não é pouco código não.

Vamos começar pela parte mais interessante, pelo menos para mim, que é a de inserir as permissões de acesso para determinado objeto. Dê uma olhada no código abaixo:

	@Autowired
	private Permissoes permissoes;

	...

	@RequestMapping(value = "/finaliza", method = RequestMethod.POST)
	public String finaliza(HttpSession session,@AuthenticationPrincipal 
				Usuario usuarioLogado) {

		ResolucaoFinal resolucaoFinal = resolucaoEmAndamento
				.geraResolucaoFinal();
		resolucaoFinalDao.save(resolucaoFinal);

		//essa classe isola o código de adicionar permissões
		permissoes.adiciona(usuarioLogado,resolucaoFinal,BasePermission.READ);

		return "redirect:/resolucao/finalizada";
	}
	@Service
	public class Permissoes {
		
		@Autowired
		private MutableAclService mutableAclService;	

		public void adiciona(UserDetails user, Object objeto, 
                      Permission... permissoes) {
	        ObjectIdentity identity = new ObjectIdentityImpl(objeto);
	        MutableAcl acl = mutableAclService.createAcl(identity);
	        PrincipalSid principalSid = new PrincipalSid(user.getUsername());
	        for (Permission permissao : permissoes) {
	        	acl.insertAce(acl.getEntries().size(), permissao, principalSid, true);			
			}
	        mutableAclService.updateAcl(acl);	
		}

	}

Vamos focar na classe Permissoes, já que nela está acontecendo a parte que nos interessa. A classe MutableAclService é a nossa porta de entrada para criar, atualizar e ler as permissões de acesso a um objeto. Tanto que nesse pequeno trecho de código usamos dois métodos dela:

  1. createAcl
  2. updateAcl

Vamos analisá-los por partes, começando pelo createAcl. 

		public void adiciona(UserDetails user, Object objeto, 
                        Permission... permissoes) {
	        ObjectIdentity identity = new ObjectIdentityImpl(objeto);
	        MutableAcl acl = mutableAclService.createAcl(identity);
                ...

O createAcl espera como argumento um ObjectIdentity, que é justamente a representação do objeto que vai ter o acesso controlado. O retorno deste método é um objeto do tipo MutableAcl, a abstração para as permissões de um objetoComo você já deve ter notado, o construtor do ObjectIdentity recebe um Object como parâmetro, já que qualquer tipo de objeto pode ser protegido. Um ponto importante é que esse Object deve ter um método chamado getId, cujo retorno será usado como chave estrangeira nas tabelas que serão criadas(ainda vamos comentar sobre isso). Caso sua classe não possua um método chamado getId, você pode usar o outro construtor que recebe além do objeto, um id como argumento.

Para falarmos do updateAcl, precisamos primeiro dar uma olhada no método insertAcl da classe MutableAcl. Através dele é que vamos adicionando permissões para o nosso objeto.

	        MutableAcl acl = mutableAclService.createAcl(identity);
	        PrincipalSid principalSid = new PrincipalSid(user.getUsername());
	        for (Permission permissao : permissoes) {
	           acl.insertAce(acl.getEntries().size(), permissao, principalSid, true);			
		}

Para ser bem sincero, essa assinatura de método é um pouco estranha para mim :/. Vamos começar pelos argumentos que fazem mais sentido, o segundo e o terceiro. O segundo argumento é um objeto cuja classe implementa a interface Permission, que é a abstração de uma permissão dentro do ACL. Ele já tem uma implementação base que é tranquila para a gente usar.

	public class BasePermission extends AbstractPermission {
		public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
		public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2
		public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
		public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
		public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16

		protected BasePermission(int mask) {
			super(mask);
		}

		protected BasePermission(int mask, char code) {
			super(mask, code);
		}
	}

Caso você esteja questionando o motivo da permissão ser representada por um int, bem vindo ao time :), neste link eles discutem sobre a decisão. O terceiro argumento do método é justamente o dono do objeto, que é representado pela classe PrincipalSid(Principal Security Identity).  Passamos como argumento no construtor dele um identificador desse “dono” que existe dentro do nosso sistema, no meu caso foi o email do usuário.

Pensando de maneira direta, os argumentos da permissão e do dono daquela permissão deveriam ser suficientes para definir a regra de acesso ao objeto, só que ainda temos outros dois. Vou tentar ser breve aqui, já que para mim eles não fazem muito sentido. A classe MutableAcl possui um outro método chamado updateAce, cuja assinatura segue abaixo:

    void updateAce(int aceIndex, Permission permission) throws NotFoundException;

Perceba que o primeiro argumento é um índice que é necessário para localizar a posição da permissão. Como para atualizar precisa do índice, para inserir você também precisar passar qual é a posição que você deseja adicionar a nova permissão. Essa é a razão do primeiro argumento do método insertAce ser um inteiro. O último argumento é um boolean para indicar se você realmente quer dar aquela permissão de acesso ao objeto. O que eu não entendo é: se você não quer dar permissão de acesso, não é melhor simplesmente não adicionar? Sei lá, devo estar me passando em alguma coisa aqui.

Com as permissões inseridas no objeto do tipo MutableAcl, podemos invocar o updateAcl da classe MutableAclService, para que tudo seja refletido no banco de dados.

Uma vez que as permissões estão associadas, você deve estar se perguntando como vamos proteger o acesso ao método. Dê uma olhada no código abaixo.

	@RequestMapping(value = "/prova/resolucao/{id}", method = RequestMethod.POST)
	@PreAuthorize("hasPermission(#id,'br.com.caelum.provas.models.ResolucaoFinal','read')")
	public String visualiza(@PathVariable("id") Integer id) {
		ResolucaoFinal resolucao = resolucaoDao.carrega(id);
		...
	}

Aqui fizemos uso das expressões suportadas pelo Spring. Por sinal esse é um tema que merece um post aqui no blog :). Temos acesso a função hasPermission que recebe três argumentos.

  1. O id objeto que está tentando ser acessado. Repare que usamos o #” para indicar que ele deve pegar esse valor do argumento de mesmo nome.
  2. A classe do objeto que ele precisa carregar.
  3. O nome da permissão que o usuário logado precisa ter. Esse nome precisa ser o mesmo da constante usada na hora de adicionar a permissão. Por default o ACL vai fazer o carregamento da permissão baseado nessa condição.

O Spring Security ACL vai verificar se o usuário logado tem acesso especificamente a este objeto. Essa é uma solução super genérica e que você pode aproveitar para qualquer projeto seu!

Para fechar, precisamos realizar as configurações necessárias para que tudo funcione. Essa parte toda eu vou deixar isolada em uma classe específica.

	@Configuration
	public class ConfiguracaoACL {

		@Autowired
		private DataSource dataSource;

		@Bean
		public AclAuthorizationStrategy aclAuthorization() {
			AclAuthorizationStrategyImpl aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(
					new SimpleGrantedAuthority("ROLE_ADMIN"));				
			return aclAuthorizationStrategy;
		}

		@Bean
		public PermissionGrantingStrategy permissionGrantingStrategy() {
			PermissionGrantingStrategy grantingStrategy = new DefaultPermissionGrantingStrategy(
					new ConsoleAuditLogger());
			return grantingStrategy;
		}

		@Bean	
		public Ehcache ehCache() {
			CacheManager cacheManager = CacheManager.create();
			if (!cacheManager.cacheExists("aclCache")) {
				cacheManager.addCache("aclCache");
			}

			Ehcache ehCache = cacheManager.getEhcache("aclCache");
			return ehCache;
		}
			

		@Bean
		public AclCache aclCache(Ehcache ehCache, PermissionGrantingStrategy grantingStrategy,
				AclAuthorizationStrategy aclAuthorizationStrategy) {
			AclCache aclCache = new EhCacheBasedAclCache(ehCache, grantingStrategy,
					aclAuthorizationStrategy);

			return aclCache;
		}

		@Bean
		public BasicLookupStrategy basicLookupStrategy(AclCache aclCache,
				AclAuthorizationStrategy aclAuthorizationStrategy,
				PermissionGrantingStrategy grantingStrategy) {

			return new BasicLookupStrategy(dataSource, aclCache, aclAuthorizationStrategy,
					grantingStrategy);
		}

		@Bean
		public MutableAclService mutableAclService(BasicLookupStrategy lookupStrategy, AclCache aclCache) {
			JdbcMutableAclService service = new JdbcMutableAclService(dataSource, lookupStrategy,
					aclCache);
			service.setClassIdentityQuery("select last_insert_id()");
			service.setSidIdentityQuery("select last_insert_id()");
			return service;
		}

		@Bean
		public MethodSecurityExpressionHandler expressionHandler(PermissionEvaluator permissionEvaluator) {
			DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
			handler.setPermissionEvaluator(permissionEvaluator);
			return handler;
		}

		@Bean
		public PermissionEvaluator permissionEvaluator(MutableAclService aclService) {
			AclPermissionEvaluator aclPermissionEvaluator = new AclPermissionEvaluator(aclService);
			return aclPermissionEvaluator;
		}

	}

Aqui você precisa medir seus esforços. Não se pode negar que cada um desses métodos produz um objeto que é necessário para o funcionamento, mas não acho saudável gastar vários parágrafos explicando um por um. Vou deixar uma lista apenas com uma breve ideia :).

  1. LookupStrategy: dependência do JdbcMutableAclService para fazer buscas no banco pelas permissões.
  2. AclCache: Camada de cache para não ficar indo no banco o tempo todo.
  3. AclAuthorizationStrategy: Verifica se certa role pode alterar permissões de um objeto.
  4. PermissionGrantingStrategy: Verifica se certo usuário pode realizar uma operação sobre o objeto.
  5. PermissionEvalutaor: Necessária para suportar o hasPermission nos métodos.

Como é de praxe, aconselho que você olhe o Javadoc de todas elas, para saber exatamente do papel de cada uma. Aproveitando, já vou fazer uma atualização no SetupMyProject para suportar a configuração do ACL :). Para completar é necessário criar as tabelas necessárias para que o módulo do ACL funcione e, além disso, modificar sua classe de configuração do Spring Security e adicionar a annotation @EnableGlobalMethodSecurity(prePostEnabled=true). Essa annotation habilita a checagem da annotation @PreAuthorize :).

Para você não esquecer, também deixo as dependências que precisam ser adicionadas no pom.xml.

		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-acl</artifactId>
		</dependency>
		<!-- cache -->

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-cache</artifactId>
		</dependency>

		<dependency>
			<groupId>net.sf.ehcache</groupId>
			<artifactId>ehcache</artifactId>
		</dependency>

Pronto! O post foi um pouco longo, mas também o uso e configuração dele não é lá uma das coisas mais fáceis. E esse foi só o primeiro deste ano, se preparem para mais. Também não deixem de mandar sugestões para temas, por aqui ou me referenciando no twitter.

Configurações automáticas do Spring Boot

Uma das mágicas do Spring Boot é que colocamos uma nova dependência no nosso projeto e magicamente tudo ou quase tudo já está configurado. A pergunta que fica é: como essa configuração é feita? Aí entra as classes denominadas de AutoConfigurations do Spring Boot.

Vamos dar uma olhada na classe abaixo:

	@Configuration
	@ConditionalOnClass({ LocalContainerEntityManagerFactoryBean.class,
			EnableTransactionManagement.class, EntityManager.class })
	@Conditional(HibernateEntityManagerCondition.class)
	@AutoConfigureAfter({ DataSourceAutoConfiguration.class })
	public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {

		private static final Log logger = LogFactory
				.getLog(HibernateJpaAutoConfiguration.class);

		private static final String JTA_PLATFORM = "hibernate.transaction.jta.platform";

		/**
		 * {@code NoJtaPlatform} implementations for various Hibernate versions.
		 */
		private static final String NO_JTA_PLATFORM_CLASSES[] = {
				"org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform",
				"org.hibernate.service.jta.platform.internal.NoJtaPlatform" };

		/**
		 * {@code WebSphereExtendedJtaPlatform} implementations for various Hibernate
		 * versions.
		 */
		private static final String WEBSHERE_JTA_PLATFORM_CLASSES[] = {
				"org.hibernate.engine.transaction.jta.platform.internal.WebSphereExtendedJtaPlatform",
				"org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform", };

		@Autowired
		private JpaProperties properties;

		@Autowired
		private DataSource dataSource;

		@Override
		protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
			return new HibernateJpaVendorAdapter();
		}
              
                ...
     }

Perceba que várias annotations foram usadas em cima da classe HibernateJpaAutoConfiguration, vamos analisar cada uma delas para que tudo fique mais claro. A mais comum é @Configuration, que é utilizada quando queremos indicar que uma classe contém métodos que produzem beans. Caso fique mais curioso, vá na classe mãe e veja os métodos anotados com @Bean. 

Uma outra interessante é a @ConditionalOnClass, que como o próprio nome diz, é utilizada para verificar se determinada classe está no classpath do projeto. Faz até bastante sentido, já que se não tiver tais classes não faz sentido configurar nada da JPA. Além dessa annotation uma outra importante é a @Conditional. Ela recebe como argumento uma classe que implementa a interface Condition, do próprio Spring, e que é utilizada para executar algum código baseada em alguma condição. Vamos dar uma olhada na classe HibernateEntityManagerCondition.

	//classe interna
	static class HibernateEntityManagerCondition extends SpringBootCondition {

		private static String[] CLASS_NAMES = {
				"org.hibernate.ejb.HibernateEntityManager",
				"org.hibernate.jpa.HibernateEntityManager" };

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context,
				AnnotatedTypeMetadata metadata) {
			for (String className : CLASS_NAMES) {
				if (ClassUtils.isPresent(className, context.getClassLoader())) {
					return ConditionOutcome.match("found HibernateEntityManager class");
				}
			}
			return ConditionOutcome.noMatch("did not find HibernateEntityManager class");
		}
	}

Simplesmente ela verifica se a implementação do EntityManager, provida pelo Hibernate, está no classpath. Ao invés de implementar a interface Condition diretamente, ela herda da interface SpringBootCondition. A ideia é que caso a condição não seja atendida um log mais claro seja escrito, para que o programador possa ter uma visão mais clara de como resolver o problema. Apenas para matar a curiosidade, vamos dar uma olhada dentro da annotation @ConditionalOnClass. 

	@Conditional(OnClassCondition.class)
	public @interface ConditionalOnClass {

		/**
		 * The classes that must be present. Since this annotation parsed by loading class
		 * bytecode it is safe to specify classes here that may ultimately not be on the
		 * classpath.
		 * @return the classes that must be present
		 */
		Class<?>[] value() default {};

		/**
		 * The classes names that must be present.
		 * @return the class names that must be present.
		 */
		String[] name() default {};

	}

Ela é só um atalho para uma @Condition que usa uma implementação pronta para checar se uma classe existe ou não no classpath. Isso é muito usado no Spring, annotations representam a composição de várias outras para que a configuração fique mais fácil para os programadores.

Para fechar a análise das annotations, faltou apenas darmos uma olhada na @AutoConfigureAfter. Como o próprio nome informa, ele diz para o Spring Boot que a classe HibernateJpaAutoConfiguration deve ser usada para criar as configurações apenas depois que a classe DataSourceAutoConfiguration for executada.

Para não passar desapercebido, dê também uma olhada no fonte da classe para você ver que realmente a maioria dos métodos que a gente se acostumou a configurar para ter o Hibernate/JPA funcionando, já está escrito dentro da AutoConfiguration provida pelo Spring Boot.

Esse foi um post que passeou um pouco mais por dentro do Spring Boot, algo que não afeta diretamente no seu dia a dia de desenvolvimento. De todo jeito, quando mais você souber do que acontece por dentro das tecnologias, mais preparado você fica para lidar com algum problema que possa aparecer.