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. Для тех, кто не в курсе, что это за класс:

Код   
package com.javamaster.repository;
 
import java.util.ArrayList;
import java.util.List;
 
import com.javamaster.domain.Order;
 
public class OrderRepositoryImpl implements OrderRepository {
   
    private List<Order> orders = new ArrayList<Order>();
   
    public OrderRepositoryImpl() {
        Order order = new Order();
        order.setId(1);
        order.setPrice(234d);
        order.setTitle("Pizza peperoni");
        Order order2 = new Order();
        order2.setId(2);
        order2.setPrice(123d);
        order2.setTitle("Sushi Philadelfia");
        orders.add(order);
        orders.add(order2);
    }
 
    public void save(Order order) {
        orders.add(order);
    }
 
    public void delete(Order order) {
        orders.remove(order);
    }
 
    public List<Order> getAll() {
        return orders;
    }
 
    public Order getById(Integer id) {
        return orders.get(id);
    }
}

 

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

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

spring di

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

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

Код   
package com.javamaster.repository;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Repository;

import com.javamaster.domain.Order;

@Repository
public class OrderRepositoryImpl implements OrderRepository {
   
    private List<Order> orders = new ArrayList<Order>();
   
    public OrderRepositoryImpl() {
        Order order = new Order();
        order.setId(1);
        order.setPrice(234d);
        order.setTitle("Pizza peperoni");
        Order order2 = new Order();
        order2.setId(2);
        order2.setPrice(123d);
        order2.setTitle("Sushi Philadelfia");
        orders.add(order);
        orders.add(order2);
    }

    public void save(Order order) {
        orders.add(order);
    }

    public void delete(Order order) {
        orders.remove(order);
    }

    public List<Order> getAll() {
        return orders;
    }

    public Order getById(Integer id) {
        return orders.get(id);
    }
}

 

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

Код   
@Service
public class OrderServiceImpl implements OrderService {

 

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

Код   
@Autowired
private OrderRepository orderRepository;

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

@Autowired
private OrderService orderService;

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

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

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

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

 

Понравилась статья? Поделиться с друзьями:
Комментарии: 2
  1. Тузик

    Добрый день! Подскажите пожалуйста, а если у нас несколько реализаций OderRepository, как Spring’у указывать нужную реализацию? Где-то в конфигах прописывается?
    Если в конфигах, то можно ли их менять на «лету», без перезагрузки сервера…..или я как-то не так понимаю работу этой системы?
    Заранее спасибо!

  2. Denys (автор)

    Здравствуйте. Если у нас есть несколько реализаций некоего класса или объекта, то можно воспользоваться аннотацией @Qualifier
    Для одного OderRepository указываем @Qualifier(«order_repository1») для другого @Qualifier(«order_repository2») для примера. Далее, когда нам нужно внедрить зависимость в какой-то класс. Мы под аннотацией @Autowired добавляем аннотацию @Qualifier(«order_repository1») или @Qualifier(«order_repository2 «) в зависимости от того какой реализацией OderRepository хотим воспользоваться.

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

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: