Será que você sabe tudo das configurações do seu projeto com Spring?

O objetivo do post é esclarecer alguns detalhes de configuração providos pelo Spring que, talvez, não seja claro para todo mundo que usa o ecossistema oferecido pelo framework. Os três primeiros parágrafos cobrem o tópico relativo a annotation @Configuration. Depois cada um cobre um tema diferente, então fique a vontade para ler na ordem que você quiser :).

O primeiro ponto é o uso da annotation @Configuration. A ideia é que você minimize a quantidade de código necessário para ensinar ao Spring quais classes do seu sistema são responsáveis  por criar objetos que serão gerenciados pelo framework. Vamos supor que você está numa aplicação web, usando o Spring MVC. Geralmente você vai ter uma classe de configuração relativa ao Servlet em si, como está exibido no código abaixo.

    public class ServletSpringMVC extends
		AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class[] {AppWebConfiguration.class};
	}

        ...

    }

Como exemplificado, a única classe que você precisa para o método getRootConfigClasses(que vai ser explicado em outro parágrafo) é a que representa a “entrada” das suas configurações. Dê uma olhada no exemplo abaixo:

      @EnableWebMvc
      @ComponentScan(basePackages="br.com.casadocodigo.loja")
      @EnableCaching
      public class AppWebConfiguration extends WebMvcConfigurerAdapter {

	@Bean
	public LocaleResolver localeResolver() {
		return new CookieLocaleResolver();
	}

     }

Perceba que essa classe já define alguns métodos anotados com @Bean, mas também está anotada com a @ComponentScan indicando o pacote base que deve ser varrido. É justamente aí que entra a annotation @Configuration. Durante a varredura, o Spring vai procurar por qualquer classe anotada com ela ou com @Component e, caso encontre, vai carregar essa classe e já invocar todos os métodos anotados com @Bean.  Lembre sempre disso, você não precisa adicionar todas as classes que servem de configuração! Outro ponto importante é: se a classe é de configuração, anote ela com @Configuration e não com @Component. Semântica é muito importante em qualquer sistema.

O segundo tópico tem a ver com o escopo de criação dos objetos que são gerenciados pelo container do Spring. Por default, todos os beans vivem no escopo de aplicação. Isso quer dizer que uma vez que o objeto foi criado, a mesma instância será utilizada por todo tempo de vida da aplicação. Não importa a classe que você esteja anotando, pode ser um @Repository, @Service ou @Controller.  O que você precisa lembrar é: caso queira criar um atributo nessa classe que não seja gerenciado pelo Spring, tenha em mente que ele será compartilhado por todo mundo na sua aplicação. Caso você queira mudar o escopo, como a maioria já deve saber, basta usar a annotation @Scope.  Na minha humilde opinião, o escopo default dos controllers deveria ser o de request. Caso você se interesse por isso, criei um exemplo que aplica esse escopo em todo mundo anotado com @Controller.

Essa é para a galera que usa o Spring Security. Quando você usa a parte de segurança, já vem habilitada a proteção contra o CSRF. Quando usamos as tags de formulário do Spring MVC, meio que por magia, começa a aparecer um campo hidden com o nome _csrf. Sabemos que a configuração do Spring Security faz esse campo aparecer, mas como? Caso você dê uma olhada na classe WebMvcSecurityConfigurationverá que ela possui um método que retorna um objeto do tipo RequestDataValueProcessor. Você pode criar implementações dessa interface para adicionar campos no formulário que usam a tag form do Spring MVC. Eu por exemplo já fiz uso, quando precisei adicionar o hidden com o estado do wizard do SetupMyProject. Isso é uma característica que eu acho muito legal no Spring MVC, como o framework tem muito feedback da comunidade, a arquitetura dele foi realmente pensada para resolver desde os problemas mais comuns nas aplicações web até as situações mais específicas.

A última configuração vem da classe responsável pela configuração da Servlet, a que geralmente herda de AbstractAnnotationConfigDispatcherServletInitializer. Existem dois métodos que você pode usar para adicionar a classe de configuração, o getRootConfigClasses e o getServletConfigClasses. Resumindo, você pode usar sempre o getRootConfigClasses. A diferença é que usando o primeiro as suas configurações são carregadas dentro de um Listener da especificação de Servlet, especificamente uma instância do objeto do tipo ContextLoaderListener. Enquanto que usando a segunda opção, suas configurações são carregadas dentro do DispatcherServlet do Spring MVC.  Usar o primeiro é até melhor, já que você garante que as configurações estarão carregadas em qualquer circunstância.

Advertisements

4 thoughts on “Será que você sabe tudo das configurações do seu projeto com Spring?

  1. Boas dicas e observações, Alberto.

    Mas deixe-me tirar algumas dúvidas com você, já que você tem mais experiência do que eu com Sprint 4.x…

    Como está o controle escopos nessa nova versão? As versões 3.x normalmente reclamavam (lançavam uma exceção) quando um bean injetado tinha um escopo MENOR que o escopo do bean hospedeiro. Depois de algumas versões da 3.x pararam de levantar exceção e permitiram isso acontecer, mas sempre com ressalvas na documentação. Podemos até resolver isso com proxy-mode (https://github.com/rponte/jsf-issuetracker-project/blob/master/src/br/com/triadworks/issuetracker/controller/util/FacesContextFactory.java#L18) mas talvez não seja exatamente o que buscamos em alguns casos (como no caso de injetar um bean de escopo prototype).

    No CDI até onde sei eles resolveram bem isso (tudo é proxy exceto @Dependent), mas no Spring normalmente configuramos praticamente TODOS os beans como escopo singleton (raramente tive a necessidade de mudar o escopo de um bean que não da camada web). E no Spring 4.x, como está isso? Tem alguma experiência com relação a escopos distintos em beans de negócio/aplicação?

    Um abraço, meu amigo!

    Like

    • Oi Rafael,

      Ainda persiste o mesmo problema. Se vc quiser injetar o escopo menor no maior, vai ter que fazer uso do proxy sim. No inicio eu achava que o CDI tinha mandado bem resolvendo isso, mas depois comecei a pensar mais e mudei de ideia. Injetar o escopo menor no maior é uma coisa um tanto quanto estranha, então prefiro que isso fique claro no código.

      Abraço!!

      Like

      • Alberto,

        Eu também acho bem estranho, tenho que confessar. No início do CDI eu considerava um estupro isso, pois não faz sentido (até discuti em listas sobre isso). Contudo, hoje não tenho mais certeza!

        Todos os contêiners estão seguindo isso para não ter que jogar a responsabilidade pro desenvolvedor, ou seja, DI e ciclo de vida (escopo) é de responsabilidade do container! Desenvolvedor deve se preocupar apenas com negócio.

        Enfim, não tenho uma opinião 100% formada ainda. Antes achava um estupro, hoje nem tanto.

        Ah! Tirando os controllers e beans da camada web, você tem usado outro escopo que não singleton nos demais beans?

        Um abraço!

        Like

  2. Opa, em geral não. Só transformo os escopos dos controllers para request por força de algum outro bean mesmo, começo com eles no modo default. Caso apareça alguém que tem ficar no escopo de sessão, aí transformo. E pegando meu comentário, eu acho estranho o escopo menor no maior, mas não condeno não :). Só gosto da abordagem de deixar isso declarado, coisa que não acontece na spec do CDI :(.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s