Skip to content

Commit

Permalink
Issue ReactiveX#711: Added SpEL support für Annotations (ReactiveX#777)
Browse files Browse the repository at this point in the history
  • Loading branch information
eddumelendez authored and RobWin committed Jan 9, 2020
1 parent 7c5c724 commit 650e37b
Show file tree
Hide file tree
Showing 18 changed files with 131 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

import java.lang.annotation.*;

/**
* This annotation can be applied to a class or a specific method. Applying it on a class is
* equivalent to applying it on all its public methods. If using Spring,
* {@code fallbackMethod} can be resolved using Spring Expression Language (SpEL).
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Documented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
* This annotation can be applied to a class or a specific method. Applying it on a class is
* equivalent to applying it on all its public methods. The annotation enables backend monitoring
* for all methods where it is applied. Backend monitoring is performed via a circuit breaker. See
* {@link io.github.resilience4j.circuitbreaker.CircuitBreaker} for details.
* {@link io.github.resilience4j.circuitbreaker.CircuitBreaker} for details. If using Spring,
* {@code fallbackMethod} can be resolved using Spring Expression Language (SpEL).
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
* This annotation can be applied to a class or a specific method. Applying it on a class is
* equivalent to applying it on all its public methods. The annotation enables throttling for all
* methods where it is applied. Throttling monitoring is performed via a rate limiter. See {@link
* io.github.resilience4j.ratelimiter.RateLimiter} for details.
* io.github.resilience4j.ratelimiter.RateLimiter} for details. If using Spring,
* {@code fallbackMethod} can be resolved using Spring Expression Language (SpEL).
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
/**
* This annotation can be applied to a class or a specific method. Applying it on a class is
* equivalent to applying it on all its public methods. The annotation enables backend retry for all
* methods where it is applied. Backend retry is performed via a retry
* methods where it is applied. Backend retry is performed via a retry. If using Spring,
* {@code fallbackMethod} can be resolved using Spring Expression Language (SpEL).
*/
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.github.resilience4j.fallback.FallbackDecorators;
import io.github.resilience4j.fallback.FallbackMethod;
import io.github.resilience4j.utils.AnnotationExtractor;
import io.github.resilience4j.utils.ValueResolver;
import io.vavr.CheckedFunction0;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
Expand All @@ -32,8 +33,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
Expand Down Expand Up @@ -64,7 +67,7 @@
* with a matching exception type as the last parameter on the annotated method
*/
@Aspect
public class BulkheadAspect implements Ordered {
public class BulkheadAspect implements EmbeddedValueResolverAware, Ordered {

private static final Logger logger = LoggerFactory.getLogger(BulkheadAspect.class);

Expand All @@ -74,6 +77,7 @@ public class BulkheadAspect implements Ordered {
private final @Nullable
List<BulkheadAspectExt> bulkheadAspectExts;
private final FallbackDecorators fallbackDecorators;
private StringValueResolver embeddedValueResolver;

public BulkheadAspect(BulkheadConfigurationProperties backendMonitorPropertiesRegistry,
ThreadPoolBulkheadRegistry threadPoolBulkheadRegistry, BulkheadRegistry bulkheadRegistry,
Expand Down Expand Up @@ -103,21 +107,22 @@ public Object bulkheadAroundAdvice(ProceedingJoinPoint proceedingJoinPoint,
}
Class<?> returnType = method.getReturnType();
String backend = bulkheadAnnotation.name();
String fallbackMethodValue = ValueResolver.resolve(this.embeddedValueResolver, bulkheadAnnotation.fallbackMethod());
if (bulkheadAnnotation.type() == Bulkhead.Type.THREADPOOL) {
if (StringUtils.isEmpty(bulkheadAnnotation.fallbackMethod())) {
if (StringUtils.isEmpty(fallbackMethodValue)) {
return proceedInThreadPoolBulkhead(proceedingJoinPoint, methodName, returnType,
backend);
}
return executeFallBack(proceedingJoinPoint, bulkheadAnnotation.fallbackMethod(), method,
return executeFallBack(proceedingJoinPoint, fallbackMethodValue, method,
() -> proceedInThreadPoolBulkhead(proceedingJoinPoint, methodName, returnType,
backend));
} else {
io.github.resilience4j.bulkhead.Bulkhead bulkhead = getOrCreateBulkhead(methodName,
backend);
if (StringUtils.isEmpty(bulkheadAnnotation.fallbackMethod())) {
if (StringUtils.isEmpty(fallbackMethodValue)) {
return proceed(proceedingJoinPoint, methodName, bulkhead, returnType);
}
return executeFallBack(proceedingJoinPoint, bulkheadAnnotation.fallbackMethod(), method,
return executeFallBack(proceedingJoinPoint, fallbackMethodValue, method,
() -> proceed(proceedingJoinPoint, methodName, bulkhead, returnType));
}

Expand Down Expand Up @@ -259,4 +264,9 @@ private Object proceedInThreadPoolBulkhead(ProceedingJoinPoint proceedingJoinPoi
public int getOrder() {
return bulkheadConfigurationProperties.getBulkheadAspectOrder();
}

@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.github.resilience4j.fallback.FallbackDecorators;
import io.github.resilience4j.fallback.FallbackMethod;
import io.github.resilience4j.utils.AnnotationExtractor;
import io.github.resilience4j.utils.ValueResolver;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
Expand All @@ -29,8 +30,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
Expand Down Expand Up @@ -63,7 +66,7 @@
* with a matching exception type as the last parameter on the annotated method
*/
@Aspect
public class CircuitBreakerAspect implements Ordered {
public class CircuitBreakerAspect implements EmbeddedValueResolverAware, Ordered {

private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerAspect.class);

Expand All @@ -72,6 +75,7 @@ public class CircuitBreakerAspect implements Ordered {
private final @Nullable
List<CircuitBreakerAspectExt> circuitBreakerAspectExtList;
private final FallbackDecorators fallbackDecorators;
private StringValueResolver embeddedValueResolver;

public CircuitBreakerAspect(CircuitBreakerConfigurationProperties circuitBreakerProperties,
CircuitBreakerRegistry circuitBreakerRegistry,
Expand Down Expand Up @@ -103,11 +107,12 @@ public Object circuitBreakerAroundAdvice(ProceedingJoinPoint proceedingJoinPoint
methodName, backend);
Class<?> returnType = method.getReturnType();

if (StringUtils.isEmpty(circuitBreakerAnnotation.fallbackMethod())) {
String fallbackMethodValue = ValueResolver.resolve(this.embeddedValueResolver, circuitBreakerAnnotation.fallbackMethod());
if (StringUtils.isEmpty(fallbackMethodValue)) {
return proceed(proceedingJoinPoint, methodName, circuitBreaker, returnType);
}
FallbackMethod fallbackMethod = FallbackMethod
.create(circuitBreakerAnnotation.fallbackMethod(), method,
.create(fallbackMethodValue, method,
proceedingJoinPoint.getArgs(), proceedingJoinPoint.getTarget());
return fallbackDecorators.decorate(fallbackMethod,
() -> proceed(proceedingJoinPoint, methodName, circuitBreaker, returnType)).apply();
Expand Down Expand Up @@ -187,4 +192,9 @@ private Object defaultHandling(ProceedingJoinPoint proceedingJoinPoint,
public int getOrder() {
return circuitBreakerProperties.getCircuitBreakerAspectOrder();
}
}

@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
import io.github.resilience4j.utils.AnnotationExtractor;
import io.github.resilience4j.utils.ValueResolver;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
Expand All @@ -30,8 +31,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
Expand Down Expand Up @@ -64,7 +67,7 @@
*/

@Aspect
public class RateLimiterAspect implements Ordered {
public class RateLimiterAspect implements EmbeddedValueResolverAware, Ordered {

private static final String RATE_LIMITER_RECEIVED = "Created or retrieved rate limiter '{}' with period: '{}'; limit for period: '{}'; timeout: '{}'; method: '{}'";
private static final Logger logger = LoggerFactory.getLogger(RateLimiterAspect.class);
Expand All @@ -73,6 +76,7 @@ public class RateLimiterAspect implements Ordered {
private final @Nullable
List<RateLimiterAspectExt> rateLimiterAspectExtList;
private final FallbackDecorators fallbackDecorators;
private StringValueResolver embeddedValueResolver;

public RateLimiterAspect(RateLimiterRegistry rateLimiterRegistry,
RateLimiterConfigurationProperties properties,
Expand Down Expand Up @@ -110,11 +114,12 @@ public Object rateLimiterAroundAdvice(ProceedingJoinPoint proceedingJoinPoint,
methodName, name);
Class<?> returnType = method.getReturnType();

if (StringUtils.isEmpty(rateLimiterAnnotation.fallbackMethod())) {
String fallbackMethodValue = ValueResolver.resolve(this.embeddedValueResolver, rateLimiterAnnotation.fallbackMethod());
if (StringUtils.isEmpty(fallbackMethodValue)) {
return proceed(proceedingJoinPoint, methodName, returnType, rateLimiter);
}
FallbackMethod fallbackMethod = FallbackMethod
.create(rateLimiterAnnotation.fallbackMethod(), method, proceedingJoinPoint.getArgs(),
.create(fallbackMethodValue, method, proceedingJoinPoint.getArgs(),
proceedingJoinPoint.getTarget());
return fallbackDecorators.decorate(fallbackMethod,
() -> proceed(proceedingJoinPoint, methodName, returnType, rateLimiter)).apply();
Expand Down Expand Up @@ -197,4 +202,9 @@ private Object handleJoinPointCompletableFuture(ProceedingJoinPoint proceedingJo
public int getOrder() {
return properties.getRateLimiterAspectOrder();
}

@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.github.resilience4j.retry.RetryRegistry;
import io.github.resilience4j.retry.annotation.Retry;
import io.github.resilience4j.utils.AnnotationExtractor;
import io.github.resilience4j.utils.ValueResolver;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
Expand All @@ -29,8 +30,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
Expand Down Expand Up @@ -60,7 +63,7 @@
* with a matching exception type as the last parameter on the annotated method
*/
@Aspect
public class RetryAspect implements Ordered {
public class RetryAspect implements EmbeddedValueResolverAware, Ordered {

private static final Logger logger = LoggerFactory.getLogger(RetryAspect.class);
private final static ScheduledExecutorService retryExecutorService = Executors
Expand All @@ -70,6 +73,7 @@ public class RetryAspect implements Ordered {
private final @Nullable
List<RetryAspectExt> retryAspectExtList;
private final FallbackDecorators fallbackDecorators;
private StringValueResolver embeddedValueResolver;

/**
* @param retryConfigurationProperties spring retry config properties
Expand Down Expand Up @@ -108,11 +112,12 @@ public Object retryAroundAdvice(ProceedingJoinPoint proceedingJoinPoint,
io.github.resilience4j.retry.Retry retry = getOrCreateRetry(methodName, backend);
Class<?> returnType = method.getReturnType();

if (StringUtils.isEmpty(retryAnnotation.fallbackMethod())) {
String fallbackMethodValue = ValueResolver.resolve(this.embeddedValueResolver, retryAnnotation.fallbackMethod());
if (StringUtils.isEmpty(fallbackMethodValue)) {
return proceed(proceedingJoinPoint, methodName, retry, returnType);
}
FallbackMethod fallbackMethod = FallbackMethod
.create(retryAnnotation.fallbackMethod(), method, proceedingJoinPoint.getArgs(),
.create(fallbackMethodValue, method, proceedingJoinPoint.getArgs(),
proceedingJoinPoint.getTarget());
return fallbackDecorators.decorate(fallbackMethod,
() -> proceed(proceedingJoinPoint, methodName, retry, returnType)).apply();
Expand Down Expand Up @@ -215,4 +220,8 @@ private void cleanup() {
}));
}

@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package io.github.resilience4j.utils;

import org.springframework.util.StringUtils;
import org.springframework.util.StringValueResolver;

public class ValueResolver {

public static String resolve(StringValueResolver valueResolver, String value) {
if (StringUtils.hasText(value)) {
return valueResolver.resolveStringValue(value);
}
return value;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,10 @@ public Maybe<String> maybe() {
public Flowable<String> flowable() {
return flowableError();
}

@Override
@Bulkhead(name = BACKEND, fallbackMethod = "#{'recovery'}")
public String spelSync() {
return syncError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,10 @@ public Maybe<String> maybe() {
public Flowable<String> flowable() {
return flowableError();
}

@Override
@CircuitBreaker(name = BACKEND, fallbackMethod = "#{'recovery'}")
public String spelSync() {
return syncError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,10 @@ public Maybe<String> maybe() {
public Flowable<String> flowable() {
return flowableError();
}

@Override
@RateLimiter(name = BACKEND, fallbackMethod = "#{'recovery'}")
public String spelSync() {
return syncError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,10 @@ public Maybe<String> maybe() {
public Flowable<String> flowable() {
return flowableError();
}

@Override
@Retry(name = BACKEND, fallbackMethod = "#{'recovery'}")
public String spelSync() {
return syncError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public interface TestDummyService {

Flowable<String> flowable();

String spelSync();

default String syncError() {
throw new RuntimeException("Test");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,9 @@ public void testMaybeRecovery() {
public void testFlowableRecovery() {
assertThat(testDummyService.flowable().blockingFirst()).isEqualTo("recovered");
}
}

@Test
public void testSpelRecovery() {
assertThat(testDummyService.spelSync()).isEqualTo("recovered");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,9 @@ public void testMaybeRecovery() {
public void testFlowableRecovery() {
assertThat(testDummyService.flowable().blockingFirst()).isEqualTo("recovered");
}
}

@Test
public void testSpelRecovery() {
assertThat(testDummyService.spelSync()).isEqualTo("recovered");
}
}
Loading

0 comments on commit 650e37b

Please sign in to comment.