Spring Boot. Чтобы Jackson создавал объекты из JSON явно и предсказуемо, можно использовать аннотацию
Каждый параметр явно биндится.
Определяем конструктор с
👉 Java Portal
@JsonCreatorКаждый параметр явно биндится.
Определяем конструктор с
@JsonCreator:class User {
public final String username;
public final int age;
@JsonCreator
public User(
@JsonProperty("username") String username,
@JsonProperty("age") int age
) {
this.username = username;
this.age = age;
}
}Please open Telegram to view this post
VIEW IN TELEGRAM
❤11
Многопоточность позволяет писать так, чтобы несколько задач выполнялись параллельно внутри одного приложения.
Чтобы использовать многопоточность (то есть писать многопоточный код), нужен класс java.lang.Thread.
Стадии жизненного цикла потока:
• New: Новый поток начинает жизнь в состоянии new. Он остается там, пока программа не запустит поток.
• Runnable: После запуска новый поток становится runnable. В этом состоянии считается, что поток выполняет свою работу.
• Waiting: Иногда поток переходит в waiting, когда ему нужно дождаться выполнения задачи другим потоком.
• Timed Waiting: Поток из runnable может перейти в timed waiting на определенный промежуток времени. После истечения этого времени он снова возвращается в runnable.
• Terminated: Поток попадает в terminated после завершения задачи или принудительного завершения.
Приоритеты потоков:
Каждый Java-поток имеет приоритет, который помогает ОС решать порядок планирования потоков.
• MIN_PRIORITY (константа 1)
• NORM_PRIORITY (константа 5) (приоритет по умолчанию)
• MAX_PRIORITY (константа 10)
Базовые способы создать поток в Java:
• Реализовать интерфейс Runnable
• Наследоваться от Thread
Методы потоков:
• public void start()
Запускает поток в отдельном пути выполнения и затем вызывает run() у этого объекта Thread.
• public void run()
Если объект Thread был создан с отдельным Runnable, то run() будет вызван на этом Runnable.
• public final void setPriority(int priority)
Устанавливает приоритет потока. Возможные значения от 1 до 10.
• public void interrupt()
Прерывает поток, заставляя продолжить выполнение, даже если он был заблокирован.
• public final boolean isAlive()
Возвращает true, если поток "жив", то есть после старта и до завершения.
Это были базовые вещи. Пост длинный, но надеюсь, что что-то новое унес с собой.
👉 Java Portal
Чтобы использовать многопоточность (то есть писать многопоточный код), нужен класс java.lang.Thread.
Стадии жизненного цикла потока:
• New: Новый поток начинает жизнь в состоянии new. Он остается там, пока программа не запустит поток.
• Runnable: После запуска новый поток становится runnable. В этом состоянии считается, что поток выполняет свою работу.
• Waiting: Иногда поток переходит в waiting, когда ему нужно дождаться выполнения задачи другим потоком.
• Timed Waiting: Поток из runnable может перейти в timed waiting на определенный промежуток времени. После истечения этого времени он снова возвращается в runnable.
• Terminated: Поток попадает в terminated после завершения задачи или принудительного завершения.
Приоритеты потоков:
Каждый Java-поток имеет приоритет, который помогает ОС решать порядок планирования потоков.
• MIN_PRIORITY (константа 1)
• NORM_PRIORITY (константа 5) (приоритет по умолчанию)
• MAX_PRIORITY (константа 10)
Базовые способы создать поток в Java:
• Реализовать интерфейс Runnable
• Наследоваться от Thread
Методы потоков:
• public void start()
Запускает поток в отдельном пути выполнения и затем вызывает run() у этого объекта Thread.
• public void run()
Если объект Thread был создан с отдельным Runnable, то run() будет вызван на этом Runnable.
• public final void setPriority(int priority)
Устанавливает приоритет потока. Возможные значения от 1 до 10.
• public void interrupt()
Прерывает поток, заставляя продолжить выполнение, даже если он был заблокирован.
• public final boolean isAlive()
Возвращает true, если поток "жив", то есть после старта и до завершения.
Это были базовые вещи. Пост длинный, но надеюсь, что что-то новое унес с собой.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤2
Spring Boot. С помощью
👉 Java Portal
@DataJpaTest можно прогонять JPA репозитории изолированно.@DataJpaTest поднимает только JPA слой без всего приложения, использует in-memory базу H2 и откатывает транзакции после каждого теста.Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍1
Поток обработки запроса в Spring Boot
Вопрос на собеседовании: как проходит HTTP-запрос внутри Spring Boot приложения?
Звучит просто, но на практике сложно правильно восстановить порядок и технические детали.
• клиент отправляет HTTP-запрос
• запрос сначала попадает в DispatcherServlet (Front Controller)
• DispatcherServlet через HandlerMapping ищет нужный контроллер
• контроллер занимается маппингом запроса и валидацией
• бизнес-логика выполняется в сервисном слое
• работа с базой идет через репозиторий (JPA)
• ответ идет обратно по тому же пути и сериализуется в JSON через Jackson
👉 Java Portal
Вопрос на собеседовании: как проходит HTTP-запрос внутри Spring Boot приложения?
Звучит просто, но на практике сложно правильно восстановить порядок и технические детали.
• клиент отправляет HTTP-запрос
• запрос сначала попадает в DispatcherServlet (Front Controller)
• DispatcherServlet через HandlerMapping ищет нужный контроллер
• контроллер занимается маппингом запроса и валидацией
• бизнес-логика выполняется в сервисном слое
• работа с базой идет через репозиторий (JPA)
• ответ идет обратно по тому же пути и сериализуется в JSON через Jackson
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍2
Spring Boot: чтобы прогнать SQL-скрипты до или после выполнения тестового метода, можно использовать аннотацию
👉 Java Portal
@Sql.@SpringBootTest
@Sql("/test/products.sql")
class ProductServiceTest {
@Autowired
ProductService productService;
@Test
void findProductByName() {
Product product = productService.findByName("product1");
assertThat(product).isNotNull();
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Что такое Throwable
Throwable в Java — это базовый класс для всех «бросаемых» аномалий. Он даёт общий функционал для работы с исключениями: стек, причину, вложенные ошибки и т. д.
С точки зрения модели: невосстанавливаемые критические состояния представлены через Error, а ошибки уровня приложения — через Exception.
То есть всё, что можно бросать (throw), наследуется от Throwable.
Коротко:
Error: обычно невосстанавливаемая и не предполагается обработка на уровне приложения
Exception: приложение может предусматривать и обрабатывать
checked: обработка контролируется компилятором
unchecked: обработка не принудительная
Иерархия выглядит примерно так:
Разница между Error и Exception
Error — «фатальный и невосстанавливаемый сбой»
Exception — «аномалия, которую приложение может ожидать и обрабатывать»
Мини сравнение:
источник: Error приходит от JVM и рантайма, Exception рождается на уровне приложения
восстановление: у Error почти нулевые шансы, у Exception всё зависит от ситуации
catch: Error обычно не ловят, Exception ловят и обрабатывают
примеры: для Error — OOM, StackOverflow; для Exception — неверный ввод или I/O ошибки
Что такое Error
Это фатальные сбои JVM.
Не то, что будут фиксить в бизнес-логике.
Примеры: OutOfMemoryError, StackOverflowError, VirtualMachineError
Почему их не ловят?
предпосылки работы программы уже нарушены
даже если поймать — непонятно, что делать дальше
нормальная стратегия — дать процессу упасть
Что такое Exception
Это исключения, которые приложение может предусматривать и включать в контрольный поток.
checked: IOException, SQLException
unchecked: NullPointerException, IllegalArgumentException
Почему их обрабатывают?
Потому что они «возможны по контракту» — неверный ввод, I/O, бизнес-валидация и т. д.
Почему в GlobalExceptionHandler не ловят Throwable
Потому что обработка Throwable приводила бы к поглощению Error (фатальных ошибок), и приложение продолжило бы работать в «сломанных» условиях.
Подробности:
➡️ Поглощение Error
Если OutOfMemoryError превратить в обычный 500, то это попытка «делать вид, что всё ок», в то время как приложение фактически в предсмертном состоянии.
➡️ Ломается контрольный поток фреймворка
Например, в Spring разное поведение завязано на тип исключения. Throwable ломает эти правила.
➡️ Падает наблюдаемость
«Ловить всё» засоряет логи шумом и усложняет поиск корня проблемы.
Отсюда правило: в GlobalExceptionHandler ловят не Throwable, а Exception (или RuntimeException) как конечный уровень обработки в приложении.
👉 Java Portal
Throwable в Java — это базовый класс для всех «бросаемых» аномалий. Он даёт общий функционал для работы с исключениями: стек, причину, вложенные ошибки и т. д.
С точки зрения модели: невосстанавливаемые критические состояния представлены через Error, а ошибки уровня приложения — через Exception.
То есть всё, что можно бросать (throw), наследуется от Throwable.
Коротко:
Error: обычно невосстанавливаемая и не предполагается обработка на уровне приложения
Exception: приложение может предусматривать и обрабатывать
checked: обработка контролируется компилятором
unchecked: обработка не принудительная
Иерархия выглядит примерно так:
java.lang.Object
└─ java.lang.Throwable // всё, что можно throw-нуть
├─ java.lang.Error // системные критические сбои
│ ├─ OutOfMemoryError
│ ├─ StackOverflowError
│ ├─ VirtualMachineError
│ └─ ...
└─ java.lang.Exception // исключения уровня приложения
├─ RuntimeException // unchecked
│ ├─ NullPointerException
│ ├─ IllegalArgumentException
│ ├─ IndexOutOfBoundsException
│ └─ ...
└─ IOException, SQLException (checked)
Разница между Error и Exception
Error — «фатальный и невосстанавливаемый сбой»
Exception — «аномалия, которую приложение может ожидать и обрабатывать»
Мини сравнение:
источник: Error приходит от JVM и рантайма, Exception рождается на уровне приложения
восстановление: у Error почти нулевые шансы, у Exception всё зависит от ситуации
catch: Error обычно не ловят, Exception ловят и обрабатывают
примеры: для Error — OOM, StackOverflow; для Exception — неверный ввод или I/O ошибки
Что такое Error
Это фатальные сбои JVM.
Не то, что будут фиксить в бизнес-логике.
Примеры: OutOfMemoryError, StackOverflowError, VirtualMachineError
Почему их не ловят?
предпосылки работы программы уже нарушены
даже если поймать — непонятно, что делать дальше
нормальная стратегия — дать процессу упасть
Что такое Exception
Это исключения, которые приложение может предусматривать и включать в контрольный поток.
checked: IOException, SQLException
unchecked: NullPointerException, IllegalArgumentException
Почему их обрабатывают?
Потому что они «возможны по контракту» — неверный ввод, I/O, бизнес-валидация и т. д.
Почему в GlobalExceptionHandler не ловят Throwable
Потому что обработка Throwable приводила бы к поглощению Error (фатальных ошибок), и приложение продолжило бы работать в «сломанных» условиях.
Подробности:
Если OutOfMemoryError превратить в обычный 500, то это попытка «делать вид, что всё ок», в то время как приложение фактически в предсмертном состоянии.
Например, в Spring разное поведение завязано на тип исключения. Throwable ломает эти правила.
«Ловить всё» засоряет логи шумом и усложняет поиск корня проблемы.
Отсюда правило: в GlobalExceptionHandler ловят не Throwable, а Exception (или RuntimeException) как конечный уровень обработки в приложении.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Spring Boot: можно переопределять конфиги на рантайме без перепаковки приложения.
Spring Boot по умолчанию использует лаунчер JarLauncher, который позволяет переопределить дефолтную конфигурацию через параметр loader.path при запуске приложения.
Предположим, у вас есть Spring Boot приложение со следующими зависимостями:
С application.properties такого вида:
И простой контроллер:
Если собрать jar и запустить:
Открыв [https://localhost:8080](https://localhost:8080) вы получите:
Если теперь создать внешний файл application.properties в той же директории, где лежит jar:
И запустить приложение с параметром loader.path, указывающим на текущую директорию:
Перейдя в [https://localhost:8080](https://localhost:8080) будет:
👉 Java Portal
Spring Boot по умолчанию использует лаунчер JarLauncher, который позволяет переопределить дефолтную конфигурацию через параметр loader.path при запуске приложения.
Предположим, у вас есть Spring Boot приложение со следующими зависимостями:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
С application.properties такого вида:
demo.message=Hello from inside the JAR
И простой контроллер:
@RestController
public class HelloController {
@Value("${demo.message}")
private String message;
@GetMapping("/")
public String hello() {
return message;
}
}
Если собрать jar и запустить:
java -jar springboot-propertieslauncher-demo-0.0.1-SNAPSHOT.jar
Открыв [https://localhost:8080](https://localhost:8080) вы получите:
Hello from inside the JAR
Если теперь создать внешний файл application.properties в той же директории, где лежит jar:
demo.message=Hello from outside the JAR
И запустить приложение с параметром loader.path, указывающим на текущую директорию:
java -jar springboot-propertieslauncher-demo-0.0.1-SNAPSHOT.jar --loader.path=.
Перейдя в [https://localhost:8080](https://localhost:8080) будет:
Hello from outside the JAR
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6