Статьи

Под ботинком — весенний ботинок

Помните времена, когда нам приходилось регистрировать диспетчеров, viewResolvers и т. Д., Чтобы сделать наше весеннее веб-приложение? Тогда была @EnableWebMvcаннотация, и теперь даже это излишне.

В настоящее время единственное, что вам нужно сделать, это добавить org.springframework.boot:spring-boot-starter-webзависимость к вашему проекту, а все остальное делается автоматически.

То же самое касается подключения к базе данных. Не так давно минимальная конфигурация Spring-контекста с учетом БД была:

  • Зарегистрировать источник данных ( <jdbc:embedded-database id="dataSource" type="HSQL"/>)
  • Регистрация менеджера сущностей (через фабрику менеджеров сущностей) ( <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">)
  • Зарегистрировать менеджер транзакций ( <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >)
  • Возврат по границам транзакций на основе аннотаций ( <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/>)

По ходу дела мы отбросили конфиги XML в пользу конфигураций. Теперь все, что вам нужно сделать, это добавить еще одну зависимость org.springframework.boot:spring-boot-starter-data-jpaи некоторый драйвер БД (например com.h2database:h2) и — опять же, Spring создает все за кулисами.

Я не знаю о вас, но я становлюсь подозрительным, когда так много вещей происходит без моего ведома. После использования Spring Boot какое-то время мне нужно было заглянуть под капот, чтобы снова чувствовать себя в безопасности — не так сильно под — просто достаточно, чтобы вернуться в свою зону комфорта.

Высокий уровень просмотра

Основной механизм выглядит так:

Все волшебные бины регистрируются в Spring-конфигурациях ( @Configuration).
Но они загружаются только при соблюдении определенных условий, а именно:

  • Обязательный класс доступен на пути к классам (новые бины волшебным образом создаются при добавлении зависимости).
  • Требуемый компонент не был явно создан программистом.

Например, для загрузки, WebMvcAutoConfigurationкогда Servlet, DispatcherServletи  WebMvcConfigurerAdapterклассы находятся в пути к классам, тогда  @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurerAdapter.class })используется.

Эта конфигурация загружает все веб-настройки MVC по умолчанию, но, опять же, для большинства из них, только если конкретный компонент еще не существует.

Так, например, для проверки, если defaultViewResolver()должен быть создан,  @ConditionalOnMissingBean(InternalResourceViewResolver.class)используется.

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
        WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
(...)
public class WebMvcAutoConfiguration {
    (...)

    @Bean
    @ConditionalOnMissingBean(InternalResourceViewResolver.class)
    public InternalResourceViewResolver defaultViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix(this.prefix);
        resolver.setSuffix(this.suffix);
        return resolver;
    }

    (...)
}

Где это срабатывает?

Все начинается с того @SpringBootApplication, с которым вы комментируете свой основной класс. Если вы проверите его источник, вы обнаружите @EnableAutoConfigurationтам, и это ответственно за большую часть магии.

@SpringBootApplication
public class Application {

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

Если вы проверите, spring-boot-autoconfigure.jar/META-INF/spring.factoriesвы найдете  org.springframework.boot.autoconfigure.EnableAutoConfigurationсвойство, которое указывает, какие автоматические конфигурации будут использоваться, чтобы «угадать» и создать требуемые компоненты.

Пример использования DB Magic

Итак, давайте выясним, как создаются необходимые компоненты для доступа к БД.
Для этого давайте не будем использовать org.springframework.boot:spring-boot-starter-data-jpaзависимости в нашей витрине, а начнем с org.springframework.boot:spring-boot-starterтого, что посмотрим, какие зависимости необходимо добавить для создания приложения с поддержкой базы данных и как автоматически выполняются необходимые шаги.

Благодаря  spring-boot-starter:1.2.6.RELEASEзависимости я получил 22 bean-компонента, зарегистрированных Spring в моем приложении (18 bean-компонентов Spring + 4 специфичных для приложения bean-компонента). Нет dataSourceили  transactionManagerсреди них.

Я хочу добавить спящий объект в проект, чтобы включить  org.hibernate:hibernate-entitymanagerзависимость компиляции.
Теперь JtaAutoConfigurationс jta propertiesбобами были добавлены, как javax.transaction.Transactionпоявились на classpath.
Я надеялся HibernateJpaAutoConfigurationпоймать, но этот также требует:

  • LocalContainerEntityManagerFactoryBean(предоставить entityManager)
  • EnableTransactionManagement(предоставить transactionManager)

И то и другое можно найти в org.springframework:spring-orm, так что давайте добавим эту зависимость в путь к классам.

Теперь Spring попытается загрузить HibernateJpaAutoConfiguration, но для этого требуется dataSourcebean-компонент ( @Autowiredкак личное поле), и мы все еще его упускаем.

Легко понять, что dataSourceбудет создано DataSourceAutoConfiguration(найдено в списке в spring.factories).

Кажется, что здесь выполнены все условия, но  DataSourceAutoConfigurationкласс еще не может быть загружен, так как он использует org.apache.tomcat.jdbc.pool.DataSourceProxy, так что это зависит от org.apache.tomcat:tomcat-jdbc. Давайте добавим это и к пути к классам.

Запустив приложение, мы видим, что приближаемся, так как это время hibernate.dialectне может быть определено. Неудивительно, что Spring не смог определить это, поскольку мы не добавили никаких зависимых от БД зависимостей. Итак, давайте включим com.h2database:h2a.

Кажется, все работает сейчас. К весне 54 зерна. Среди них:

  • источник данных ( org.apache.tomcat.jdbc.pool.DataSourceдобавлен DataSourceAutoConfiguration.NonEmbeddedConfiguration.dataSource())
  • entityManagerFactory (- org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBeanдобавлено JpaBaseConfiguration.entityManagerFactory()(родитель HibernateJpaAutoConfiguration))
  • org.springframework.orm.jpa.JpaTransactionManageractionManager (- добавлено JpaBaseConfiguration.transactionManager()(родитель HibernateJpaAutoConfiguration)

Зависимости приведены на диаграмме ниже:

Демонстрационный проект можно найти здесь .