diff --git a/2025-11/spring-07-advanced-config/.gitignore b/2025-11/spring-07-advanced-config/.gitignore
new file mode 100644
index 00000000..e62c33c2
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/.gitignore
@@ -0,0 +1,4 @@
+.idea/
+*.iml
+
+target/
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/.gitignore b/2025-11/spring-07-advanced-config/application-events-demo/.gitignore
new file mode 100644
index 00000000..789ddc9e
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/.gitignore
@@ -0,0 +1,32 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+#other
+*.bat
+*/.idea
+*.iml
+*/target
+
+.idea
+*.iml
+target
\ No newline at end of file
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/README.md b/2025-11/spring-07-advanced-config/application-events-demo/README.md
new file mode 100644
index 00000000..63e68847
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/README.md
@@ -0,0 +1,2 @@
+# application-events-demo
+Пример работы с событиями
\ No newline at end of file
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/pom.xml b/2025-11/spring-07-advanced-config/application-events-demo/pom.xml
new file mode 100644
index 00000000..cf20ba7b
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/pom.xml
@@ -0,0 +1,63 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.5.3
+
+
+
+ ru.otus.example
+ application-events-demo
+ 0.0.1-SNAPSHOT
+ application-events-demo
+ Application events demo
+
+
+ 17
+ 17
+ 17
+ 3.4.0
+ 2.0
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+ org.springframework.shell
+ spring-shell-starter
+ ${spring.shell.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/ApplicationEventsDemoApplication.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/ApplicationEventsDemoApplication.java
new file mode 100644
index 00000000..d53bb34e
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/ApplicationEventsDemoApplication.java
@@ -0,0 +1,15 @@
+package ru.otus.example.applicationeventsdemo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.shell.command.annotation.CommandScan;
+
+@CommandScan
+@SpringBootApplication
+public class ApplicationEventsDemoApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ApplicationEventsDemoApplication.class, args);
+ }
+
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/AbstractRespondent.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/AbstractRespondent.java
new file mode 100644
index 00000000..5f901659
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/AbstractRespondent.java
@@ -0,0 +1,11 @@
+package ru.otus.example.applicationeventsdemo.events;
+
+public class AbstractRespondent {
+ public void delay(long mills) {
+ try {
+ Thread.sleep(mills);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsConfig.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsConfig.java
new file mode 100644
index 00000000..a9525f31
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsConfig.java
@@ -0,0 +1,19 @@
+package ru.otus.example.applicationeventsdemo.events;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.ApplicationEventMulticaster;
+import org.springframework.context.event.SimpleApplicationEventMulticaster;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+
+//@Configuration
+public class EventsConfig {
+
+ // Имя бина важно
+ @Bean
+ public ApplicationEventMulticaster applicationEventMulticaster() {
+ SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
+ eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
+ return eventMulticaster;
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsPublisher.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsPublisher.java
new file mode 100644
index 00000000..2274570a
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/EventsPublisher.java
@@ -0,0 +1,5 @@
+package ru.otus.example.applicationeventsdemo.events;
+
+public interface EventsPublisher {
+ void publish();
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEvent.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEvent.java
new file mode 100644
index 00000000..22bab552
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEvent.java
@@ -0,0 +1,15 @@
+package ru.otus.example.applicationeventsdemo.events;
+
+import lombok.Getter;
+import org.springframework.context.ApplicationEvent;
+
+public class HalfAGlassOfWaterEvent extends ApplicationEvent {
+
+ @Getter
+ private final String payload;
+
+ public HalfAGlassOfWaterEvent(Object source) {
+ super(source);
+ payload = "Осталось половина стакана воды!!!";
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEventPublisher.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEventPublisher.java
new file mode 100644
index 00000000..a1186fcc
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/HalfAGlassOfWaterEventPublisher.java
@@ -0,0 +1,17 @@
+package ru.otus.example.applicationeventsdemo.events;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class HalfAGlassOfWaterEventPublisher implements EventsPublisher {
+
+ private final ApplicationEventPublisher publisher;
+
+ @Override
+ public void publish() {
+ publisher.publishEvent(new HalfAGlassOfWaterEvent(this));
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/NegativeRespondent.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/NegativeRespondent.java
new file mode 100644
index 00000000..ca573e3f
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/NegativeRespondent.java
@@ -0,0 +1,16 @@
+package ru.otus.example.applicationeventsdemo.events;
+
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NegativeRespondent extends AbstractRespondent implements ApplicationListener {
+
+ @Override
+ public void onApplicationEvent(HalfAGlassOfWaterEvent halfAGlassOfWaterEvent) {
+ delay(100);
+ System.out.println("Негативно настроенный слушатель");
+ System.out.println(String.format("- %s", halfAGlassOfWaterEvent.getPayload()));
+ System.out.println("- Какой ужас. Теперь он наполовину пуст!!!\n\n");
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/PositiveRespondent.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/PositiveRespondent.java
new file mode 100644
index 00000000..645890a8
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/events/PositiveRespondent.java
@@ -0,0 +1,16 @@
+package ru.otus.example.applicationeventsdemo.events;
+
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PositiveRespondent extends AbstractRespondent {
+
+ @EventListener
+ public void onApplicationEvent(HalfAGlassOfWaterEvent halfAGlassOfWaterEvent) {
+ delay(100);
+ System.out.println("Позитивно настроенный слушатель");
+ System.out.println(String.format("- %s", halfAGlassOfWaterEvent.getPayload()));
+ System.out.println("- Ничего. Главное, что он наполовину полон!!!\n\n");
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/security/InMemoryLoginContext.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/security/InMemoryLoginContext.java
new file mode 100644
index 00000000..3a2586e4
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/security/InMemoryLoginContext.java
@@ -0,0 +1,20 @@
+package ru.otus.example.applicationeventsdemo.security;
+
+import org.springframework.stereotype.Component;
+
+import static java.util.Objects.nonNull;
+
+@Component
+public class InMemoryLoginContext implements LoginContext {
+ private String userName;
+
+ @Override
+ public void login(String userName) {
+ this.userName = userName;
+ }
+
+ @Override
+ public boolean isUserLoggedIn() {
+ return nonNull(userName);
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/security/LoginContext.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/security/LoginContext.java
new file mode 100644
index 00000000..a48e6401
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/security/LoginContext.java
@@ -0,0 +1,6 @@
+package ru.otus.example.applicationeventsdemo.security;
+
+public interface LoginContext {
+ void login(String userName);
+ boolean isUserLoggedIn();
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommands.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommands.java
new file mode 100644
index 00000000..c4da29dd
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommands.java
@@ -0,0 +1,38 @@
+package ru.otus.example.applicationeventsdemo.shell;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.shell.Availability;
+import org.springframework.shell.standard.ShellComponent;
+import org.springframework.shell.standard.ShellMethod;
+import org.springframework.shell.standard.ShellMethodAvailability;
+import org.springframework.shell.standard.ShellOption;
+import ru.otus.example.applicationeventsdemo.events.EventsPublisher;
+import ru.otus.example.applicationeventsdemo.security.LoginContext;
+
+@ShellComponent(value = "Application Events Commands")
+@RequiredArgsConstructor
+public class ApplicationEventsCommands {
+
+ private final EventsPublisher eventsPublisher;
+
+ private final LoginContext loginContext;
+
+ @ShellMethod(value = "Login command", key = {"l", "login"})
+ public String login(@ShellOption(defaultValue = "AnyUser") String userName) {
+ loginContext.login(userName);
+ return String.format("Добро пожаловать: %s", userName);
+ }
+
+ @ShellMethod(value = "Publish event command", key = {"p", "pub", "publish"})
+ @ShellMethodAvailability(value = "isPublishEventCommandAvailable")
+ public String publishEvent() {
+ eventsPublisher.publish();
+ return "Событие опубликовано";
+ }
+
+ private Availability isPublishEventCommandAvailable() {
+ return loginContext.isUserLoggedIn()
+ ? Availability.available()
+ : Availability.unavailable("Сначала залогиньтесь");
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shellnew/ApplicationEventsCommandsNewWay.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shellnew/ApplicationEventsCommandsNewWay.java
new file mode 100644
index 00000000..c3d9c774
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shellnew/ApplicationEventsCommandsNewWay.java
@@ -0,0 +1,30 @@
+package ru.otus.example.applicationeventsdemo.shellnew;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.shell.command.annotation.Command;
+import org.springframework.shell.command.annotation.CommandAvailability;
+import org.springframework.shell.command.annotation.Option;
+import ru.otus.example.applicationeventsdemo.events.EventsPublisher;
+import ru.otus.example.applicationeventsdemo.security.LoginContext;
+
+@Command(group = "Application Events Commands New Way")
+@RequiredArgsConstructor
+public class ApplicationEventsCommandsNewWay {
+
+ private final EventsPublisher eventsPublisher;
+
+ private final LoginContext loginContext;
+
+ @Command(description = "Login command new way", command = "login2", alias = "l2")
+ public String login(@Option(defaultValue = "AnyUser") String userName) {
+ loginContext.login(userName);
+ return String.format("Добро пожаловать: %s", userName);
+ }
+
+ @Command(description = "Publish event command new way", command = "publish2", alias = {"p2", "pub2"})
+ @CommandAvailability(provider = "publishEventCommandAvailabilityProvider")
+ public String publishEvent() {
+ eventsPublisher.publish();
+ return "Событие опубликовано";
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shellnew/ShellConfig.java b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shellnew/ShellConfig.java
new file mode 100644
index 00000000..7df16eee
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/java/ru/otus/example/applicationeventsdemo/shellnew/ShellConfig.java
@@ -0,0 +1,18 @@
+package ru.otus.example.applicationeventsdemo.shellnew;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.shell.Availability;
+import org.springframework.shell.AvailabilityProvider;
+import ru.otus.example.applicationeventsdemo.security.LoginContext;
+
+@Configuration
+public class ShellConfig {
+
+ @Bean
+ public AvailabilityProvider publishEventCommandAvailabilityProvider(LoginContext loginContext) {
+ return () -> loginContext.isUserLoggedIn()
+ ? Availability.available()
+ : Availability.unavailable("Сначала залогиньтесь");
+ }
+}
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/main/resources/application.yml b/2025-11/spring-07-advanced-config/application-events-demo/src/main/resources/application.yml
new file mode 100644
index 00000000..013ba76e
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/main/resources/application.yml
@@ -0,0 +1,10 @@
+logging:
+ level:
+ root: ERROR
+
+spring:
+ shell:
+ interactive:
+ enabled: true
+ main:
+ allow-circular-references: true
\ No newline at end of file
diff --git a/2025-11/spring-07-advanced-config/application-events-demo/src/test/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommandsTest.java b/2025-11/spring-07-advanced-config/application-events-demo/src/test/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommandsTest.java
new file mode 100644
index 00000000..97aa9351
--- /dev/null
+++ b/2025-11/spring-07-advanced-config/application-events-demo/src/test/java/ru/otus/example/applicationeventsdemo/shell/ApplicationEventsCommandsTest.java
@@ -0,0 +1,101 @@
+package ru.otus.example.applicationeventsdemo.shell;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.shell.CommandNotCurrentlyAvailable;
+import org.springframework.shell.InputProvider;
+import org.springframework.shell.ResultHandlerService;
+import org.springframework.shell.Shell;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
+import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
+import ru.otus.example.applicationeventsdemo.events.EventsPublisher;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.mockito.Mockito.*;
+
+@DisplayName("Тест команд shell ")
+@SpringBootTest
+class ApplicationEventsCommandsTest {
+
+ private static final String GREETING_PATTERN = "Добро пожаловать: %s";
+ private static final String DEFAULT_LOGIN = "AnyUser";
+ private static final String CUSTOM_LOGIN = "Вася";
+ private static final String COMMAND_LOGIN = "login";
+ private static final String COMMAND_LOGIN_SHORT = "l";
+ private static final String COMMAND_PUBLISH = "publish";
+ private static final String COMMAND_PUBLISH_EXPECTED_RESULT = "Событие опубликовано";
+ private static final String COMMAND_LOGIN_PATTERN = "%s %s";
+
+ private InputProvider inputProvider;
+
+ private ArgumentCaptor