Spring dependency injection — внедрение зависимостей в Spring

Продолжим тему фреймворка Spring и сегодня рассмотрим spring dependency injection или внедрение зависимостей как его еще иногда называют. Для того, чтобы разобраться как работает внедрение зависимостей в данном java фреймворке нужно разобрать понятие Inversion of Control (далее IoC) инверсия управления.

IoC — принцип объектно-ориентированного программирования, который предназначен для уменьшения связанности модулей и классов программы. Данный принцип входит в пятерку SOLID принципов. Если не вдаваться в подробности, то в нем говориться что модули верхних уровней не должны зависеть от модулей нижних уровней. Данные модули должны зависеть от абстракций. А если еще проще, то нужно пытаться программировать на уровне абстракций, а не реализаций. Тогда, когда Ваша реализация будет меняться, ее изменения не затронут верхние уровни.

Dependency injection (DI) — как раз и есть одной из реализаций IoC. Spring Framework имеет очень отличную поддержку DI. Как раз ее реализацию в Spring сейчас на примере и посмотрим.

Мы уже программировали на уровне абстракций. В статье Spring MVC первое веб приложение мы предоставляли доступ к нашей сущности Order через интерфейс OrderRepository и его реализацию OrderRepositoryImpl. Далее мы использовали OrderRepository в сервис слое и уже OrderService мы предоставили как конечную точку доступа к сущности Order.

На первый взгляд такая архитектура кажется избыточной, но если рассмотреть подробнее — ее реализация очень удобная в случае добавления или изменения функционала. Допустим Вы решили, что теперь будете использовать хранение данный в базе данных. Для этого Вам не нужно менять сервис и его использование. Достаточно поменять только класс OrderRepositoryImpl. Для тех, кто не в курсе, что это за класс:

Код   
  1. package com.javamaster.repository;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import com.javamaster.domain.Order;
  7.  
  8. public class OrderRepositoryImpl implements OrderRepository {
  9.    
  10.     private List<Order> orders = new ArrayList<Order>();
  11.    
  12.     public OrderRepositoryImpl() {
  13.         Order order = new Order();
  14.         order.setId(1);
  15.         order.setPrice(234d);
  16.         order.setTitle("Pizza peperoni");
  17.         Order order2 = new Order();
  18.         order2.setId(2);
  19.         order2.setPrice(123d);
  20.         order2.setTitle("Sushi Philadelfia");
  21.         orders.add(order);
  22.         orders.add(order2);
  23.     }
  24.  
  25.     public void save(Order order) {
  26.         orders.add(order);
  27.     }
  28.  
  29.     public void delete(Order order) {
  30.         orders.remove(order);
  31.     }
  32.  
  33.     public List<Order> getAll() {
  34.         return orders;
  35.     }
  36.  
  37.     public Order getById(Integer id) {
  38.         return orders.get(id);
  39.     }
  40. }

 

Код выше — простой DAO класс для стандартных операций над сущностью. Здесь для примера хранение происходило в списке. Если Вы решите изменить хранение данных на другую систему, поменять нужно будет только класс выше. Наш сервис ничего не знает о реализации. Он просто хранит и предоставляет методы.

Теперь о том, как реализована DI в Spring. Для того, чтобы Spring мог делать внедрения в классе есть три базовые аннотации: @Component, @Service, @Repository.

spring di

Эти аннотации нужно добавить над теми классами, которые Вы хотите внедрить в зависимости. На примете простого Spring MVC приложения попробуем реализовать данные аннотации.

Класс OrderRepositoryImpl пометим аннотацией @Repository:

Код   
  1. package com.javamaster.repository;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6. import org.springframework.stereotype.Repository;
  7.  
  8. import com.javamaster.domain.Order;
  9.  
  10. public class OrderRepositoryImpl implements OrderRepository {
  11.    
  12.     private List<Order> orders = new ArrayList<Order>();
  13.    
  14.     public OrderRepositoryImpl() {
  15.         Order order = new Order();
  16.         order.setId(1);
  17.         order.setPrice(234d);
  18.         order.setTitle("Pizza peperoni");
  19.         Order order2 = new Order();
  20.         order2.setId(2);
  21.         order2.setPrice(123d);
  22.         order2.setTitle("Sushi Philadelfia");
  23.         orders.add(order);
  24.         orders.add(order2);
  25.     }
  26.  
  27.     public void save(Order order) {
  28.         orders.add(order);
  29.     }
  30.  
  31.     public void delete(Order order) {
  32.         orders.remove(order);
  33.     }
  34.  
  35.     public List<Order> getAll() {
  36.         return orders;
  37.     }
  38.  
  39.     public Order getById(Integer id) {
  40.         return orders.get(id);
  41.     }
  42. }

 

Класс OrderServiceImpl соответственно аннотацией @Service:

Код   
  1. @Service
  2. public class OrderServiceImpl implements OrderService {

 

Теперь, чтобы использовать реализацию OrderRepository нужно в сервисе воспользоваться аннотацией @Autowired. Теперь в сервисе вместо private OrderRepository orderRepository = new OrderRepositoryImpl(); будет 

Код   
  1. @Autowired
  2. private OrderRepository orderRepository;

Теперь, чтобы использовать сервис в контроллере можно заменить строку: private OrderService orderService = new OrderServiceImpl(); на

@Autowired
private OrderService orderService;

Spring сам найден нужную реализацию выше указанных интерфейсов.

Аннотации @Component, @Service, @Repository всего лишь обозначают для спринг, что это реализации соответствующих интерфейсов.

В данной статье не будет рассмотрено внедрение зависимостей через конструкторы и сеттеры. Я считаю, что непосредственное внедрение зависимостей (на примере выше) вполне достаточно для начального уровня изучающих Spring и дальнейшее усложнение может запутать читателя.

Еще пример dependency injection на видео ниже:

 

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *