From 00b4aace34e62ea1ce63f41ef38473fca1f200fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=B0=D1=81=D0=BF=D1=88=D0=B8=D1=86=D0=BA=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9?= Date: Thu, 4 Jul 2024 16:48:20 +0500 Subject: [PATCH] feature: Rate Limiting pattern (#2973) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Заготовка архитектуры --- rate-limiting/pom.xml | 30 ++++++++ .../src/main/java/com/iluwatar/App.java | 43 ++++++++++++ .../src/main/java/com/iluwatar/Main.java | 7 -- .../java/com/iluwatar/aspect/RateLimited.java | 17 +++++ .../iluwatar/aspect/RateLimiterAspect.java | 68 +++++++++++++++++++ .../controller/RateLimitedController.java | 26 +++++++ .../java/com/iluwatar/model/DtoClass.java | 15 ++++ .../com/iluwatar/pattern/RateLimiter.java | 11 +++ 8 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 rate-limiting/src/main/java/com/iluwatar/App.java delete mode 100644 rate-limiting/src/main/java/com/iluwatar/Main.java create mode 100644 rate-limiting/src/main/java/com/iluwatar/aspect/RateLimited.java create mode 100644 rate-limiting/src/main/java/com/iluwatar/aspect/RateLimiterAspect.java create mode 100644 rate-limiting/src/main/java/com/iluwatar/controller/RateLimitedController.java create mode 100644 rate-limiting/src/main/java/com/iluwatar/model/DtoClass.java create mode 100644 rate-limiting/src/main/java/com/iluwatar/pattern/RateLimiter.java diff --git a/rate-limiting/pom.xml b/rate-limiting/pom.xml index 2c186493680f..4584cf49704b 100644 --- a/rate-limiting/pom.xml +++ b/rate-limiting/pom.xml @@ -34,6 +34,22 @@ rate-limiting + + org.springframework + spring-webmvc + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework + spring-context + + + org.springframework.boot + spring-boot-starter-thymeleaf + org.junit.jupiter junit-jupiter-engine @@ -44,6 +60,20 @@ mockito-core test + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework + spring-test + test + + + org.springframework.boot + spring-boot-starter-aop + diff --git a/rate-limiting/src/main/java/com/iluwatar/App.java b/rate-limiting/src/main/java/com/iluwatar/App.java new file mode 100644 index 000000000000..c443be2baa6d --- /dev/null +++ b/rate-limiting/src/main/java/com/iluwatar/App.java @@ -0,0 +1,43 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.SpringApplication; + +/** + * App class. + */ +@Slf4j +public class App { + + /** + * Program entry point. + */ + public static void main(String[] args) { + SpringApplication app = new SpringApplication(App.class); + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/rate-limiting/src/main/java/com/iluwatar/Main.java b/rate-limiting/src/main/java/com/iluwatar/Main.java deleted file mode 100644 index 49bd2db0610f..000000000000 --- a/rate-limiting/src/main/java/com/iluwatar/Main.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.iluwatar; - -public class Main { - public static void main(String[] args) { - System.out.println("Hello world!"); - } -} \ No newline at end of file diff --git a/rate-limiting/src/main/java/com/iluwatar/aspect/RateLimited.java b/rate-limiting/src/main/java/com/iluwatar/aspect/RateLimited.java new file mode 100644 index 000000000000..69fb8e1c24bc --- /dev/null +++ b/rate-limiting/src/main/java/com/iluwatar/aspect/RateLimited.java @@ -0,0 +1,17 @@ +package com.iluwatar.aspect; + +import java.util.concurrent.TimeUnit; + +/** + * AOP annotation. + */ +public @interface RateLimited { + /** + * invoke method vialotation for one ip address. + */ + int count() default 10; + /** + * time unit for reset vialotation. + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; +} diff --git a/rate-limiting/src/main/java/com/iluwatar/aspect/RateLimiterAspect.java b/rate-limiting/src/main/java/com/iluwatar/aspect/RateLimiterAspect.java new file mode 100644 index 000000000000..6ca7d8ff4d8d --- /dev/null +++ b/rate-limiting/src/main/java/com/iluwatar/aspect/RateLimiterAspect.java @@ -0,0 +1,68 @@ +package com.iluwatar.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +/** + * Aspect for rate limiting functionality using Spring AOP. + */ +@Slf4j +@Aspect +@Component +public class RateLimiterAspect { + + /** + * Pointcut to intercept methods annotated with @RateLimited. + */ + @Pointcut("@annotation(com.iluwatar.aspect.RateLimited)") + public void callMethodWithAnnotation() { } + + /** + * Advice executed before methods annotated with @RateLimited are invoked. + */ + @Before( + value = "callMethodWithAnnotation()", argNames = "jp") + public void endpointBeforeInvoke(JoinPoint jp) { + String methodName = jp.getSignature().getName(); + LOGGER.info("Before executing method: {}", methodName); + } + + /** + * Advice executed after methods annotated with @RateLimited successfully return. + * + * @param jp JoinPoint that intercepted the method call. + * @param returningValue Value returned by the intercepted method. + * @return The same returningValue as passed. + */ + @AfterReturning( + value = "callMethodWithAnnotation()", + argNames = "jp,returningValue", + returning = "returningValue") + public Object endpointAfterReturning(JoinPoint jp, Object returningValue) { + String methodName = jp.getSignature().getName(); + LOGGER.info("Before executing method: {}", methodName); + return returningValue; + } + + /** + * Advice executed after methods annotated with @RateLimited throw an exception. + * + * @param jp JoinPoint that intercepted the method call. + * @param e Exception thrown by the intercepted method. + */ + @AfterThrowing( + pointcut = "callMethodWithAnnotation()", + argNames = "jp,e", + throwing = "e") + public void endpointAfterThrowing(JoinPoint jp, Exception e) { + String methodName = jp.getSignature().getName(); + LOGGER.info("Before executing method: {}", methodName); + } + +} diff --git a/rate-limiting/src/main/java/com/iluwatar/controller/RateLimitedController.java b/rate-limiting/src/main/java/com/iluwatar/controller/RateLimitedController.java new file mode 100644 index 000000000000..5cb57ac78200 --- /dev/null +++ b/rate-limiting/src/main/java/com/iluwatar/controller/RateLimitedController.java @@ -0,0 +1,26 @@ +package com.iluwatar.controller; + +import com.iluwatar.aspect.RateLimited; +import com.iluwatar.model.DtoClass; +import java.util.concurrent.TimeUnit; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Rest API controller for example rate limited. + */ +@RestController +public class RateLimitedController { + + /** + * Simple GET method. + * + * @return Simple DTO object. + */ + @RateLimited(count = 15, timeUnit = TimeUnit.MINUTES) + @GetMapping("test-request") + public DtoClass getRequest() { + return new DtoClass(); + } + +} diff --git a/rate-limiting/src/main/java/com/iluwatar/model/DtoClass.java b/rate-limiting/src/main/java/com/iluwatar/model/DtoClass.java new file mode 100644 index 000000000000..2ca4f7dc582e --- /dev/null +++ b/rate-limiting/src/main/java/com/iluwatar/model/DtoClass.java @@ -0,0 +1,15 @@ +package com.iluwatar.model; + +import lombok.Data; + +/** + * Example dto for controller. + */ +@Data +public class DtoClass { + + private Long id = 1L; + + private String name = "dto for example"; + +} diff --git a/rate-limiting/src/main/java/com/iluwatar/pattern/RateLimiter.java b/rate-limiting/src/main/java/com/iluwatar/pattern/RateLimiter.java new file mode 100644 index 000000000000..b25b0ba64b7b --- /dev/null +++ b/rate-limiting/src/main/java/com/iluwatar/pattern/RateLimiter.java @@ -0,0 +1,11 @@ +package com.iluwatar.pattern; + +import org.springframework.stereotype.Component; + +/** + * Realization Rate Limiting. + */ +@Component +public class RateLimiter { + +}