Introduction advice 與 Around advice 不同,因為它涉及提供實現(xiàn)而不是裝飾。
介紹建議的示例包括為您實現(xiàn)持久性邏輯的 GORM 和 Spring Data。
Micronaut 的客戶端注解是另一個引入建議的例子,其中 Micronaut 在編譯時為你實現(xiàn)了 HTTP 客戶端接口。
實現(xiàn) Introduction 建議的方式與實現(xiàn) Around 建議的方式非常相似。
您首先定義一個支持介紹建議的注釋。舉個例子,假設(shè)你想實現(xiàn)通知,為接口中的每個方法返回一個存根值(測試框架中的常見要求)??紤]以下 @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 類必須實現(xiàn) MethodInterceptor 接口,就像環(huán)繞通知一樣。
以下是一個示例實現(xiàn):
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 注釋相關(guān)聯(lián)
該類使用 @Singleton 注釋并實現(xiàn) MethodInterceptor 接口
@Stub 注釋的值是從上下文中讀取的,并嘗試將值轉(zhuǎn)換為返回類型
否則返回 null
現(xiàn)在要在應(yīng)用程序中使用此介紹建議,請使用 @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?
}
|
所有抽象方法都委托給要實現(xiàn)的 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不能實現(xiàn)方法,調(diào)用MethodInvocationContext的proceed方法。這讓其他引入通知攔截器實現(xiàn)該方法,如果沒有通知可以實現(xiàn)該方法,將拋出 UnsupportedOperationException。
此外,如果存在多個引入通知,您可能希望覆蓋 MethodInterceptor 的 getOrder() 方法以控制通知的優(yōu)先級。
以下部分介紹了 Micronaut 提供的核心建議類型。
更多建議: