А тем временем, вышел Kotlin 2.0!
Основные изменения включают стабилизацию нового компилятора Kotlin K2, улучшение работы с многоплатформенными проектами, поддержку новых плагинов и улучшения производительности компилятора. В новой версии также прокачали smart-cast, а также ускорили работу IDE.
Несколько странно выглядит smart-cast для операций decrement и increment, меняющих тип объекта 🤯
#Kotlin
🔗 https://kotlinlang.org/docs/whatsnew20.html
Подписывайтесь:
😌 @spring_aio
Основные изменения включают стабилизацию нового компилятора Kotlin K2, улучшение работы с многоплатформенными проектами, поддержку новых плагинов и улучшения производительности компилятора. В новой версии также прокачали smart-cast, а также ускорили работу IDE.
Несколько странно выглядит smart-cast для операций decrement и increment, меняющих тип объекта 🤯
interface Rho {
operator fun inc(): Sigma = TODO()
}
var unknownObject: Rho = TODO()
++unknownObject // после этого unknownObject: Sigma 🤪 но Kotlin знает об этом)
#Kotlin
🔗 https://kotlinlang.org/docs/whatsnew20.html
Подписывайтесь:
Please open Telegram to view this post
VIEW IN TELEGRAM
Kotlin Help
What's new in Kotlin 2.0.0 | Kotlin
👍6❤5👏2
This media is not supported in your browser
VIEW IN TELEGRAM
Когда меня просят стартануть проект не на Spring Boot 😂
😁13🔥3🤣3❤1👍1
Иногда полезно освежить в памяти базовые принципы фреймворка. В Spring Framework центральное место занимает Bean. В своем видео Джош Лонг рассказывает об истории Bean и его жизненном цикле.
#SpringTips #SpringBoot
📱 https://www.youtube.com/watch?v=Z5hxolai4Tk
Подписывайтесь:
😌 @spring_aio
#SpringTips #SpringBoot
Подписывайтесь:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3👏2
Hibernate — очень мощный и функциональный ORM (Object-Relational Mapping) фреймворк. Он связывает базы данных с помощью объектно-ориентированных языков программирования. Однако многие, начиная с ним работать, натыкаются на проблемы производительности или отсутствия нужной функциональности. Многие из этих проблем появляются просто из-за того, что разработчики не умеют его «готовить».
🔗 https://habr.com/ru/companies/magnit/articles/814573/
Подписывайтесь:
😌 @spring_aio
🔗 https://habr.com/ru/companies/magnit/articles/814573/
Подписывайтесь:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥4👌2
Классная новость для всех Spring Boot разработчиков! Spring Academy дает бесплатный доступ ко всем своим обучающим материалам. 9 курсов и 12 гайдов по Spring Boot.
P.S. Есть сложности в регистрации из РФ.
🔗 https://spring.academy/
Подписывайтесь:
😌 @spring_aio
P.S. Есть сложности в регистрации из РФ.
🔗 https://spring.academy/
Подписывайтесь:
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👏3🤩2👍1
Контейнеризовать Spring Boot приложение можно так:
FROM gradle:8.5.0-jdk21
WORKDIR /
COPY / .
RUN ./gradlew installDist
CMD ./build/install/app/bin/app
И так:
FROM bellsoft/liberica-openjdk-alpine:21 AS builder
WORKDIR /application
COPY . .
RUN --mount=type=cache,target=/root/.gradle chmod +x gradlew && ./gradlew clean build -x test
FROM bellsoft/liberica-openjre-alpine:21 AS layers
WORKDIR /application
COPY --from=builder /application/build/libs/*.jar app.jar
RUN java -Djarmode=layertools -jar app.jar extract
FROM bellsoft/liberica-openjre-alpine:21
VOLUME /tmp
RUN adduser -S spring-user
USER spring-user
COPY --from=layers /application/dependencies/ ./
COPY --from=layers /application/spring-boot-loader/ ./
COPY --from=layers /application/snapshot-dependencies/ ./
COPY --from=layers /application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
Второй вариант с одной стороны намного сложнее реализовать, но с другой стороны он даёт множество преимуществ, среди которых можно отметить:
🔗 Подробнее о том, как написать идеальный Dockerfile тут: https://spring.io/guides/topicals/spring-boot-docker
Подписывайтесь:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤4🔥4
Spring Стартер Недели
Как сделать CRUD за 5 минут? Создаем модель данных, репозиторий, контроллер с 5-8 методами и, возможно, несколько dto. Если печатать со скоростью 600 символов в минуту, то можно успеть 🙈
Или берем Spring Data Rest, и получаем круды для своих репозиториев из коробки. И не только круды. Можно выставить наружу любой метод доступа к данным, прикрутить пагинацию и сортировку.
Однако, быстрый старт в начале может обернуться болью в процессе кастомизации или добавлении сложной (и не очень) логики. Тем не менее, выглядит как вполне себе хорошее решение для небольших REST сервисов, почти что Low Code 🙃.
Больше информации о данном стартере можно получить из доклада Рустама Курамшина на JPoint 2023.
📱 https://www.youtube.com/watch?v=roaGUHaWPxw
🔗 https://spring.io/projects/spring-data-rest
#SpringStarter #SpringBoot
Подписывайтесь:
😌 @spring_aio
Как сделать CRUD за 5 минут? Создаем модель данных, репозиторий, контроллер с 5-8 методами и, возможно, несколько dto. Если печатать со скоростью 600 символов в минуту, то можно успеть 🙈
Или берем Spring Data Rest, и получаем круды для своих репозиториев из коробки. И не только круды. Можно выставить наружу любой метод доступа к данным, прикрутить пагинацию и сортировку.
Однако, быстрый старт в начале может обернуться болью в процессе кастомизации или добавлении сложной (и не очень) логики. Тем не менее, выглядит как вполне себе хорошее решение для небольших REST сервисов, почти что Low Code 🙃.
Больше информации о данном стартере можно получить из доклада Рустама Курамшина на JPoint 2023.
🔗 https://spring.io/projects/spring-data-rest
#SpringStarter #SpringBoot
Подписывайтесь:
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤3🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
Не то чтобы, нас сильно интересовал Python, но анимация очень интересная.
Жизненный цикл кода от IDE до рабочей программы.
Жизненный цикл кода от IDE до рабочей программы.
👍8🔥4👌3
В Kotlin 2.1 анонсировали новую интересную функцию под названием "when guards", которая расширяет возможности конструкции when. Guard'ы позволяют добавлять дополнительные проверки с помощью ключевого слова if.
Что интересно, это, кажется, первая фича языка, которую Kotlin взял из Java.
Какой вариант вам кажется более предпочтительным?
👍 - Kotlin, ❤️ - Java
fun printAnimalInfo(animal: Animal) {
when (animal) {
is Animal.Dog if animal.isFriendly -> {
println("This is a friendly dog named ${animal.name}.")
}
is Animal.Dog -> {
println("This is a dog named ${animal.name}.")
}
is Animal.Cat if animal.isLazy -> {
println("This is a lazy cat named ${animal.name}.")
}
is Animal.Cat -> {
println("This is a cat named ${animal.name}.")
}
}
}
sealed class Animal {
class Dog(val name: String, val isFriendly: Boolean) : Animal()
class Cat(val name: String, val isLazy: Boolean) : Animal()
}
Что интересно, это, кажется, первая фича языка, которую Kotlin взял из Java.
record Point(int x, int y) {
}
class Cartesian {
static void printQuadrant(Point p) {
switch (p) {
case Point(var x, var y) when x > 0 && y > 0 -> {
System.out.println("first");
}
default ->
System.out.println("other");
}
}
}
Какой вариант вам кажется более предпочтительным?
👍 - Kotlin, ❤️ - Java
❤18👍10
🕐 Тонкое управление Scheduled задачами в Spring
Какими способами можно настроить время и условие запуска Scheduled задач в Spring?
Первый способ - через
Но в таком варианте, мы управляем только условием запуска, но не можем настроить переодичность.
Другой вариант, это объявление cron expression в пропертях:
Но как тогда в таком случае отключить джобу? В качестве cron expression можно использовать дефис(-), что означает, что джобу запускать не нужно вовсе. И тогда мы обходимся без явного перечисления профилей в
Такой подход особо полезен при использовании spring-cloud-config, тогда нет необходимости делать передеплой приложения, чтобы выключить, или донастроить джобу. Нужно только не забыть повесить
#SpringBoot #SpringTips
Какими способами можно настроить время и условие запуска Scheduled задач в Spring?
Первый способ - через
@Profile
над сервисом, в котором объявлена задача, чтобы указать профили, в которых она должна (или не должна) запускаться.
java
@Profile("test,!prod")
class Teapot {
@Scheduled(cron = "0 15 10 15 * ?")
void makeTea() {
log.info("I'am a teapot.");
}
}
Но в таком варианте, мы управляем только условием запуска, но не можем настроить переодичность.
Другой вариант, это объявление cron expression в пропертях:
#application-test.properties
teapot.make_tea.cron=0 15 10 15 * ?
@Scheduled(cron = "${teapot.make_tea.cron}")
void makeTea() {
log.info("I'am a teapot.");
}
Но как тогда в таком случае отключить джобу? В качестве cron expression можно использовать дефис(-), что означает, что джобу запускать не нужно вовсе. И тогда мы обходимся без явного перечисления профилей в
@Profile
.
#application-prod.properties
teapot.make_tea.cron=-
Такой подход особо полезен при использовании spring-cloud-config, тогда нет необходимости делать передеплой приложения, чтобы выключить, или донастроить джобу. Нужно только не забыть повесить
@RefreshScope
на класс.#SpringBoot #SpringTips
👍10👌5🔥3
🎉 Встречайте нашу дебютную статью на Habr!
👩💻 Блеск и нищета нового Scrolling API в Spring Data
В статье мы разобрали новое Scrolling API, которое предназначено для эффективной пагинации. В частности, Scrolling API приносит KeySet пагинацию в Spring Data, которая в теории может быть сильно быстрее стандратной и всем известной offset пагинации.
Однако, в процессе исследования выяснилось, что с PostgreSQL новое API работает не совсем так, как ожидается. А ведь это одна из самых популярных СУБД в мире!
Заинтриговали? Переходите по ссылке, оставляйте комментарии, и, конечно, ждем ваших лайков)
🔗 https://habr.com/ru/companies/spring_aio/articles/819193/
#SpringBoot #SpringData
Подписывайтесь:
😌 @spring_aio
В статье мы разобрали новое Scrolling API, которое предназначено для эффективной пагинации. В частности, Scrolling API приносит KeySet пагинацию в Spring Data, которая в теории может быть сильно быстрее стандратной и всем известной offset пагинации.
Однако, в процессе исследования выяснилось, что с PostgreSQL новое API работает не совсем так, как ожидается. А ведь это одна из самых популярных СУБД в мире!
Заинтриговали? Переходите по ссылке, оставляйте комментарии, и, конечно, ждем ваших лайков)
🔗 https://habr.com/ru/companies/spring_aio/articles/819193/
#SpringBoot #SpringData
Подписывайтесь:
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥21👍5👏4
🌟 Статическая и динамическая конфигурация в Spring Boot: что выбрать?
В мире облачных сервисов правильная настройка конфигурации играет ключевую роль. В этой статье рассматриваются два подхода: статическая и динамическая конфигурация.
🔧 Статическая конфигурация удобна предсказуемостью и простотой развертывания. Пример на Spring Boot:
🔄 Динамическая конфигурация обеспечивает гибкость и адаптивность. Например, для изменения конфигураций во время выполнения приложения можно использовать Spring Cloud:
Spring Cloud предоставляет возможность создания config сервера, который может подгружать новые конфигурации из Git. Ознакомьтесь с полной статьей для более детального погружения и примеров кода!
📚 Читать далее
#SpringBoot #SpringCloud
В мире облачных сервисов правильная настройка конфигурации играет ключевую роль. В этой статье рассматриваются два подхода: статическая и динамическая конфигурация.
🔧 Статическая конфигурация удобна предсказуемостью и простотой развертывания. Пример на Spring Boot:
@Value("${myapp.staticValue}")
private String staticValue;
public void printStaticValue() {
System.out.println(staticValue);
}
🔄 Динамическая конфигурация обеспечивает гибкость и адаптивность. Например, для изменения конфигураций во время выполнения приложения можно использовать Spring Cloud:
@RefreshScope
@RestController
public class MessageRestController {
@Value("${message:Hello default}")
private String message;
@GetMapping("/message")
public String getMessage() {
return this.message;
}
}
Spring Cloud предоставляет возможность создания config сервера, который может подгружать новые конфигурации из Git. Ознакомьтесь с полной статьей для более детального погружения и примеров кода!
📚 Читать далее
#SpringBoot #SpringCloud
🔥11❤3👍2👏2
EqualsVerifier отмечает 15-летие 🥳
Переопределение методов equals() и hashCode() – непростая задача. Они должны соответствовать не только требованиям Java, но и используемому стеку технологий (например, JPA).
Библиотека EqualsVerifier помогает разработчикам проверить корректность переопределенных методов уже 15 лет.
Jan Ouwens, создатель библиотеки, делится своим опытом и планами в новой статье.
Узнайте, какие проблемы решались разработчиком по мере развития Java, что было популярно до GitHub, и какие планы у Jan на будущее: https://jqno.nl/post/2024/06/01/looking-back-on-15-years-of-equalsverifier/
Подписывайтесь:
😌 @spring_aio
Переопределение методов equals() и hashCode() – непростая задача. Они должны соответствовать не только требованиям Java, но и используемому стеку технологий (например, JPA).
Библиотека EqualsVerifier помогает разработчикам проверить корректность переопределенных методов уже 15 лет.
Jan Ouwens, создатель библиотеки, делится своим опытом и планами в новой статье.
Узнайте, какие проблемы решались разработчиком по мере развития Java, что было популярно до GitHub, и какие планы у Jan на будущее: https://jqno.nl/post/2024/06/01/looking-back-on-15-years-of-equalsverifier/
Подписывайтесь:
Please open Telegram to view this post
VIEW IN TELEGRAM
tr ouwens
Looking back on 15 years of EqualsVerifier
In which I take a trip down memory lane.
👍11🔥5❤3
На первый взгляд, выбор правильного Java-рантайма для вашего проекта на Spring Boot может показаться тривиальным. В конце концов, все популярные рантаймы основываются на коде OpenJDK и предлагают одинаковые программные интерфейсы.
Но не все рантаймы реализованы одинаково. В этой статье мы обсудим различные показатели, которые могут повлиять на ваше решение выбрать определенный дистрибутив Java для Spring Boot приложения.
🔗 https://habr.com/ru/companies/spring_aio/articles/819899/
#JVM #Java #SpringBoot
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7👏3🔥2
🐢 Неожиданное падение производительности при переходе на Spring Boot 3.3.0 👩💻
Hibernate подложил небольшую свинью, конвертируя JPQL в SQL. Внезапно, запрос поиска записей по списку id с передачей пустого списка деградирует в table full scan.
Однако, Hibernate пофиксил баг в течении 10 часов после поста в запрещенную в РФ соцсеть. Осталось дождаться новой версии Spring Boot, которая включит себе этот фикс.
🔗Подробнее читайте на Хабре
#SpringBoot #Hibernate #BreakingNews
Hibernate подложил небольшую свинью, конвертируя JPQL в SQL. Внезапно, запрос поиска записей по списку id с передачей пустого списка деградирует в table full scan.
Однако, Hibernate пофиксил баг в течении 10 часов после поста в запрещенную в РФ соцсеть. Осталось дождаться новой версии Spring Boot, которая включит себе этот фикс.
🔗Подробнее читайте на Хабре
#SpringBoot #Hibernate #BreakingNews
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯14😱5👍3🔥2😁2
Друзья, напоминаем, что у нас есть чат (@spring_aio_chat), в котором вы можете:
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍4🌚2
Неблокирующие сервисы вчера: WebFlux, Coroutines и Loom.
"Неблокирующие сервисы" сегодня: DockerHub, IntelliJ IDEA Ultimate, Slack и другие.
#программисты_шутят
"Неблокирующие сервисы" сегодня: DockerHub, IntelliJ IDEA Ultimate, Slack и другие.
#программисты_шутят
😁26✍3🔥2💩2👏1
Dynamic Projection в Spring Data JPA
Используя Spring Data, довольно часто могут возникать накладные расходы из-за получения из базы слишком большого количества полей. Чтобы решить эту проблему, мы можем объявлять методы с нативными запросами, DTO или проекциями для случаев, когда необходимо ограничить количество выбираемых полей. Но такой подход приводит к появлению множества очень похожих методов в репозитории. Например:
Чтобы решить эту проблему можно прибегнуть к использованию Dynamic Projection:
Подробнее о сценариях использования и компромиссах, на которые придется пойти используя Dynamic Projection, читайте в следующей статье: https://maciejwalkowiak.com/blog/spring-data-jpa-dynamic-projections/
Используя Spring Data, довольно часто могут возникать накладные расходы из-за получения из базы слишком большого количества полей. Чтобы решить эту проблему, мы можем объявлять методы с нативными запросами, DTO или проекциями для случаев, когда необходимо ограничить количество выбираемых полей. Но такой подход приводит к появлению множества очень похожих методов в репозитории. Например:
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByName(String name); // выбираем из базы сущность со всеми её полями
List<ProductProjection> findPrjsByName(String name); //выбираем из базы ограниченный набор полей, указанный в некоторой проекции
List<ProductDto> findDtosByName(String name); //выбираем из базы ограниченный набор полей, указанный в некоторой DTO
}
Чтобы решить эту проблему можно прибегнуть к использованию Dynamic Projection:
public interface ProductRepository extends JpaRepository<Product, Long> {
<T> List<T> findByName(String name, Class<T> type);
}
Подробнее о сценариях использования и компромиссах, на которые придется пойти используя Dynamic Projection, читайте в следующей статье: https://maciejwalkowiak.com/blog/spring-data-jpa-dynamic-projections/
Maciejwalkowiak
Dynamic Projections with Spring Data JPA
🔥15👍11👌3
Мы рады сообщить, что наше сообщество начинает обрастать экспертами, и мы будем знакомить вас с их мнением. Встречайте, Михаил Поливаха, коммитер Spring Data JDBC (Relational), не удержался от комментария по вопросу поддержки проекций в разных модулях Spring Data. Ниже прямая речь Михаила.
Надо сказать, что projection-ы, как функциональность, должна быть доступна во всех модулях spring-data. Вопрос в том, что еще не все модули ее поддержку реализовали до конца.
Наивный читатель мог бы предположить, что поскольку в spring-data-jdbc есть поддержка как interface based projection-ов, так и dynamic projection-ов, то вот это заработает:
Но данный код сгенерит ошибку глубоко в недрах JdbcQueryCreator-a:
Связано это с тем, что на данный момент spring-data-jdbc просто не умеет переваривать динамические проджекшены для инфтерфейсов 🙂
Про это мы знаем, бага на это дело пока нет, если он кому-либо важен - можем завести. Хочу также напомнить, что если есть какие-либо инициативы для нововведений в spring-data-jdbc - можно оставлять в комментариях или писать мне в ЛС.
Надо сказать, что projection-ы, как функциональность, должна быть доступна во всех модулях spring-data. Вопрос в том, что еще не все модули ее поддержку реализовали до конца.
Наивный читатель мог бы предположить, что поскольку в spring-data-jdbc есть поддержка как interface based projection-ов, так и dynamic projection-ов, то вот это заработает:
public interface MyEntityRepository extends CrudRepository<MyEntity, Long> {
<T> Optional<T> findProjectionByStatus(String status, Class<T> clazz);
}
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Accessors(chain = true)
@Table
public class MyEntity {
@Id
@EqualsAndHashCode.Include
private Long id;
private String status;
@CreatedDate
private Instant createdAt;
}
interface MyEntityInterfaceProjection {
String status();
Long id();
}
@Test
void whenDynamicProjectsAreInUseViaInterfaces_thenBlast() {
saveInitialEntity();
Optional<MyEntityInterfaceProjection> active = myEntityRepository.findProjectionByStatus("active", MyEntityInterfaceProjection.class);
Assertions.assertThat(active)
.isPresent()
.hasValueSatisfying(myEntityProjection -> {
Assertions.assertThat(myEntityProjection.id() != null && myEntityProjection.status().equalsIgnoreCase("active")).isTrue();
});
}
@NotNull
private MyEntity saveInitialEntity() {
MyEntity myEntity = new MyEntity();
myEntity.setStatus("active");
return myEntityRepository.save(myEntity);
}
Но данный код сгенерит ошибку глубоко в недрах JdbcQueryCreator-a:
java.lang.IllegalStateException: SELECT does not declare a select list
at org.springframework.data.relational.core.sql.SelectValidator.doValidate(SelectValidator.java:57)
at org.springframework.data.relational.core.sql.SelectValidator.validate(SelectValidator.java:49)
at org.springframework.data.relational.core.sql.DefaultSelectBuilder.build(DefaultSelectBuilder.java:207)
at org.springframework.data.jdbc.repository.query.JdbcQueryCreator.complete(JdbcQueryCreator.java:173)
at org.springframework.data.jdbc.repository.query.JdbcQueryCreator.complete(JdbcQueryCreator.java:66)
Связано это с тем, что на данный момент spring-data-jdbc просто не умеет переваривать динамические проджекшены для инфтерфейсов 🙂
Про это мы знаем, бага на это дело пока нет, если он кому-либо важен - можем завести. Хочу также напомнить, что если есть какие-либо инициативы для нововведений в spring-data-jdbc - можно оставлять в комментариях или писать мне в ЛС.
🔥19👍8👏3