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
Подробный разбор решения задачи 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
Что выведет код?

public class Task041224_1 {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
boolean c = true;

boolean result1 = a && (b || c) && !b;
boolean result2 = (a ^ b) || (c && b);
boolean result3 = !(a && c) || (b && !c);

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


#Tasks
А ведь раньше логику в школах преподавали...🧐

https://t.me/Java_for_beginner_dev

#Mems
Примеры аспектов

1. Аспект логирования

Этот аспект логирует вызовы методов до и после их выполнения.
@Aspect
@Component
public class LoggingAspect {

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

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


2. Аспект измерения времени выполнения

Измеряет время, которое метод тратит на выполнение.
@Aspect
@Component
public class PerformanceAspect {

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

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

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

return proceed;
}
}


3. Аспект обработки исключений

Перехватывает и обрабатывает исключения, выбрасываемые методами.

@Aspect
@Component
public class ExceptionHandlingAspect {

@AfterThrowing(pointcut = "execution(* com.example.service.UserService.*(..))", throwing = "exception")
public void logException(JoinPoint joinPoint, Throwable exception) {
System.out.println("Exception in method: " + joinPoint.getSignature().getName());
System.out.println("Exception message: " + exception.getMessage());
}
}


4. Аспект для проверки авторизации

Проверяет, имеет ли пользователь доступ к выполнению метода.
@Aspect
@Component
public class SecurityAspect {

@Before("execution(* com.example.service.SensitiveService.*(..))")
public void checkAccess(JoinPoint joinPoint) {
System.out.println("Checking access before method: " + joinPoint.getSignature().getName());
// Проверка прав доступа
if (!isUserAuthorized()) {
throw new SecurityException("User not authorized");
}
}

private boolean isUserAuthorized() {
// Логика авторизации
return true; // Например, возвращаем всегда true
}
}


5. Аспект кеширования

Кеширует результат выполнения метода.
@Aspect
@Component
public class CachingAspect {

private final Map<String, Object> cache = new HashMap<>();

@Around("execution(* com.example.service.CacheableService.*(..))")
public Object cacheMethod(ProceedingJoinPoint joinPoint) throws Throwable {
String key = joinPoint.getSignature().toString() + Arrays.toString(joinPoint.getArgs());

if (cache.containsKey(key)) {
System.out.println("Returning cached result for " + key);
return cache.get(key);
}

Object result = joinPoint.proceed(); // Выполнение метода
cache.put(key, result);
System.out.println("Caching result for " + key);

return result;
}
}


#Java #Training #Spring #AOP