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.

Advertisements

5 thoughts on “Configurações automáticas do Spring Boot

  1. Primeiramente parabéns Alberto.
    A respeito do Spring Boot, você acha que é uma boa para a utilização em projetos de médio porte pra cima já ? A ideia dele mesmo é você no final gerar um .jar e utilizar o mesmo embarcado ? Ou somente para microservices mesmo ?

    Like

    • Oi Lucas, obrigado :).

      Você pode usar o Spring Boot em qualquer tipo de projeto que queira usar Spring. A ideia dele é facilitar a configuração, desde as dependências até as bibliotecas e frameworks que você vai querer usar junto com o Spring. No fim você pode gerar o jar, mas também tem a opção de gerar um war convencional :).

      Like

      • Olá Alberto,

        Entendi. Achei muito legal também a questão do DevTools do Spring, que é integrado com o Spring Boot.

        Em relação a utilizar ele embarcado, você acredita que ele rodando dessa maneira é possível utilizar em projetos de médio porte ou superior ou pra esses casos, utilizar ele no desenvolvimento e gerar um war convencional?

        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