Java for Beginner
672 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Spring. Внедрение зависимостей через конструктор

Введение в концепцию Dependency Injection (DI)

Dependency Injection (DI) — это один из основных принципов разработки программного обеспечения, основанный на инверсии управления. Этот принцип позволяет классу не создавать свои зависимости самостоятельно, а получать их извне, обычно через конструктор, сеттеры или интерфейсы. DI способствует слабой связанности компонентов и улучшает тестируемость кода.

Spring Framework построен на основе DI, что делает его важным аспектом для понимания того, как работает этот фреймворк. Внедрение зависимостей через конструктор — это один из самых распространённых и рекомендуемых подходов, так как он позволяет создавать неизменяемые объекты и упрощает тестирование.

Что такое внедрение зависимостей через конструктор?

Внедрение зависимостей через конструктор означает, что зависимости класса передаются ему через его конструктор во время создания объекта. В этом подходе зависимости становятся неизменяемыми после создания объекта, что делает код более безопасным и предсказуемым.

Когда Spring создает объект (или бин), он автоматически передает все необходимые зависимости в конструктор, используя конфигурацию, определённую в XML-файлах или аннотациях.

Пример внедрения зависимостей через конструктор

Допустим, у нас есть класс NotificationService, который зависит от другого класса MessageService. Вот как можно использовать внедрение через конструктор:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class NotificationService {

private final MessageService messageService;

// Внедрение зависимости через конструктор
@Autowired
public NotificationService(MessageService messageService) {
this.messageService = messageService;
}

public void sendNotification(String message) {
messageService.sendMessage(message);
}
}

@Component
public class MessageService {

public void sendMessage(String message) {
System.out.println("Отправка сообщения: " + message);
}
}
В данном примере класс NotificationService получает зависимость MessageService через конструктор. Аннотация @Autowired сообщает Spring, что нужно автоматически внедрить MessageService в этот конструктор.


#Java #Training #Spring #Dependency_Injection_via_constructor
Конфигурация с использованием аннотаций

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

Создадим основной класс приложения, где Spring контейнер будет автоматически создавать и управлять зависимостями:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// Получаем бин NotificationService
NotificationService notificationService = context.getBean(NotificationService.class);

// Используем сервис для отправки уведомления
notificationService.sendNotification("Привет, Spring!");
}
}


Конфигурация с использованием XML


Кроме аннотаций, Spring также поддерживает конфигурацию бинов через XML-файлы. Вот как можно задать внедрение зависимостей через конструктор в XML-конфигурации:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- Определение бина MessageService -->
<bean id="messageService" class="com.example.MessageService"/>

<!-- Определение бина NotificationService с внедрением через конструктор -->
<bean id="notificationService" class="com.example.NotificationService">
<constructor-arg ref="messageService"/>
</bean>
</beans>
При такой конфигурации Spring автоматически передаст бин messageService в конструктор бина notificationService.


Преимущества внедрения через конструктор

Иммутабельность (неизменяемость): Параметры, переданные через конструктор, становятся неизменными, что улучшает безопасность кода.
Явная зависимость: Использование конструктора делает зависимости явными, так как при создании объекта сразу видно, какие зависимости необходимы для его работы.
Тестируемость: Классы, которые используют внедрение через конструктор, проще тестировать с помощью Mock-объектов (например, с помощью фреймворков Mockito или JUnit), поскольку зависимости можно легко передать в тестах.
Невозможность создания "полуинициализированных" объектов: Все зависимости обязательно передаются в момент создания объекта, что исключает возможность использования объекта без всех необходимых ресурсов.


Когда использовать внедрение через конструктор?

Необходимые зависимости: Когда зависимость обязательна для работы класса, её лучше передавать через конструктор. Это гарантирует, что объект не может быть создан без необходимых зависимостей.
Неизменяемые объекты: Если объект не должен изменяться после создания (например, если его состояние зависит от переданных параметров), лучше использовать конструктор для передачи зависимостей.


#Java #Training #Spring #Dependency_Injection_via_constructor
Что выведет код?

Задача по Spring. Тема: #Dependency_Injection_via_setters и #Dependency_Injection_via_constructor. Сложность средняя.

Подробный разбор через 30 минут!🫡

import org.springframework.context.annotation.*;

@Configuration
class Config2410 {
@Bean
public MyService2410 myService2410() {
return new MyService2410();
}

@Bean
public MyBean2410 setterInjectedBean2410(MyService2410 myService) {
MyBean2410 bean = new MyBean2410();
bean.setMyService2410(myService);
return bean;
}

@Bean
public MyBean2410 constructorInjectedBean2410(MyService2410 myService) {
return new MyBean2410(myService);
}
}

class MyService2410 {
public void serve() {
System.out.println("Service called");
}
}

class MyBean2410 {
private MyService2410 myService;

public MyBean2410(MyService2410 myService) {
this.myService = myService;
System.out.println("Constructor injection");
}

public MyBean2410() {
System.out.println("No-arg constructor");
}

public void setMyService2410(MyService2410 myService) {
this.myService = myService;
System.out.println("Setter injection");
}

public void useService2410() {
myService.serve();
}
}

public class Task241024_2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config2410.class);

MyBean2410 setterBean = context.getBean("setterInjectedBean2410", MyBean2410.class);
MyBean2410 constructorBean = context.getBean("constructorInjectedBean2410", MyBean2410.class);

setterBean.useService2410();
constructorBean.useService2410();

context.close();
}
}


#TasksSpring