Java for Beginner
673 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
Просто 😂😂😂😂😂

https://t.me/Java_for_beginner_dev

#Mems
Примеры использования кеша на примере Caffeine и Redis

1. Пример с использованием Caffeine

Допустим, у нас есть метод, который возвращает данные пользователя.
@Service
public class UserService {

@Cacheable("usersCache")
public User getUserById(Long id) {
System.out.println("Fetching user from database...");
// Имитация запроса к базе данных
return new User(id, "User" + id);
}

@CacheEvict(value = "usersCache", key = "#id")
public void updateUser(Long id, User user) {
System.out.println("Updating user in database...");
// Обновление в базе
}
}


Проверка:
Первый вызов getUserById(1L) загрузит данные из базы.
Повторный вызов вернёт данные из кеша.
Метод updateUser(1L, user) очистит устаревшие данные из кеша.
Вывод: Кеш на базе Caffeine идеально подходит для небольших объёмов данных с высокой скоростью работы.


2. Пример с использованием Redis

Допустим, мы создаём приложение, где кеш хранится в Redis.
@Service
public class ProductService {

@Cacheable("productCache")
public Product getProductById(Long id) {
System.out.println("Fetching product from database...");
// Имитация запроса к базе данных
return new Product(id, "Product" + id);
}

@CacheEvict(value = "productCache", key = "#id")
public void updateProduct(Long id, Product product) {
System.out.println("Updating product in database...");
// Обновление в базе
}
}


Проверка:
При вызове getProductById(1L) данные сохраняются в Redis.
Повторный вызов с тем же ID возвращает данные из Redis без обращения к базе.
Метод updateProduct(1L, product) удаляет кешированные данные.


Преимущества Redis:
Данные доступны для всех экземпляров приложения в распределённой системе.
Redis поддерживает TTL (время жизни кеша), что удобно для управления устареванием данных.


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

Задача по aннотации @Transactional, аннотациям @Cacheable и @CacheEvict, симуляция кеша в Spring. Сложность легкая.

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

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
@EnableCaching
public class Task291124_2 {
public static void main(String[] args) {
SpringApplication.run(Task291124_2.class, args);
}

@Bean
public CommandLineRunner demo(UserService2911 userService) {
return args -> {
System.out.println(userService.getUserById(1L));
System.out.println(userService.getUserById(1L));
userService.clearCache();
System.out.println(userService.getUserById(1L));
};
}
}

@Service
class UserService2911 {
private final Map<Long, String> database = new HashMap<>();

public UserService2911() {
database.put(1L, "Alice");
}

@Cacheable("users")
public String getUserById(Long id) {
System.out.println("Fetching user from database...");
return database.get(id);
}

@CacheEvict(value = "users", allEntries = true)
public void clearCache() {
System.out.println("Cache cleared");
}

@Transactional
public void updateUser(Long id, String newName) {
database.put(id, newName);
if (newName == null) {
throw new IllegalArgumentException("Name cannot be null");
}
}
}


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

1. Контекст задачи

Задача исследует использование аннотаций Spring для работы с кешированием (
@Cacheable, @CacheEvict) и транзакциями (@Transactional). Также рассматривается, как Spring управляет кешем, обрабатывает транзакции и вызывает базовые CRUD операции.

2. Ключевые элементы кода

Аннотация
@SpringBootApplication:
Указывает, что Task291124_2 — это основной класс Spring Boot приложения. Он автоматически настраивает компоненты приложения, включая механизмы кеширования и управления транзакциями.

Аннотация
@EnableCaching:
Разрешает проведение кеширования. Без включения @EnableCaching Spring не активирует кеширование, и @Cacheable не работает.

Аннотация
@Service:
UserService2911 помечен как сервисный компонент, что делает его доступным в контексте Spring для внедрения зависимостей.

Кеширование с помощью аннотаций
@Cacheable и @CacheEvict:
@Cacheable("users"): Метод getUserById(Long id) кеширует результат выполнения с ключом, основанным на значении параметра id. Если вызов осуществляется с тем же id, результат извлекается из кеша, и метод повторно не выполняется.
@CacheEvict(value = "users", allEntries = true): Метод clearCache() очищает кеш для всех записей в кеше users.

Транзакционное управление с помощью
@Transactional:
Метод updateUser(Long id, String newName) помечен как транзакционный. Если во время выполнения метода происходит исключение, транзакция откатывается, и изменения в базе данных не применяются.

Симуляция базы данных:
Данные хранятся в объекте Map<Long, String> database, который используется как простая "база данных". В данном случае только один пользователь (Alice) с id = 1L изначально добавлен в "базу".

Использование CommandLineRunner:
Метод demo() выполняет тестовый код сразу после запуска приложения. Он вызывает методы getUserById() и clearCache(), демонстрируя поведение кеширования.

3. Сценарий работы программы

Запуск приложения:
Программа запускается через
SpringApplication.run(Main2911.class, args);, и Spring Boot автоматически настраивает кеширование, транзакции и остальные компоненты приложения.

Первый вызов getUserById(1L):
Метод getUserById(1L) вызывается первый раз. Поскольку кеш для ключа 1L еще не существует, данные извлекаются из "базы данных" (Map), выводится:
Fetching user from database...

Результат ("Alice") добавляется в кеш и возвращается.

Второй вызов getUserById(1L):
Метод вызывается снова с тем же параметром 1L. Поскольку результат уже находится в кеше, он извлекается из кеша без повторного обращения к "базе данных". Никакого сообщения о запросе к базе данных не выводится, а результат ("Alice") возвращается напрямую.

Вызов clearCache():
Метод clearCache() вызывается, что очищает кеш для всех записей в кеше users. В консоль выводится сообщение:
Cache cleared


Третий вызов getUserById(1L):
После очистки кеша метод снова вызывается с параметром 1L. Поскольку кеш был очищен, данные снова извлекаются из "базы данных".
Вывод:
Fetching user from database...

Результат ("Alice") возвращается и снова кешируется.

4. Ключевые моменты и выводы

Механизм кеширования:
Аннотация
@Cacheable кеширует результат выполнения метода, что предотвращает повторное выполнение, если запрос уже был обработан ранее.
Аннотация
@CacheEvict используется для очистки кеша. В данном случае allEntries = true очищает все записи в кеше users.

Транзакционное управление:
Метод updateUser() не используется в задаче, но он демонстрирует работу транзакций. Если в процессе обновления пользовательского имени возникает исключение (например, при передаче null), транзакция откатывается, и изменения в базе данных не применяются.

Проверка работы кеша:
Первый вызов метода getUserById() выполняет запрос к "базе данных", а второй использует кеш.
После вызова clearCache() кеш очищается, и следующий вызов метода снова выполняет запрос к базе.

#Solution_TasksSpring
Всем доброго утра!🖐

Не знаю что писать в субботу с утра)))

Поэтому просто пожелаю Вам хороших выходных😉

А если кому скучно - жду вас в нашем чате - https://t.me/Java_Beginner_chat
Всем привет!🖐

Сегодня в 16:00 по МСК мы вновь встречаемся в том же месте! (Яндекс.Телемост, кто не понял)

@VladislavSlavName потренируется в написании web-приложения, а Вы можете составить ему компанию

Ждем всех!💪
Встреча создана!

Залетаем👍

https://telemost.yandex.ru/j/74261437324336
Встреча_в_Телемосте_01_12_24_20_02_00_—_запись.webm
182.9 MB
Простое Web приложение, обучение аннотации @Query

Спасибо всем кто пришел, за участие!


Отдельная благодарность @VladislavSlavName что не зассал (побоялся) и показал нам свои знания 💪

На сегодняшней встрече мы написали простое Web приложение, разобрали работу каждой использованной аннотации, класса и метода, изучили аннотацию @Query.

Прикладываю запись, если кто-то пожелает пересмотреть)
Основы аспектно-ориентированного программирования (AOP) в Spring

Аспектно-ориентированное программирование (AOP) – это подход, позволяющий разделять сквозную функциональность приложения (например, логирование, безопасность, транзакции) от основной логики. AOP в Spring является мощным инструментом для управления поведением приложения, упрощая код и повышая его модульность.

AOP — это методология программирования, которая вводит концепцию аспектов. Аспект – это модуль, содержащий сквозную функциональность, которую можно применить к разным частям программы без изменения их исходного кода.

Основные концепции AOP

Аспект (Aspect)
Модуль, содержащий сквозную функциональность (например, логирование или авторизацию).
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("Logging before method execution");
}
}


Точка соединения (Join Point)

Определённое место в программе, где можно "вставить" аспект. Например, вызов метода, создание объекта.

Срез (Pointcut)

Условие, определяющее, на какие точки соединения должен применяться аспект.
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayerMethods() {}


Совет (Advice)
Логика, которая выполняется на основе среза. Типы советов:

@Before: выполняется до вызова метода.
@After: выполняется после завершения метода.
@AfterReturning: выполняется, если метод завершился успешно.
@AfterThrowing: выполняется при возникновении исключения.
@Around: оборачивает выполнение метода, позволяет управлять его выполнением.
@Before("serviceLayerMethods()")
public void logBeforeServiceMethod() {
System.out.println("Executing service method...");
}


Как включить AOP в Spring?

Добавьте зависимость в проект: Для использования AOP в Spring Boot:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>


Включите поддержку AOP: Добавьте аннотацию @EnableAspectJAutoProxy в ваш @Configuration класс.
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {}


Создайте аспект:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("Method execution intercepted by AOP.");
}
}


Создайте бизнес-логику:
@Service
public class UserService {
public void getUserById(Long id) {
System.out.println("Getting user by ID: " + id);
}
}


Результат:
Вызов метода getUserById(1L) сначала выполняет логику @Before, а затем основную логику метода.

Пример с логированием (совет @Around):
@Aspect
@Component
public class PerformanceLoggingAspect {

@Around("execution(* com.example.service.*.*(..))")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();

Object result = joinPoint.proceed(); // Выполнение метода

long executionTime = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return result;
}
}
Теперь при вызове методов сервисного слоя будет логироваться время выполнения.


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

import java.util.ArrayList;
import java.util.List;

public class Task021224_1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
list.add(i * i);
}

list.add(2, 10);
list.set(0, list.get(3));
list.remove(Integer.valueOf(16));

for (int i = 0; i < list.size(); i++) {
list.set(i, list.get(i) % 7);
}

System.out.println(list);
}
}


#Tasks
400к+: "О, я Вас кажется знаю, Вы же у нас работаете,да?" 🤪😂

https://t.me/Java_for_beginner_dev

#Mems
Зачем нужно AOP?

Основная задача AOP — изолировать сквозную функциональность, которую сложно выразить через объектно-ориентированное программирование. AOP упрощает код, устраняя необходимость дублирования.

Примеры сквозной функциональности

Логирование:
Логировать действия пользователя, запросы или ошибки.

@Before("execution(* com.example.controller.*.*(..))")
public void logRequest() {
System.out.println("Handling request...");
}


Управление транзакциями:
Начало и завершение транзакции при выполнении метода.

@Around("@annotation(org.springframework.transaction.annotation.Transactional)")
public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Transaction started");
Object result = joinPoint.proceed();
System.out.println("Transaction committed");
return result;
}


Авторизация:
Проверка, имеет ли пользователь доступ к определённому ресурсу.

@Before("execution(* com.example.service.*.*(..))")
public void checkAuthorization() {
if (!isAuthorized()) {
throw new SecurityException("User is not authorized");
}
}


Отслеживание производительности:
Логирование времени выполнения метода.

@Around("execution(* com.example.service.*.*(..))")
public Object logPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long elapsedTime = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " executed in " + elapsedTime + "ms");
return result;
}


Основные преимущества использования AOP

Модульность:
Сквозная функциональность сосредоточена в аспектах, что упрощает сопровождение кода.

Читаемость:
Устранение дублирования. Бизнес-логику можно сосредоточить в одном месте.

Гибкость:
Возможность легко изменять аспекты без изменения основного кода.

Повышение тестируемости:
Сквозную функциональность можно тестировать отдельно.

Практический пример: Логирование запросов

Аспект для логирования:
@Aspect
@Component
public class RequestLoggingAspect {

@Before("execution(* com.example.controller.*.*(..))")
public void logRequest(JoinPoint joinPoint) {
System.out.println("Request to: " + joinPoint.getSignature());
}
}


Контроллер:
@RestController
public class UserController {

@GetMapping("/users/{id}")
public String getUser(@PathVariable Long id) {
return "User with ID: " + id;
}
}
Результат: Каждый запрос к контроллеру будет логироваться через аспект.


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

Сложная логика аспекта:
Если аспект содержит значительную часть логики, его тестирование и сопровождение могут усложниться.

Чрезмерное использование:
Злоупотребление AOP может сделать проект сложным для понимания из-за "невидимых" операций.

#Java #Training #Spring #AOP
Понятия Joinpoint, Pointcut, Advice

В AOP (аспектно-ориентированном программировании) три ключевых концепции — Joinpoint, Pointcut и Advice — определяют, как и где выполняется логика аспектов. Эти понятия позволяют чётко определить, где вставлять дополнительную функциональность, и упростить реализацию сквозных задач.

Joinpoint


Joinpoint — это конкретная точка в выполнении программы, где аспект может быть применён.

Примеры:
Вызов метода.
Выполнение метода.
Обработка исключений.


Примеры Joinpoint в Spring AOP

Spring поддерживает только Joinpoint, связанные с методами:
Вызов метода (method execution).
Перехват аргументов метода.
Обработка результата или исключения.


Пример:
@Before("execution(* com.example.service.UserService.*(..))")
public void logMethodCall(JoinPoint joinPoint) {
System.out.println("Method called: " + joinPoint.getSignature());
System.out.println("Arguments: " + Arrays.toString(joinPoint.getArgs()));
}


Основные методы Joinpoint

getSignature(): возвращает информацию о вызываемом методе.
getArgs(): возвращает массив аргументов метода.
getTarget(): объект, на котором вызван метод.
getThis(): прокси-объект, созданный Spring AOP.


Пример использования:
@After("execution(* com.example.service.UserService.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("Executed method: " + joinPoint.getSignature().getName());
}


Pointcut

Pointcut — это выражение, определяющее набор Joinpoint, к которым будет применяться аспект.
Pointcut помогает сосредоточить внимание только на нужных местах кода.


В Spring используются SpEL (Spring Expression Language) для создания срезов:

По классу и методам:
execution(* com.example.service.UserService.*(..))


По пакетам:
execution(* com.example..*(..)) // Все методы во всех пакетах


По аннотациям:
@annotation(org.springframework.transaction.annotation.Transactional)


Пример:
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayerMethods() {}
Теперь serviceLayerMethods() можно использовать как ссылку на срез.


Advice

Advice — это дополнительная логика, которая выполняется в определённой точке выполнения программы (Joinpoint).
Advice описывает, что нужно выполнить.

Типы Advice в Spring

@Before: выполняется перед вызовом метода.
@Before("execution(* com.example.service.UserService.*(..))")
public void logBefore() {
System.out.println("Method is about to be called");
}


@After: выполняется после завершения метода (независимо от результата).
@After("execution(* com.example.service.UserService.*(..))")
public void logAfter() {
System.out.println("Method has been executed");
}


@AfterReturning: выполняется, если метод завершился успешно.
@AfterReturning(pointcut = "execution(* com.example.service.UserService.*(..))", returning = "result")
public void logAfterReturning(Object result) {
System.out.println("Method returned value: " + result);
}


@AfterThrowing: выполняется при выбросе исключения.
@AfterThrowing(pointcut = "execution(* com.example.service.UserService.*(..))", throwing = "exception")
public void logAfterThrowing(Exception exception) {
System.out.println("Exception thrown: " + exception.getMessage());
}


@Around: оборачивает выполнение метода, позволяет контролировать его выполнение.
@Around("execution(* com.example.service.UserService.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before method execution");
Object result = joinPoint.proceed();
System.out.println("After method execution");
return result;
}


#Java #Training #Spring #AOP #Joinpoint #Pointcut #Advice
Что выведет код?

import java.util.Locale;

public class Task031224_1 {
public static void main(String[] args) {
String template = "Value: %.2f, Hex: %04x, Bool: %b";

String result1 = String.format(template, 12.34567, 255, null);
String result2 = String.format(Locale.US, template, 0.1, 16, true);

System.out.println(result1);
System.out.println(result2);
}
}


#Tasks
Неожиданно, о требованиях HR 😱😂

https://t.me/Java_for_beginner_dev

#Mems
Создание простого аспекта

Теперь разберёмся, как создать и настроить простой аспект в Spring.

Шаг 1: Добавьте зависимость

Добавьте зависимость Spring AOP в pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>


Шаг 2: Включите поддержку AOP

Добавьте аннотацию @EnableAspectJAutoProxy в конфигурационный класс:
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {}


Шаг 3: Реализация аспекта

Создайте аспектный класс:
@Aspect
@Component
public class LoggingAspect {

@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}

@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}

@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void logAfterReturning(Object result) {
System.out.println("Method returned: " + result);
}

@AfterThrowing(pointcut = "serviceMethods()", throwing = "exception")
public void logAfterThrowing(Exception exception) {
System.out.println("Exception: " + exception.getMessage());
}
}


Создайте бизнес-логику:
@Service
public class UserService {
public String getUserById(Long id) {
System.out.println("Fetching user...");
if (id == null) {
throw new IllegalArgumentException("ID cannot be null");
}
return "User" + id;
}
}


Контроллер для проверки:
@RestController
public class UserController {
@Autowired
private UserService userService;

@GetMapping("/users/{id}")
public String getUser(@PathVariable Long id) {
return userService.getUserById(id);
}
}


Результат работы аспекта


При вызове метода getUserById(1):
- @Before: "Before method: getUserById".
- Выполняется логика метода.
- @AfterReturning: "Method returned: User1".

При вызове метода с ошибкой getUserById(null):
- @Before: "Before method: getUserById".
- Метод выбрасывает исключение.
- @AfterThrowing: "Exception: ID cannot be null".

Советы по работе с AOP

Используйте AOP для сквозных задач, таких как:
Логирование.
Транзакции.
Безопасность.


Избегайте чрезмерного использования AOP, чтобы не усложнять отладку.
Структурируйте Pointcut выражения, чтобы аспекты легко переиспользовались.
Тестируйте аспекты отдельно от основной бизнес-логики.

#Java #Training #Spring #AOP #CreateAOP
Аннотации @Before, @After, @Around

Spring AOP предоставляет различные типы советов (Advice), которые позволяют внедрять дополнительную логику в определённые точки выполнения программы.

Аннотация @Before

Аннотация @Before используется для выполнения кода перед вызовом метода.
Срабатывает до метода-цели, вне зависимости от его результата.
Используется для логирования, проверки входных данных, проверки прав доступа и т.д.


@Before("pointcut_expression")
public void adviceMethod(JoinPoint joinPoint) {
// Логика совета
}


Пример использования:
@Aspect
@Component
public class LoggingAspect {

@Before("execution(* com.example.service.UserService.*(..))")
public void logBeforeMethod(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
}


Нюансы:
Не контролирует выполнение метода: метод-цель будет вызван независимо от совета.
Не может перехватывать результат или исключение.


Аннотация @After

Аннотация @After используется для выполнения кода после завершения метода, независимо от того, успешно он завершился или выбросил исключение.
Полезна для освобождения ресурсов, записи логов.

@After("pointcut_expression")
public void adviceMethod(JoinPoint joinPoint) {
// Логика совета
}


Пример использования:
@Aspect
@Component
public class CleanupAspect {

@After("execution(* com.example.service.UserService.*(..))")
public void cleanupAfterMethod(JoinPoint joinPoint) {
System.out.println("After method: " + joinPoint.getSignature().getName());
}
}


Нюансы:
Всегда срабатывает после метода, даже если метод выбросил исключение.
Используется для логирования и операций, которые должны быть выполнены в любом случае.


Аннотация @Around

Аннотация @Around оборачивает вызов метода-цели и позволяет полностью контролировать его выполнение.
Может изменять параметры метода и результат.
Позволяет управлять выполнением метода, включая его пропуск или повторное выполнение.
Используется для измерения времени выполнения, транзакционного управления и других сложных сценариев.


@Around("pointcut_expression")
public Object adviceMethod(ProceedingJoinPoint joinPoint) throws Throwable {
// Логика до метода
Object result = joinPoint.proceed(); // Выполнение метода-цели
// Логика после метода
return result;
}


Пример использования:
@Aspect
@Component
public class PerformanceAspect {

@Around("execution(* com.example.service.UserService.*(..))")
public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();

Object result = joinPoint.proceed(); // Выполняем метод

long executionTime = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");

return result;
}
}


Нюансы:
Требует вызова proceed() для выполнения метода-цели.
Может модифицировать результат или перехватывать исключения.
Самая мощная из всех аннотаций, но требует осторожного использования.


#Java #Training #Spring #AOP #Before #After #Around