Skip to the content.

Технологии программирования

Главная / Лекция 7. Spring Framework — от архитектурных проблем к модели исполнения

Лекция 7. Spring Framework — от архитектурных проблем к модели исполнения

Содержание

  1. Введение: от простого к сложному
  2. Инверсия управления (IoC)
  3. Dependency Injection
  4. Ментальная модель: приложение как граф объектов
  5. Spring Container
  6. Бины и конфигурация
  7. Autowiring
  8. Конфигурация в классическом Spring
  9. Spring Boot и автоконфигурация
  10. Введение в Spring MVC
  11. Быстрый старт: Spring Initializr

0. Введение: от простого к сложному

В начале разработки зависимости обычно выглядят просто:

UserService service = new UserService(new UserRepository());

Но в реальном приложении ситуация быстро усложняется:

class OrderService {
    private final PaymentService paymentService = new PaymentService(
        new BankClient(
            new HttpClient(),
            new RetryPolicy(),
            new MetricsCollector()
        )
    );
}

Здесь уже возникает несколько проблем:

👉 Важно: проблема не в количестве кода, а в том, кто управляет зависимостями


1. Инверсия управления (IoC)

Что меняется концептуально

В классическом подходе программа сама управляет всем:

Инверсия управления (IoC) означает, что эти обязанности передаются внешнему компоненту — контейнеру.


Что такое IoC Container

IoC Container — это компонент, который:

В Spring это реализовано через ApplicationContext.


Ключевая идея

👉 Управление «инвертируется»: не код управляет системой, а инфраструктура управляет кодом

Это проявляется, например, в веб-разработке:

@GetMapping("/users")
public List<User> getUsers() { ... }

Мы не вызываем этот метод напрямую — его вызывает фреймворк.



2. Dependency Injection

Определение

Dependency Injection (DI) — это способ передачи зависимостей объекту извне, вместо их создания внутри.


Связь с теорией

DI является практической реализацией принципа:

👉 Dependency Inversion Principle (SOLID)

Высокоуровневые модули не должны зависеть от низкоуровневых напрямую.


Пример

❌ без DI:

class UserService {
    private UserRepository repo = new UserRepository();
}

✅ с DI:

class UserService {
    private final UserRepository repo;

    public UserService(UserRepository repo) {
        this.repo = repo;
    }
}


Почему это важно

  1. Тестируемость
    UserRepository mock = mock(UserRepository.class);
    UserService service = new UserService(mock);
    
  2. Гибкость архитектуры
    • можно менять реализации без переписывания кода
  3. Явность зависимостей
    • зависимости видны в конструкторе

Виды DI


3. Ментальная модель: приложение как граф объектов

Чтобы понять Spring, важно сменить модель мышления.

Приложение — это не просто набор классов, а граф объектов, где:

Пример:

UserController → UserService → UserRepository

Что делает Spring

Spring:

  1. анализирует зависимости между объектами
  2. строит этот граф
  3. создает объекты в правильном порядке
  4. внедряет зависимости

Это позволяет не думать о создании объектов вручную.



4. Spring Container

Определение

Spring Container — это реализация IoC Container в Spring.

Основной интерфейс — ApplicationContext.


Что он делает


Что такое Bean

Bean — это объект, который создается и управляется контейнером Spring.

Важно:


Жизненный цикл (упрощенно)

  1. Создание объекта
  2. Внедрение зависимостей
  3. Инициализация
  4. Использование
  5. Уничтожение

5. Бины и конфигурация

Как объявляются бины

@Component
class UserRepository {}
@Service
class UserService {}
@Configuration
class AppConfig {
    @Bean
    UserService userService(UserRepository repo) {
        return new UserService(repo);
    }
}

Что такое Scope

Scope определяет, сколько экземпляров объекта создается контейнером.

Основные варианты:

Важно понимать: 👉 scope влияет на поведение приложения и управление состоянием


Ключевая мысль

👉 Мы описываем структуру приложения, а не процесс создания объектов



6. Autowiring

Autowiring — это механизм, с помощью которого Spring автоматически находит и внедряет зависимости.


Как это работает

Основной принцип — поиск по типу:

class UserService {
    public UserService(UserRepository repo) { ... }
}

Spring находит bean типа UserRepository и передает его.


Проблема неоднозначности

Если есть несколько бинов одного типа:

@Bean DataSource mysql()
@Bean DataSource postgres()

Spring не сможет выбрать автоматически.


Решение

@Qualifier("mysql")

или

@Primary

7. Конфигурация в классическом Spring

До появления Spring Boot разработчик явно описывал конфигурацию приложения.

XML-конфигурация (исторически основной способ)

<beans>
    <bean id="userRepository" class="com.example.UserRepository"/>

    <bean id="userService" class="com.example.UserService">
        <constructor-arg ref="userRepository"/>
    </bean>
</beans>

Что здесь происходит

👉 Важно: конфигурация = описание графа зависимостей


Java-конфигурация (более современный вариант)

@Configuration
class AppConfig {

    @Bean
    UserRepository userRepository() {
        return new UserRepository();
    }

    @Bean
    UserService userService(UserRepository repo) {
        return new UserService(repo);
    }
}

Что изменилось


Проблемы классического подхода


7. Spring Boot и автоконфигурация

Основная идея

👉 Convention over Configuration

Spring Boot:


Как работает автоконфигурация

Spring Boot:

  1. анализирует classpath
  2. определяет, какие библиотеки подключены
  3. включает соответствующие конфигурации

Пример: DataSource

Если в проекте есть:

Spring Boot автоматически:


Условная конфигурация

@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)

👉 Конфигурация включается только если:


Конфигурация через application.yml

Spring Boot выносит настройки в конфигурационные файлы:

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/app
    username: user
    password: password
  jpa:
    hibernate:
      ddl-auto: update

Что происходит


@SpringBootApplication

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

Что внутри


Как это связано с DI

Spring Boot не отменяет DI — он:


Итог

Подход Что делает разработчик
Классический Spring вручную описывает все бины
Spring Boot описывает только отклонения от стандартов


8. Введение в Spring MVC

Spring MVC — это модуль Spring, который реализует web-layer: связывает HTTP-запросы и Java-код.


8.1. Как проходит запрос


8.2. Аннотации и их смысл (с примерами)

Контроллеры

@Controller
class PageController {

    @GetMapping("/home")
    public String home() {
        return "home"; // имя HTML шаблона
    }
}
@RestController
class UserController {

    @GetMapping("/users")
    public List<User> getUsers() {
        return List.of(new User("Alex"));
    }
}

👉 Разница:


Mapping запросов

@RequestMapping("/users")
class UserController {

    @GetMapping
    List<User> getAll() { ... }

    @PostMapping
    User create() { ... }
}

Параметры запроса

PathVariable

@GetMapping("/users/{id}")
User getUser(@PathVariable Long id) {
    return service.get(id);
}

Query параметры

@GetMapping("/users")
List<User> findUsers(@RequestParam String name) {
    return service.findByName(name);
}

RequestBody

@PostMapping("/users")
User createUser(@RequestBody User user) {
    return service.create(user);
}

Комбинированный пример

@RestController
@RequestMapping("/users")
class UserController {

    @GetMapping("/{id}")
    User get(@PathVariable Long id) {
        return service.get(id);
    }

    @GetMapping
    List<User> search(@RequestParam(required = false) String name) {
        return service.search(name);
    }

    @PostMapping
    User create(@RequestBody User user) {
        return service.create(user);
    }
}

8.3. Как данные проходят через систему

Когда приходит запрос:

👉 Все это происходит автоматически через инфраструктуру Spring


8.4. Связь с архитектурой

Controller → Service → Repository

8.5. Итоговая модель

Spring MVC:

👉 Вы описываете правила обработки, а не работаете с HTTP напрямую

9 Быстрый старт: Spring Initializr

Spring Initializr — это официальный инструмент для генерации готового каркаса Spring Boot приложения.

👉 Его задача — убрать рутинный старт проекта и сразу дать рабочую основу.


Что он делает

При генерации проекта:


Как им пользоваться

  1. Выбрать:
    • язык (Java/Kotlin)
    • сборщик (Maven/Gradle)
    • версию Spring Boot
  2. Добавить зависимости (например):
    • Spring Web
    • Spring Data JPA
    • PostgreSQL Driver
  3. Скачать и открыть проект

Что получается на выходе

Минимальное приложение:

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

👉 Такой проект уже можно запустить — он поднимет Spring-контекст и (при наличии web starter) встроенный сервер.


Важная идея

👉 Spring Initializr не добавляет «магии» —
он просто генерирует правильную конфигурацию, которую можно было бы написать вручную.


Когда использовать


10. Ключевые идеи

Spring:


4 ключевые идеи

  1. IoC — управление передано контейнеру
  2. DI — способ связывания зависимостей
  3. Bean — управляемый объект
  4. Boot — автоматизация конфигурации