From 41ad97ea54431d963fea054c646819e287811cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 12 Oct 2024 19:23:59 +0200 Subject: [PATCH] feat: spring support --- README.md | 25 ++++- TODO.md | 6 -- settings.gradle.kts | 3 +- spring/build.gradle.kts | 24 +++++ .../org/incendo/disruptor/spring/Disrupt.java | 62 ++++++++++++ .../disruptor/spring/DisruptorAdvice.java | 97 +++++++++++++++++++ .../spring/DisruptorBeanPostProcessor.java | 84 ++++++++++++++++ .../disruptor/spring/package-info.java | 4 + ...ot.autoconfigure.AutoConfiguration.imports | 2 + .../disruptor/test/DisruptorAdviceTest.java | 55 +++++++++++ .../disruptor/test/TestApplication.java | 35 +++++++ .../incendo/disruptor/test/TestConfig.java | 47 +++++++++ .../incendo/disruptor/test/TestService.java | 39 ++++++++ spring/src/test/resources/application.yml | 7 ++ 14 files changed, 482 insertions(+), 8 deletions(-) delete mode 100644 TODO.md create mode 100644 spring/build.gradle.kts create mode 100644 spring/src/main/java/org/incendo/disruptor/spring/Disrupt.java create mode 100644 spring/src/main/java/org/incendo/disruptor/spring/DisruptorAdvice.java create mode 100644 spring/src/main/java/org/incendo/disruptor/spring/DisruptorBeanPostProcessor.java create mode 100644 spring/src/main/java/org/incendo/disruptor/spring/package-info.java create mode 100644 spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 spring/src/test/java/org/incendo/disruptor/test/DisruptorAdviceTest.java create mode 100644 spring/src/test/java/org/incendo/disruptor/test/TestApplication.java create mode 100644 spring/src/test/java/org/incendo/disruptor/test/TestConfig.java create mode 100644 spring/src/test/java/org/incendo/disruptor/test/TestService.java create mode 100644 spring/src/test/resources/application.yml diff --git a/README.md b/README.md index 2fb7676..81f0af2 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ library for introducing disruptions to your code to replicate an unstable live e ## Modules - **core:** core disruptor API -- ~~**spring:** spring integration~~ +- **spring:** spring integration - **openfeign:** feign integration ## Example @@ -56,4 +56,27 @@ Feign.builder()/*...*/.addCapability(capability)/*...*/; Capability disruptorCapability() { return DisruptorCapability(disruptor, "group"); } +``` + +### Spring + +```java +import java.beans.BeanProperty; + +@Configuration +public class YourConfig { + + @Bean + Disruptor disruptor() { + return Disruptor.builder()/*...*/.build(); + } +} + +@Disrupt("group") // You may annotate a class... +public class YourService { + + @Disrupt("other-group") //... or a method + public void yourMethod() { + } +} ``` \ No newline at end of file diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 8b15c27..0000000 --- a/TODO.md +++ /dev/null @@ -1,6 +0,0 @@ -# TODO - -1. [x] Create core API -2. [x] Tests :) -3. [ ] Create Spring (AOP) integration -4. [x] Create Feign integration \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 93188b6..df7dfda 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,4 +30,5 @@ dependencyResolutionManagement { rootProject.name = "disruptor" include(":core") -include(":openfeign") \ No newline at end of file +include(":openfeign") +include(":spring") \ No newline at end of file diff --git a/spring/build.gradle.kts b/spring/build.gradle.kts new file mode 100644 index 0000000..31fc10d --- /dev/null +++ b/spring/build.gradle.kts @@ -0,0 +1,24 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +plugins { + id("disruptor.base-conventions") + id("disruptor.publishing-conventions") + alias(libs.plugins.spring.plugin.boot) +} + +plugins.apply("io.spring.dependency-management") + +tasks.named("bootJar") { + enabled = false +} + +dependencies { + api(projects.disruptor.core) + implementation(libs.spring.boot.autoconfigure) + + testImplementation(libs.spring.boot.starter.test) +} + +tasks.named("test") { + useJUnitPlatform() +} diff --git a/spring/src/main/java/org/incendo/disruptor/spring/Disrupt.java b/spring/src/main/java/org/incendo/disruptor/spring/Disrupt.java new file mode 100644 index 0000000..2aee0e8 --- /dev/null +++ b/spring/src/main/java/org/incendo/disruptor/spring/Disrupt.java @@ -0,0 +1,62 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.disruptor.spring; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.apiguardian.api.API; +import org.springframework.core.annotation.AliasFor; + +/** + * Annotation placed on classes or methods to indicate that they should be disrupted. + * + * @since 1.0.0 + */ +@Documented +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@API(status = API.Status.STABLE, since = "1.0.0") +public @interface Disrupt { + + /** + * Returns the group name. + * + * @return group name + */ + @AliasFor("group") + String value() default ""; + + /** + * Returns the group name. + * + * @return group name + */ + @AliasFor("value") + String group() default ""; +} diff --git a/spring/src/main/java/org/incendo/disruptor/spring/DisruptorAdvice.java b/spring/src/main/java/org/incendo/disruptor/spring/DisruptorAdvice.java new file mode 100644 index 0000000..a0d047e --- /dev/null +++ b/spring/src/main/java/org/incendo/disruptor/spring/DisruptorAdvice.java @@ -0,0 +1,97 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.disruptor.spring; + +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.apiguardian.api.API; +import org.incendo.disruptor.DisruptionMode; +import org.incendo.disruptor.Disruptor; +import org.jspecify.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Role; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Component; + +import static org.springframework.beans.factory.config.BeanDefinition.ROLE_INFRASTRUCTURE; + +@Role(ROLE_INFRASTRUCTURE) +@ConditionalOnBean(Disruptor.class) +@Component +@API(status = API.Status.INTERNAL, since = "1.0.0") +public class DisruptorAdvice implements MethodInterceptor, ApplicationListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(DisruptorAdvice.class); + + private @Nullable Disruptor disruptor; + + @Override + public Object invoke(final MethodInvocation invocation) throws Throwable { + if (this.disruptor == null) { + return invocation.proceed(); + } + + // The annotation may either be on the class, or method level. + final String group; + final Disrupt methodAnnotation = AnnotationUtils.findAnnotation(invocation.getMethod(), Disrupt.class); + + final Class clazz; + if (invocation.getThis() != null) { + clazz = invocation.getThis().getClass(); + } else { + clazz = invocation.getMethod().getDeclaringClass(); + } + + if (methodAnnotation == null) { + final Disrupt classAnnotation = AnnotationUtils.findAnnotation(clazz, Disrupt.class); + if (classAnnotation == null) { + return invocation.proceed(); + } + group = classAnnotation.group(); + } else { + group = methodAnnotation.group(); + } + + LOGGER.trace( + "Calling disruptor for method {} in class {} using group {}", + invocation.getMethod().getName(), + clazz.getCanonicalName(), + group + ); + + this.disruptor.disrupt(group, DisruptionMode.BEFORE); + final Object result = invocation.proceed(); + this.disruptor.disrupt(group, DisruptionMode.AFTER); + return result; + } + + @Override + public void onApplicationEvent(final ApplicationReadyEvent event) { + this.disruptor = event.getApplicationContext().getBean(Disruptor.class); + } +} diff --git a/spring/src/main/java/org/incendo/disruptor/spring/DisruptorBeanPostProcessor.java b/spring/src/main/java/org/incendo/disruptor/spring/DisruptorBeanPostProcessor.java new file mode 100644 index 0000000..bd6a160 --- /dev/null +++ b/spring/src/main/java/org/incendo/disruptor/spring/DisruptorBeanPostProcessor.java @@ -0,0 +1,84 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.disruptor.spring; + +import java.util.concurrent.atomic.AtomicBoolean; +import org.apiguardian.api.API; +import org.incendo.disruptor.Disruptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.framework.ProxyFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Component; +import org.springframework.util.ReflectionUtils; + +@ConditionalOnBean(Disruptor.class) +@Component +@API(status = API.Status.INTERNAL, since = "1.0.0") +public class DisruptorBeanPostProcessor implements BeanPostProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(DisruptorAdvice.class); + + private final DisruptorAdvice disruptorAdvice; + + /** + * Creates a new post processor. + * + * @param disruptorAdvice disruptor advice + */ + public DisruptorBeanPostProcessor(final DisruptorAdvice disruptorAdvice) { + this.disruptorAdvice = disruptorAdvice; + } + + @Override + public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException { + // If there are no @Disrupt annotations then we're not interested. + if (!this.hasDisruptorAnnotation(bean)) { + return bean; + } + + LOGGER.debug("Creating disruptor proxy for bean {}, class {}", bean, bean.getClass().getCanonicalName()); + + // If there are, however, then we want to create a new proxy which invokes the disruptor. + final ProxyFactory proxyFactory = new ProxyFactory(bean); + proxyFactory.addAdvice(this.disruptorAdvice); + return proxyFactory.getProxy(getClass().getClassLoader()); + } + + private boolean hasDisruptorAnnotation(final Object bean) { + if (AnnotationUtils.findAnnotation(bean.getClass(), Disrupt.class) != null) { + return true; + } + final AtomicBoolean annotationPresent = new AtomicBoolean(false); + ReflectionUtils.doWithMethods(bean.getClass(), method -> { + if (AnnotationUtils.findAnnotation(method, Disrupt.class) != null) { + annotationPresent.set(true); + } + }); + return annotationPresent.get(); + } +} diff --git a/spring/src/main/java/org/incendo/disruptor/spring/package-info.java b/spring/src/main/java/org/incendo/disruptor/spring/package-info.java new file mode 100644 index 0000000..fb6c113 --- /dev/null +++ b/spring/src/main/java/org/incendo/disruptor/spring/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package org.incendo.disruptor.spring; + +import org.jspecify.annotations.NullMarked; diff --git a/spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..a6b2b9e --- /dev/null +++ b/spring/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,2 @@ +org.incendo.disruptor.spring.DisruptorAdvice +org.incendo.disruptor.spring.DisruptorBeanPostProcessor \ No newline at end of file diff --git a/spring/src/test/java/org/incendo/disruptor/test/DisruptorAdviceTest.java b/spring/src/test/java/org/incendo/disruptor/test/DisruptorAdviceTest.java new file mode 100644 index 0000000..cfbf1f8 --- /dev/null +++ b/spring/src/test/java/org/incendo/disruptor/test/DisruptorAdviceTest.java @@ -0,0 +1,55 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.disruptor.test; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@SpringBootTest +class DisruptorAdviceTest { + + @Autowired private TestService testService; + + @Test + void methodAnnotation() { + final RuntimeException runtimeException = assertThrows( + RuntimeException.class, + () -> this.testService.testMethod() + ); + assertThat(runtimeException).hasMessageThat().isEqualTo("method"); + } + + @Test + void classAnnotation() { + final RuntimeException runtimeException = assertThrows( + RuntimeException.class, + () -> this.testService.otherMethod() + ); + assertThat(runtimeException).hasMessageThat().isEqualTo("class"); + } +} diff --git a/spring/src/test/java/org/incendo/disruptor/test/TestApplication.java b/spring/src/test/java/org/incendo/disruptor/test/TestApplication.java new file mode 100644 index 0000000..814ed81 --- /dev/null +++ b/spring/src/test/java/org/incendo/disruptor/test/TestApplication.java @@ -0,0 +1,35 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.disruptor.test; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TestApplication { + + public static void main(final String[] args) { + SpringApplication.run(TestApplication.class, args); + } +} diff --git a/spring/src/test/java/org/incendo/disruptor/test/TestConfig.java b/spring/src/test/java/org/incendo/disruptor/test/TestConfig.java new file mode 100644 index 0000000..644f3ce --- /dev/null +++ b/spring/src/test/java/org/incendo/disruptor/test/TestConfig.java @@ -0,0 +1,47 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.disruptor.test; + +import org.incendo.disruptor.Disruptor; +import org.incendo.disruptor.trigger.DisruptionTrigger; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TestConfig { + + @Bean + Disruptor disruptor() { + return Disruptor.builder() + .group( + "method", + g -> g.config(c -> c.trigger(DisruptionTrigger.random(1f)) + .throwException(ctx -> new RuntimeException("method")))) + .group( + "class", + g -> g.config(c -> c.trigger(DisruptionTrigger.random(1f)) + .throwException(ctx -> new RuntimeException("class")))) + .build(); + } +} diff --git a/spring/src/test/java/org/incendo/disruptor/test/TestService.java b/spring/src/test/java/org/incendo/disruptor/test/TestService.java new file mode 100644 index 0000000..de98260 --- /dev/null +++ b/spring/src/test/java/org/incendo/disruptor/test/TestService.java @@ -0,0 +1,39 @@ +// +// MIT License +// +// Copyright (c) 2024 Incendo +// +// 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 org.incendo.disruptor.test; + +import org.incendo.disruptor.spring.Disrupt; +import org.springframework.stereotype.Service; + +@Disrupt("class") +@Service +public class TestService { + + @Disrupt("method") + public void testMethod() { + } + + public void otherMethod() { + } +} diff --git a/spring/src/test/resources/application.yml b/spring/src/test/resources/application.yml new file mode 100644 index 0000000..7ca5c05 --- /dev/null +++ b/spring/src/test/resources/application.yml @@ -0,0 +1,7 @@ +spring: + profiles: + active: test + +logging: + level: + org.incendo.disruptor: TRACE