Micronaut 介紹 Advice

2023-03-02 11:51 更新

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 = "")
  1. 介紹建議用Introduction注釋

  2. 添加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)
    }
}
  1. InterceptorBean 注釋用于將攔截器與 @Stub 注釋相關(guān)聯(lián)

  2. 該類使用 @Singleton 注釋并實現(xiàn) MethodInterceptor 接口

  3. @Stub 注釋的值是從上下文中讀取的,并嘗試將值轉(zhuǎn)換為返回類型

  4. 否則返回 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 提供的核心建議類型。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號