Micronaut Bean 生命周期 Advice

2023-03-02 14:12 更新

有時您可能需要將建議應用于 bean 的生命周期。有 3 種類型的建議適用于這種情況:

  • 攔截 bean 的構造

  • 攔截 bean 的 @PostConstruct 調用

  • 攔截 bean 的 @PreDestroy 調用

Micronaut 通過允許定義額外的 @InterceptorBinding 元注解來支持這 3 個用例。

考慮以下注解定義:

AroundConstruct 示例

 Java Groovy  Kotlin 
import io.micronaut.aop.*;
import io.micronaut.context.annotation.Prototype;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@AroundConstruct // (1)
@InterceptorBinding(kind = InterceptorKind.POST_CONSTRUCT) // (2)
@InterceptorBinding(kind = InterceptorKind.PRE_DESTROY) // (3)
@Prototype // (4)
public @interface ProductBean {
}
import io.micronaut.aop.*
import io.micronaut.context.annotation.Prototype
import java.lang.annotation.*

@Retention(RetentionPolicy.RUNTIME)
@AroundConstruct // (1)
@InterceptorBinding(kind = InterceptorKind.POST_CONSTRUCT) // (2)
@InterceptorBinding(kind = InterceptorKind.PRE_DESTROY) // (3)
@Prototype // (4)
@interface ProductBean {
}
import io.micronaut.aop.AroundConstruct
import io.micronaut.aop.InterceptorBinding
import io.micronaut.aop.InterceptorBindingDefinitions
import io.micronaut.aop.InterceptorKind
import io.micronaut.context.annotation.Prototype

@Retention(AnnotationRetention.RUNTIME)
@AroundConstruct // (1)
@InterceptorBindingDefinitions(
    InterceptorBinding(kind = InterceptorKind.POST_CONSTRUCT), // (2)
    InterceptorBinding(kind = InterceptorKind.PRE_DESTROY) // (3)
)
@Prototype // (4)
annotation class ProductBean
  1. 添加@AroundConstruct 注釋以指示應該攔截構造函數(shù)

  2. @InterceptorBinding 定義用于指示應該發(fā)生@PostConstruct 攔截

  3. @InterceptorBinding 定義用于指示應該發(fā)生@PreDestroy 攔截

  4. 該 bean 被定義為 @Prototype,因此每個注入點都需要一個新實例

請注意,如果您不需要 @PostConstruct 和 @PreDestroy 攔截,您可以簡單地刪除這些綁定。

然后可以在目標類上使用 @ProductBean 注釋:

使用 AroundConstruct 元注釋

 Java Groovy  Kotlin 
import io.micronaut.context.annotation.Parameter;

import jakarta.annotation.PreDestroy;

@ProductBean // (1)
public class Product {
    private final String productName;
    private boolean active = false;

    public Product(@Parameter String productName) { // (2)
        this.productName = productName;
    }

    public String getProductName() {
        return productName;
    }

    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    @PreDestroy // (3)
    void disable() {
        active = false;
    }
}
import io.micronaut.context.annotation.Parameter
import jakarta.annotation.PreDestroy

@ProductBean // (1)
class Product {
    final String productName
    boolean active = false

    Product(@Parameter String productName) { // (2)
        this.productName = productName
    }

    @PreDestroy // (3)
    void disable() {
        active = false
    }
}
import io.micronaut.context.annotation.Parameter
import jakarta.annotation.PreDestroy

@ProductBean // (1)
class Product(@param:Parameter val productName: String ) { // (2)

    var active: Boolean = false
    @PreDestroy
    fun disable() { // (3)
        active = false
    }
}
  1. @ProductBean 注釋定義在 Product 類型的類上

  2. @Parameter 注解表明這個 bean 需要一個參數(shù)來完成構造

  3. 任何@PreDestroy 或@PostConstruct 方法在攔截器鏈中最后執(zhí)行

現(xiàn)在您可以為構造函數(shù)攔截定義 ConstructorInterceptor bean,為 @PostConstruct 或 @PreDestroy 攔截定義 MethodInterceptor bean。

以下工廠定義了一個 ConstructorInterceptor,它攔截 Product 實例的構造并將它們注冊到一個假設的 ProductService 中,首先驗證產(chǎn)品名稱:

定義構造函數(shù)攔截器

 Java Groovy  Kotlin 
import io.micronaut.aop.*;
import io.micronaut.context.annotation.Factory;

@Factory
public class ProductInterceptors {
    private final ProductService productService;

    public ProductInterceptors(ProductService productService) {
        this.productService = productService;
    }
}

@InterceptorBean(ProductBean.class)
ConstructorInterceptor<Product> aroundConstruct() { // (1)
    return context -> {
        final Object[] parameterValues = context.getParameterValues(); // (2)
        final Object parameterValue = parameterValues[0];
        if (parameterValue == null || parameterValues[0].toString().isEmpty()) {
            throw new IllegalArgumentException("Invalid product name");
        }
        String productName = parameterValues[0].toString().toUpperCase();
        parameterValues[0] = productName;
        final Product product = context.proceed(); // (3)
        productService.addProduct(product);
        return product;
    };
}
import io.micronaut.aop.*
import io.micronaut.context.annotation.Factory


@Factory
class ProductInterceptors {
    private final ProductService productService

    ProductInterceptors(ProductService productService) {
        this.productService = productService
    }
}

@InterceptorBean(ProductBean.class)
ConstructorInterceptor<Product> aroundConstruct() { // (1)
    return  { context ->
        final Object[] parameterValues = context.parameterValues // (2)
        final Object parameterValue = parameterValues[0]
        if (parameterValue == null || parameterValues[0].toString().isEmpty()) {
            throw new IllegalArgumentException("Invalid product name")
        }
        String productName = parameterValues[0].toString().toUpperCase()
        parameterValues[0] = productName
        final Product product = context.proceed() // (3)
        productService.addProduct(product)
        return product
    }
}
import io.micronaut.aop.*
import io.micronaut.context.annotation.Factory

@Factory
class ProductInterceptors(private val productService: ProductService) {
}

@InterceptorBean(ProductBean::class)
fun aroundConstruct(): ConstructorInterceptor<Product> { // (1)
    return ConstructorInterceptor { context: ConstructorInvocationContext<Product> ->
        val parameterValues = context.parameterValues // (2)
        val parameterValue = parameterValues[0]
        require(!(parameterValue == null || parameterValues[0].toString().isEmpty())) { "Invalid product name" }
        val productName = parameterValues[0].toString().uppercase()
        parameterValues[0] = productName
        val product = context.proceed() // (3)
        productService.addProduct(product)
        product
    }
}
  1. 定義了一個新的 @InterceptorBean,它是一個 ConstructorInterceptor

  2. 可以根據(jù)需要檢索和修改構造函數(shù)參數(shù)值

  3. 可以使用 proceed() 方法調用構造函數(shù)

定義攔截 @PostConstruct 和 @PreDestroy 方法的 MethodInterceptor 實例與為常規(guī)方法定義攔截器沒有什么不同。但是請注意,您可以使用傳遞的 MethodInvocationContext 來識別正在發(fā)生的攔截類型,并相應地調整代碼,如以下示例所示:

定義構造函數(shù)攔截器

 Java Groovy  Kotlin 
@InterceptorBean(ProductBean.class) // (1)
MethodInterceptor<Product, Object> aroundInvoke() {
    return context -> {
        final Product product = context.getTarget();
        switch (context.getKind()) {
            case POST_CONSTRUCT: // (2)
                product.setActive(true);
                return context.proceed();
            case PRE_DESTROY: // (3)
                productService.removeProduct(product);
                return context.proceed();
            default:
                return context.proceed();
        }
    };
}
@InterceptorBean(ProductBean.class) // (1)
MethodInterceptor<Product, Object> aroundInvoke() {
    return { context ->
        final Product product = context.getTarget()
        switch (context.kind) {
            case InterceptorKind.POST_CONSTRUCT: // (2)
                product.setActive(true)
                return context.proceed()
            case InterceptorKind.PRE_DESTROY: // (3)
                productService.removeProduct(product)
                return context.proceed()
            default:
                return context.proceed()
        }
    }
}
@InterceptorBean(ProductBean::class)
fun  aroundInvoke(): MethodInterceptor<Product, Any> { // (1)
    return MethodInterceptor { context: MethodInvocationContext<Product, Any> ->
        val product = context.target
        return@MethodInterceptor when (context.kind) {
            InterceptorKind.POST_CONSTRUCT -> { // (2)
                product.active = true
                context.proceed()
            }
            InterceptorKind.PRE_DESTROY -> { // (3)
                productService.removeProduct(product)
                context.proceed()
            }
            else -> context.proceed()
        }
    }
}
  1. 定義了一個新的 @InterceptorBean,它是一個 MethodInterceptor

  2. @PostConstruct攔截處理

  3. @PreDestroy攔截處理


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號