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 через XML

Spring Framework предлагает несколько способов конфигурации бинов и зависимостей, одним из которых является использование XML-файлов. Несмотря на то, что конфигурация с помощью аннотаций и Java-классов становится всё более популярной, XML по-прежнему остается важной частью Spring, особенно в проектах с долгосрочной поддержкой или в сложных корпоративных приложениях.

XML-конфигурация — это способ описания бинов и зависимостей вашего приложения в виде отдельного XML-файла. Контейнер Spring считывает этот файл при старте приложения и создает бины в соответствии с описанной конфигурацией. Основное преимущество XML-конфигурации — это четкое разделение конфигурации от кода.

Основные элементы XML-конфигурации включают:
<beans> — корневой элемент, содержащий все бины и их зависимости.
<bean> — элемент, описывающий бин (объект).
<property> — элемент, задающий свойства бина и внедрение зависимостей.


Пример конфигурации Spring через XML

Рассмотрим базовый пример конфигурации Spring-приложения через XML. Допустим, у нас есть простое приложение для отправки сообщений, в котором MessageService отправляет сообщение, а MessageProcessor обрабатывает это сообщение.

1. Определение классов в Java

Создадим два класса: один для обработки сообщений, другой — для отправки.
public interface MessageService {
void sendMessage(String message);
}

public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Отправка Email: " + message);
}
}

public class MessageProcessor {
private MessageService messageService;

// Внедрение зависимости через сеттер
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}

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


2. Конфигурация XML


Теперь создадим XML-файл конфигурации, в котором мы опишем бины для классов EmailService и MessageProcessor, а также укажем зависимость.

<?xml version="1.0" encoding="UTF-8"?>
<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">

<!-- Определение бина для сервиса отправки сообщений -->
<bean id="emailService" class="com.example.EmailService"/>

<!-- Определение бина для процессора сообщений с внедрением зависимости -->
<bean id="messageProcessor" class="com.example.MessageProcessor">
<property name="messageService" ref="emailService"/>
</bean>
</beans>
Как это работает?
<bean id="emailService">: здесь определяется бин для класса EmailService. Контейнер Spring создаст объект этого класса при запуске.
<bean id="messageProcessor">: бин для MessageProcessor, в котором указана зависимость messageService. С помощью элемента <property> контейнер внедрит объект EmailService в MessageProcessor.


3. Запуск приложения

Чтобы использовать эту конфигурацию, нам нужно загрузить XML-файл в контекст Spring и запросить созданные бины.
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
public static void main(String[] args) {
// Загрузка XML-конфигурации
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

// Получение бина messageProcessor
MessageProcessor processor = (MessageProcessor) context.getBean("messageProcessor");

// Использование бина
processor.processMessage("Привет, Spring!");
}
}


#Java #Training #Spring #Spring_Configuration_XML
Особенности конфигурации через XML

Внедрение зависимостей через конструктор
Spring также поддерживает внедрение зависимостей через конструктор в XML-конфигурации. Для этого используется элемент <constructor-arg>.
<bean id="emailService" class="com.example.EmailService"/>

<bean id="messageProcessor" class="com.example.MessageProcessor">
<constructor-arg ref="emailService"/>
</bean>
В данном случае зависимость будет передана через конструктор класса MessageProcessor.


Использование коллекций в конфигурации

Spring позволяет передавать коллекции (списки, карты, множества) через XML-конфигурацию:
<bean id="listBean" class="java.util.ArrayList">
<constructor-arg>
<list>
<value>Item 1</value>
<value>Item 2</value>
</list>
</constructor-arg>
</bean>


Определение скоупов бинов
Скоуп бина можно задать через атрибут scope:
<bean id="emailService" class="com.example.EmailService" scope="prototype"/>
singleton (по умолчанию) — один и тот же бин создается для всего приложения.
prototype — новый экземпляр бина создается каждый раз при обращении.


Преимущества и недостатки конфигурации через XML

Преимущества:
Гибкость и модульность: конфигурация отделена от кода, что упрощает изменение и управление бинами.
Легкость интеграции в большие проекты: многие существующие корпоративные приложения до сих пор используют XML-конфигурации.
Декларативное управление зависимостями: все зависимости четко прописаны в одном месте.


Недостатки:
Больше кода: XML-конфигурации могут становиться громоздкими в больших проектах.
Меньшая гибкость по сравнению с аннотациями и Java-конфигурацией: XML не так легко поддерживать и изменять, как Java-код или аннотации.
Меньшая читабельность: сложные конфигурации могут быть трудночитаемыми.


Когда использовать XML-конфигурацию?

Несмотря на то, что современные проекты все чаще используют аннотации и Java-конфигурацию, XML может быть полезен в следующих случаях:

Поддержка старых проектов: многие старые корпоративные приложения все еще используют XML-конфигурации.
Разделение конфигурации от кода: если требуется четкое разделение кода и конфигурации, XML может быть предпочтительным.
Комбинирование с другими способами конфигурации: XML может комбинироваться с аннотациями и Java-конфигурацией.


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

import java.util.*;

public class Task211024_1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "orange"));
list.removeIf(s -> s.startsWith("b"));
list.replaceAll(String::toUpperCase);
System.out.println(list);
}
}


#Tasks
🧐 а Вы согласны?

https://t.me/Java_for_beginner_dev

#Mems
Конфигурация Spring через аннотации

В современном Spring Framework основным способом конфигурирования бинов стало использование аннотаций. Аннотации значительно упрощают разработку, так как позволяют интегрировать конфигурацию непосредственно в код, избегая громоздких XML-файлов.

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

Основные аннотации, используемые в Spring, включают:
@Component — определяет класс как Spring-бин.
@Autowired — внедряет зависимость в бин.
@Configuration — определяет класс как конфигурационный.
@Bean — указывает метод, возвращающий бин.
@Scope — задает область видимости бина.

Пример конфигурации через аннотации


Рассмотрим пример приложения для отправки сообщений с использованием аннотаций.

1. Определение классов

Создадим интерфейс MessageService и его реализацию EmailService. Затем создадим класс MessageProcessor, который будет зависеть от MessageService.
import org.springframework.stereotype.Component;

public interface MessageService {
void sendMessage(String message);
}

@Component
public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Отправка Email: " + message);
}
}

@Component
public class MessageProcessor {

private final MessageService messageService;

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

public void processMessage(String message) {
messageService.sendMessage(message);
}
}
@Component над классом EmailService и MessageProcessor указывает Spring, что эти классы должны быть зарегистрированы как бины.


2. Автоматическое внедрение зависимостей с @Autowired

Аннотация @Autowired используется для автоматического внедрения зависимостей в бин.
@Component
public class MessageProcessor {

private MessageService messageService;

@Autowired
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}

public void processMessage(String message) {
messageService.sendMessage(message);
}
}
В этом примере Spring автоматически найдет бин типа MessageService и внедрит его в метод setMessageService.


3. Конфигурация с помощью @Configuration и @Bean

Для более гибкой настройки бинов можно использовать аннотацию @Configuration, которая заменяет XML-конфигурацию на Java-класс.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

@Bean
public MessageService emailService() {
return new EmailService();
}

@Bean
public MessageProcessor messageProcessor() {
return new MessageProcessor(emailService());
}
}
@Configuration указывает, что класс содержит методы для создания бинов.
@Bean указывает метод, который возвращает бин для использования в контейнере Spring.


Запуск приложения


Чтобы запустить приложение с аннотационной конфигурацией, нужно создать ApplicationContext, используя AnnotationConfigApplicationContext.
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);

MessageProcessor processor = context.getBean(MessageProcessor.class);
processor.processMessage("Привет, Spring с аннотациями!");
}
}


#Java #Training #Spring #Spring_Configuration_Annotations
Преимущества аннотационной конфигурации

Чистота кода: Конфигурация находится непосредственно в коде, что упрощает поддержку и понимание структуры приложения.
Меньше кода: Отсутствие необходимости создавать отдельные XML-файлы для описания бинов.
Гибкость: Аннотации позволяют использовать все возможности Spring, такие как автоматическое управление зависимостями, скоупами и жизненным циклом бинов.
Лучшая интеграция с современными подходами: Аннотации легко интегрируются с другими фреймворками и библиотеками.


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

Наиболее предпочтительным способом внедрения зависимостей в Spring считается внедрение через конструктор. Этот подход упрощает тестирование и гарантирует, что объект не будет создан без всех необходимых зависимостей.
@Component
public class MessageProcessor {

private final MessageService messageService;

@Autowired
public MessageProcessor(MessageService messageService) {
this.messageService = messageService;
}

public void processMessage(String message) {
messageService.sendMessage(message);
}
}
В данном случае мы используем конструктор с аннотацией @Autowired, который внедряет зависимость MessageService.


Использование
@Qualifier для выбора реализации

Если в приложении есть несколько реализаций интерфейса, можно использовать аннотацию @Qualifier, чтобы указать, какую именно реализацию внедрить.
@Component
@Qualifier("emailService")
public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Отправка Email: " + message);
}
}

@Component
@Qualifier("smsService")
public class SmsService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Отправка SMS: " + message);
}
}

@Component
public class MessageProcessor {

private MessageService messageService;

@Autowired
@Qualifier("smsService")
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}

public void processMessage(String message) {
messageService.sendMessage(message);
}
}
В этом примере, несмотря на наличие нескольких реализаций интерфейса MessageService, с помощью @Qualifier мы указываем, что нужно использовать SmsService.


Определение скоупов через @Scope

Аннотация @Scope позволяет указать область видимости бина. По умолчанию бины создаются с областью видимости singleton, но можно указать другие области, например, prototype.
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class PrototypeBean {
public PrototypeBean() {
System.out.println("Создан новый экземпляр PrototypeBean");
}
}
Теперь при каждом запросе этого бина Spring будет создавать новый экземпляр.


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

Преимущества:
Простота и удобство: Конфигурация через аннотации делает код более понятным и чистым.
Гибкость: Возможность управлять бинами и зависимостями прямо в коде.
Снижение объема конфигураций: Отсутствие необходимости в громоздких XML-файлах.
Легкость тестирования: Аннотации позволяют легко подменять зависимости в тестах.


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


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

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

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

import org.springframework.context.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;

public class Task211024_2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfigTask.class);
MyServiceTest myService = context.getBean(MyServiceTest.class);
myService.printMessage();
}
}

@Component
class MyServiceTest {
private final MyRepository myRepository;
private final String prefix;

public MyServiceTest(MyRepository myRepository, @Value("CustomPrefix") String prefix) {
this.myRepository = myRepository;
this.prefix = prefix;
}

public void printMessage() {
System.out.println(prefix + ": " + myRepository.getData());
}
}

@Component
class MyRepository {
public String getData() {
return "Repository Data";
}
}

@Configuration
@ComponentScan()
class AppConfigTask {}


#TasksSpring
Подробный разбор решения задачи Task211024_2

1. Создание контекста:

Программа начинается с создания контекста Spring при помощи AnnotationConfigApplicationContext, который принимает конфигурационный класс AppConfigTask. Это запускает процесс сканирования компонентов (аннотированных классов) и создает все нужные бины для работы приложения.

2. Конфигурационный класс AppConfigTask:


Класс AppConfigTask помечен аннотацией
@Configuration, что говорит Spring о том, что этот класс содержит определения бинов или конфигурацию для приложения.
Аннотация
@ComponentScan() указывает, что Spring должен сканировать текущий пакет по умолчанию на наличие компонентов с аннотацией @Component и создавать для них бины.

3. Класс MyServiceTest:


Класс помечен аннотацией
@Component, поэтому Spring создаст бин для этого класса.
В конструкторе MyServiceTest происходит автоматическая инъекция зависимости через параметр MyRepository myRepository, что значит, что Spring найдет бин типа MyRepository и передаст его в конструктор.
Также в конструкторе используется аннотация
@Value("CustomPrefix"), которая указывает Spring на необходимость подставить строку "CustomPrefix" в поле prefix. Это статическое значение, жестко заданное в коде, а не загружаемое из файла конфигурации.

4. Класс MyRepository:


Этот класс также помечен аннотацией
@Component, поэтому Spring создает его бин.
Метод getData() возвращает строку "Repository Data".

5. Работа программы:


После создания контекста в методе main происходит получение бина MyServiceTest через вызов context.getBean(MyService.class).
Затем вызывается метод printMessage() у объекта MyServiceTest
Внутри метода printMessage() выводится в консоль значение переменной prefix и результат вызова метода getData() у объекта myRepository. Значение переменной prefix задается через аннотацию
@Value и равно "CustomPrefix". Метод getData() возвращает строку "Repository Data".
Соответственно, в консоли будет выведена строка "CustomPrefix: Repository Data".

Почему это работает?


Spring находит классы MyServiceTest и MyRepository благодаря аннотации
@Component и создает для них бины.
Зависимость MyRepository инъектируется в MyServiceTest через конструктор, благодаря автоматической инъекции.
Аннотация
@Value("CustomPrefix") указывает на строку, которая напрямую передается в переменную prefix, обеспечивая статическое значение без необходимости внешнего конфигурационного файла.
Результат выводится с правильным форматом: значение из prefix и значение из метода getData().


#Solution_TasksSpring
Основы Bean в Spring: создание и управление

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

Основные компоненты, связанные с бинами в Spring:

Контейнер IoC: это ядро Spring, которое отвечает за создание и управление жизненным циклом бинов.
Конфигурация: способы описания бинов, которые могут быть как в виде XML-файлов, так и с использованием аннотаций или Java-конфигурации.
Внедрение зависимостей (Dependency Injection): механизм, при котором контейнер автоматически предоставляет объектам необходимые зависимости.


Способы создания бинов в Spring

Есть несколько способов создания и определения бинов в Spring:
Создание бина через XML-конфигурацию
Создание бина с помощью аннотаций


Java-классы для конфигурации бинов

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

Пример: создадим простое приложение для отправки сообщений.
public interface MessageService {
void sendMessage(String message);
}

public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Отправка сообщения через Email: " + message);
}
}


XML-конфигурация (beans.xml):
<?xml version="1.0" encoding="UTF-8"?>
<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">

<!-- Определение бина для EmailService -->
<bean id="emailService" class="com.example.EmailService"/>
</beans>


Использование бина:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

MessageService service = (MessageService) context.getBean("emailService");
service.sendMessage("Привет, Spring!");
}
}


2. Определение бина с помощью аннотаций


Современный и популярный способ создания бинов в Spring — это использование аннотаций. Аннотации позволяют конфигурировать бины непосредственно в коде, избавляя от необходимости создания XML-файлов.
import org.springframework.stereotype.Component;

@Component
public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Отправка сообщения через Email: " + message);
}
}
Здесь мы используем аннотацию @Component, чтобы 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);

MessageService service = context.getBean(EmailService.class);
service.sendMessage("Привет, Spring с аннотациями!");
}
}


#Java #Training #Spring #Spring_Bean
3. Определение бина через Java-конфигурацию

Другой мощный способ — это использование конфигурационных классов. Аннотация
@Configuration позволяет заменить XML-файл Java-классом, в котором объявлены методы с аннотацией @Bean.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

@Bean
public MessageService emailService() {
return new EmailService();
}
}
Этот Java-класс полностью заменяет XML-конфигурацию.


Управление бинами в Spring

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


Внедрение зависимостей

Spring поддерживает несколько типов внедрения зависимостей:
Через конструктор — наиболее предпочтительный метод.
Через сеттеры — позволяет внедрять зависимости после создания объекта.


Пример внедрения зависимости через конструктор:
@Component
public class MessageProcessor {

private final MessageService messageService;

@Autowired
public MessageProcessor(MessageService messageService) {
this.messageService = messageService;
}

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


Пример внедрения зависимости через сеттер:
@Component
public class MessageProcessor {

private MessageService messageService;

@Autowired
public void setMessageService(MessageService messageService) {
this.messageService = messageService;
}

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


Скоупы бинов

Spring поддерживает следующие основные скоупы для бинов:
Singleton — по умолчанию каждый бин создается в одном экземпляре для всего приложения.
Prototype — новый экземпляр бина создается каждый раз при запросе.


Пример указания скоупа через аннотацию:
@Component
@Scope("prototype")
public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
System.out.println("Отправка сообщения через Email: " + message);
}
}


Lazy и Eager инициализация бинов

Spring предоставляет возможность управлять тем, когда именно создаются бины:
Eager инициализация — бины создаются сразу при старте контекста (по умолчанию).
Lazy инициализация — бины создаются только тогда, когда они впервые запрашиваются.


@Component
@Lazy
public class LazyService {
public LazyService() {
System.out.println("LazyService создан");
}
}
В данном случае бин LazyService не будет создан до тех пор, пока он не будет запрошен.


Преимущества управления бинами в Spring

Гибкость: Spring позволяет использовать различные подходы для создания и управления бинами, такие как аннотации, XML и Java-конфигурации.
Автоматизация: Контейнер Spring автоматически управляет жизненным циклом бинов, что облегчает разработку сложных приложений.
Модульность: Каждый бин может быть независимо настроен и протестирован.


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

public class Task221024_1 {
public static void main(String[] args) {
System.out.println(Status.PENDING.getDescription());
System.out.println(Status.APPROVED.ordinal());
}
}

enum Status {
PENDING("Waiting for approval"),
APPROVED("Approved by admin"),
REJECTED("Request denied");

private String description;

Status(String description) {
this.description = description;
}

public String getDescription() {
return description;
}
}


#Tasks
А потом разработчик виноват😂

https://t.me/Java_for_beginner_dev

#Mems
Жизненный цикл бинов

Одной из ключевых особенностей Spring является управление жизненным циклом бинов. Контейнер Spring полностью контролирует создание, настройку и уничтожение бинов.

Этапы жизненного цикла бина в Spring

Жизненный цикл бина включает в себя несколько стадий:
Создание бина: контейнер IoC создает объект и управляет его инициализацией.
Внедрение зависимостей: если у бина есть зависимости, они автоматически разрешаются и внедряются Spring.
Пост-инициализация: дополнительные операции, которые можно выполнить после создания объекта.
Использование бина: бин может быть использован в приложении.
Уничтожение бина: при завершении работы приложения Spring уничтожает бины.


Жизненный цикл бина на примере

Создадим пример с бином, который отправляет сообщения, и реализуем этапы его жизненного цикла.


Пример класса с методами инициализации и уничтожения:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;

@Component
public class MessageService {

public MessageService() {
System.out.println("Создание бина MessageService");
}

@PostConstruct
public void init() {
System.out.println("Инициализация бина MessageService");
}

public void sendMessage(String message) {
System.out.println("Отправка сообщения: " + message);
}

@PreDestroy
public void destroy() {
System.out.println("Уничтожение бина MessageService");
}
}


Объяснение этапов:
Конструктор: при создании бина вызывается конструктор класса. Здесь мы видим, что при создании бина выводится сообщение "Создание бина MessageService".
Аннотация
@PostConstruct: после создания бина и внедрения всех зависимостей вызывается метод, помеченный этой аннотацией. В нашем примере это метод init(), который выводит сообщение "Инициализация бина MessageService".
Методы бина: после инициализации бин может быть использован для выполнения своих задач. В данном случае это метод sendMessage(), который выводит сообщение.
Аннотация
@PreDestroy: перед уничтожением бина вызывается метод, помеченный аннотацией @PreDestroy. В нашем примере это метод destroy(), который выводит сообщение "Уничтожение бина MessageService".

Использование интерфейсов для управления жизненным циклом

Spring также предоставляет интерфейсы для более детального управления жизненным циклом бинов:
InitializingBean: интерфейс с методом afterPropertiesSet(), который вызывается после внедрения зависимостей.
DisposableBean: интерфейс с методом destroy(), который вызывается при завершении работы приложения для уничтожения бина.


Пример реализации этих интерфейсов:
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class CustomService implements InitializingBean, DisposableBean {

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Инициализация бина CustomService через afterPropertiesSet");
}

@Override
public void destroy() throws Exception {
System.out.println("Уничтожение бина CustomService через destroy");
}
}


#Java #Training #Spring #Spring_Bean_LifeCicle
Методы инициализации и уничтожения через XML

Если вы используете XML-конфигурацию, вы можете указать методы инициализации и уничтожения прямо в конфигурационном файле:
<bean id="messageService" class="com.example.MessageService" 
init-method="init" destroy-method="destroy"/>
Здесь init-method и destroy-method указывают на методы, которые будут вызваны при инициализации и уничтожении бина соответственно.


Singleton и Prototype: Различия в жизненном цикле

Spring поддерживает несколько типов скоупов для бинов, наиболее популярные из которых — это singleton и prototype. Жизненный цикл бинов в этих скоупах отличается:
Singleton: бин создается один раз при старте контейнера и существует на протяжении всего времени работы приложения.
Prototype: новый экземпляр бина создается каждый раз, когда он запрашивается.


@Component
@Scope("prototype")
public class PrototypeBean {

public PrototypeBean() {
System.out.println("Создан новый экземпляр PrototypeBean");
}
}
При каждом запросе PrototypeBean будет создаваться новый объект.


Способы ручного управления жизненным циклом бинов

Иногда возникает необходимость вручную управлять жизненным циклом бинов, например, для освобождения ресурсов. Это можно сделать, используя метод close() у контекста:
AnnotationConfigApplicationContext context = 
new AnnotationConfigApplicationContext(AppConfig.class);

MessageService service = context.getBean(MessageService.class);
service.sendMessage("Привет, Spring!");

context.close();
Метод close() завершает работу контекста и вызывает методы уничтожения всех бинов.

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

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

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

public class Task221024_2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig221024.class);
MyBean myBean = context.getBean(MyBean.class);
myBean.doSomething();
context.close();
}
}

@Component
class MyBean implements InitializingBean, DisposableBean {

public MyBean() {
System.out.println("Constructor called");
}

@Override
public void afterPropertiesSet() {
System.out.println("afterPropertiesSet (init) called");
}

public void doSomething() {
System.out.println("Doing something");
}

@Override
public void destroy() {
System.out.println("destroy (cleanup) called");
}
}

@Configuration
@ComponentScan()
class AppConfig221024 {}


#TasksSpring
Подробный разбор решения задачи Task221024_2

Задача состоит из трех ключевых компонентов:

Класс MyBean — бин, который Spring будет управлять.
Конфигурационный класс AppConfig221024 — используется для указания, что Spring должен искать компоненты (бины) в определенном пакете с помощью аннотации
@ComponentScan.
Метод main() — точка входа в программу, где создается Spring-контекст и управляется жизненным циклом бина.


Ключевые элементы задачи

Создание бина — через вызов конструктора.
Инициализация бина — через вызов метода afterPropertiesSet() из интерфейса InitializingBean.
Использование бина — через вызов метода doSomething() для выполнения основной логики.
Очистка и уничтожение бина — через вызов метода destroy() из интерфейса DisposableBean.


Детали работы программы

Класс MyBean:
Этот класс представляет собой обычный Spring-бин. Он отмечен аннотацией @Component, что позволяет Spring автоматически обнаруживать его при сканировании пакета.

Бин реализует два интерфейса:
InitializingBean (с методом afterPropertiesSet()), который вызывается после того, как Spring завершит инъекцию зависимостей и бин будет готов к использованию.
DisposableBean (с методом destroy()), который вызывается перед уничтожением бина, когда Spring-контекст закрывается.


Метод main():
Здесь создается Spring-контекст с использованием AnnotationConfigApplicationContext и передается класс конфигурации AppConfig221024.
После этого Spring автоматически находит бин MyBean, создает его экземпляр, инициализирует его, и предоставляет для использования в коде.
После завершения работы программы вызывается метод context.close(), который закрывает Spring-контекст, что вызывает метод очистки у бина.


Ход выполнения программы

Spring создает бин MyBean:
Когда Spring начинает работу, он находит класс MyBean, отмеченный аннотацией @Component, и создает его экземпляр.
При этом вызывается конструктор класса MyBean, который выводит в консоль строку "Constructor called".


Инициализация бина:
После создания экземпляра и завершения инъекции всех зависимостей, Spring вызывает метод afterPropertiesSet() из интерфейса InitializingBean.
Этот метод используется для выполнения задач, которые должны быть выполнены сразу после создания объекта (например, инициализация сложных зависимостей, проверка состояний и т.д.).
В нашем случае, этот метод выводит строку "afterPropertiesSet (init) called" в консоль.


Основная логика программы:
В методе main() вызывается метод doSomething() у бина. Этот метод выполняет некоторую основную логику программы и выводит строку "Doing something".

Закрытие контекста и разрушение бина:
Когда выполнение программы заканчивается, вызывается метод context.close(), который закрывает Spring-контекст. Это действие инициирует вызов метода destroy() из интерфейса DisposableBean, где бин должен освободить ресурсы или выполнить задачи очистки перед уничтожением.
В данном случае, метод destroy() выводит строку "destroy (cleanup) called".


Лог выполнения программы:
Сначала выводится "Constructor called" — бин создается, и вызывается его конструктор.
Затем выводится "afterPropertiesSet (init) called" — это метод инициализации, который вызывается после создания бина.
Далее выводится "Doing something" — это основная логика программы, выполняемая в методе doSomething().
Наконец, выводится "destroy (cleanup) called" — это метод разрушения бина, который вызывается при закрытии Spring-контекста.


#Solution_TasksSpring
Синглтон и Прототипы в Spring

Когда говорят о скоупах (областях видимости) бинов в Spring, обычно рассматривают два наиболее часто используемых типа — это Singleton (синглтон) и Prototype (прототип). Они определяют, как и когда создаются экземпляры объектов (бинов) и как управляется их временем жизни в приложении. Понимание различий между этими скоупами помогает разработчикам эффективно управлять ресурсами и объектами в приложении.

Что такое скоуп (Scope) бина?

Скоуп бина определяет жизненный цикл и количество экземпляров бина в контейнере Spring. Он регулирует, сколько объектов будет создано и как долго эти объекты будут существовать. Spring поддерживает несколько различных скоупов, но на практике наиболее популярными являются:
Singleton — бин создается один раз и существует на протяжении всего времени работы контейнера Spring.
Prototype — новый экземпляр бина создается каждый раз при запросе.


Singleton Scope (Синглтон)

Синглтон — это скоуп по умолчанию в Spring. Когда бин имеет скоуп синглтона, контейнер создает только один его экземпляр для всего приложения. Этот бин будет использоваться повторно при каждом обращении к нему в течение времени работы приложения.


Пример использования синглтона

Создадим класс, который представляет собой сервис для отправки сообщений:
import org.springframework.stereotype.Component;

@Component
public class MessageService {
public MessageService() {
System.out.println("Создан объект MessageService");
}

public void sendMessage(String message) {
System.out.println("Отправка сообщения: " + message);
}
}


Теперь создадим приложение, которое использует этот бин несколько раз:

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);

// Получаем бин MessageService дважды
MessageService service1 = context.getBean(MessageService.class);
service1.sendMessage("Привет, Spring!");

MessageService service2 = context.getBean(MessageService.class);
service2.sendMessage("Второе сообщение");

// Проверим, что оба объекта одинаковы
System.out.println(service1 == service2); // true
}
}
В данном случае Spring создает только один экземпляр MessageService, и каждый раз при запросе через context.getBean() возвращается один и тот же объект. Сообщение в консоли "Создан объект MessageService" будет выведено только один раз.


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

Синглтон хорош для использования в ситуациях, когда объект должен быть уникален для всего приложения и его состояние не должно изменяться между различными вызовами.

Примеры:
Сервисы, которые обеспечивают кэширование данных.
Сервисы для доступа к базе данных, где создаётся пул соединений.
Управляющие объекты, которые контролируют общий процесс приложения.


#Java #Training #Spring #Spring_Singleton