Introduction advice 与 Around advice 不同,因为它涉及提供实现而不是装饰。
介绍建议的示例包括为您实现持久性逻辑的 GORM 和 Spring Data。
Micronaut 的客户端注解是另一个引入建议的例子,其中 Micronaut 在编译时为你实现了 HTTP 客户端接口。
实现 Introduction 建议的方式与实现 Around 建议的方式非常相似。
您首先定义一个支持介绍建议的注释。举个例子,假设你想实现通知,为接口中的每个方法返回一个存根值(测试框架中的常见要求)。考虑以下 @Stub 注释:
Introduction Advice Annotation Example
Java |
Groovy |
Kotlin |
import io.micronaut.aop.Introduction;
import io.micronaut.context.annotation.Bean;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Introduction // (1)
@Bean // (2)
@Documented
@Retention(RUNTIME)
@Target({TYPE, ANNOTATION_TYPE, METHOD})
public @interface Stub {
String value() default "";
}
|
import io.micronaut.aop.Introduction
import io.micronaut.context.annotation.Bean
import java.lang.annotation.Documented
import java.lang.annotation.Retention
import java.lang.annotation.Target
import static java.lang.annotation.ElementType.ANNOTATION_TYPE
import static java.lang.annotation.ElementType.METHOD
import static java.lang.annotation.ElementType.TYPE
import static java.lang.annotation.RetentionPolicy.RUNTIME
@Introduction // (1)
@Bean // (2)
@Documented
@Retention(RUNTIME)
@Target([TYPE, ANNOTATION_TYPE, METHOD])
@interface Stub {
String value() default ""
}
|
import io.micronaut.aop.Introduction
import io.micronaut.context.annotation.Bean
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FILE
import kotlin.annotation.AnnotationTarget.FUNCTION
import kotlin.annotation.AnnotationTarget.PROPERTY_GETTER
import kotlin.annotation.AnnotationTarget.PROPERTY_SETTER
@Introduction // (1)
@Bean // (2)
@MustBeDocumented
@Retention(RUNTIME)
@Target(CLASS, FILE, ANNOTATION_CLASS, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER)
annotation class Stub(val value: String = "")
|
介绍建议用Introduction注释
添加Bean注解,使得所有用@Stub注解的类型都成为bean
前面示例中引用的 StubIntroduction 类必须实现 MethodInterceptor 接口,就像环绕通知一样。
以下是一个示例实现:
StubIntroduction
Java |
Groovy |
Kotlin |
import io.micronaut.aop.*;
import io.micronaut.core.annotation.Nullable;
import jakarta.inject.Singleton;
@Singleton
@InterceptorBean(Stub.class) // (1)
public class StubIntroduction implements MethodInterceptor<Object, Object> { // (2)
@Nullable
@Override
public Object intercept(MethodInvocationContext<Object, Object> context) {
return context.getValue( // (3)
Stub.class,
context.getReturnType().getType()
).orElse(null); // (4)
}
}
|
import io.micronaut.aop.MethodInterceptor
import io.micronaut.aop.MethodInvocationContext
import io.micronaut.aop.InterceptorBean
import io.micronaut.core.annotation.Nullable
import jakarta.inject.Singleton
@Singleton
@InterceptorBean(Stub) // (1)
class StubIntroduction implements MethodInterceptor<Object,Object> { // (2)
@Nullable
@Override
Object intercept(MethodInvocationContext<Object, Object> context) {
context.getValue( // (3)
Stub,
context.returnType.type
).orElse(null) // (4)
}
}
|
import io.micronaut.aop.*
import jakarta.inject.Singleton
@Singleton
@InterceptorBean(Stub::class) // (1)
class StubIntroduction : MethodInterceptor<Any, Any> { // (2)
override fun intercept(context: MethodInvocationContext<Any, Any>): Any? {
return context.getValue<Any>( // (3)
Stub::class.java,
context.returnType.type
).orElse(null) // (4)
}
}
|
InterceptorBean 注释用于将拦截器与 @Stub 注释相关联
该类使用 @Singleton 注释并实现 MethodInterceptor 接口
@Stub 注释的值是从上下文中读取的,并尝试将值转换为返回类型
否则返回 null
现在要在应用程序中使用此介绍建议,请使用 @Stub 注释您的抽象类或接口:
StubExample
Java |
Groovy |
Kotlin |
@Stub
public interface StubExample {
@Stub("10")
int getNumber();
LocalDateTime getDate();
}
|
@Stub
interface StubExample {
@Stub("10")
int getNumber()
LocalDateTime getDate()
}
|
@Stub
interface StubExample {
@get:Stub("10")
val number: Int
val date: LocalDateTime?
}
|
所有抽象方法都委托给要实现的 StubIntroduction 类。
以下测试演示了 StubIntroduction 的行为:
Testing Introduction Advice
Java |
Groovy |
Kotlin |
StubExample stubExample = applicationContext.getBean(StubExample.class);
assertEquals(10, stubExample.getNumber());
assertNull(stubExample.getDate());
|
when:
def stubExample = applicationContext.getBean(StubExample)
then:
stubExample.number == 10
stubExample.date == null
|
val stubExample = applicationContext.getBean(StubExample::class.java)
stubExample.number.shouldBe(10)
stubExample.date.shouldBe(null)
|
注意如果introduction advice不能实现方法,调用MethodInvocationContext的proceed方法。这让其他引入通知拦截器实现该方法,如果没有通知可以实现该方法,将抛出 UnsupportedOperationException。
此外,如果存在多个引入通知,您可能希望覆盖 MethodInterceptor 的 getOrder() 方法以控制通知的优先级。
以下部分介绍了 Micronaut 提供的核心建议类型。
更多建议: