Micronaut Scopes

2023-02-27 15:02 更新

Micronaut 具有基于 JSR-330 的可擴展 bean 作用域機制。支持以下默認(rèn)范圍:

內(nèi)置范圍

表 1. Micronaut 內(nèi)置范圍
類型 描述

@Singleton

Singleton 作用域表示將只存在一個 bean 實例

@Context

Context scope表示bean會和ApplicationContext同時創(chuàng)建(eager initialization)

@Prototype

Prototype作用域表示每次注入時都會創(chuàng)建一個新的bean實例

@Infrastructure

Infrastructure 作用域表示不能使用 @Replaces 覆蓋或替換的 bean,因為它對系統(tǒng)的功能至關(guān)重要。

@ThreadLocal

@ThreadLocal 范圍是一個自定義范圍,它通過 ThreadLocal 為每個線程關(guān)聯(lián)一個 bean

@Refreshable

@Refreshable 范圍是一個自定義范圍,它允許通過 /refresh 端點刷新 bean 的狀態(tài)。

@RequestScope

@RequestScope 作用域是一個自定義作用域,表示創(chuàng)建了一個新的 bean 實例并與每個 HTTP 請求相關(guān)聯(lián)

@Prototype 注解是@Bean 的同義詞,因為默認(rèn)作用域是原型。

可以通過定義實現(xiàn) CustomScope 接口的 @Singleton bean 來添加其他范圍。

請注意,當(dāng)啟動 ApplicationContext 時,默認(rèn)情況下 @Singleton-scoped beans 是延遲和按需創(chuàng)建的。這是為了優(yōu)化啟動時間而設(shè)計的。

如果這對您的用例造成問題,您可以選擇使用 @Context 注釋,它將對象的生命周期綁定到 ApplicationContext 的生命周期。換句話說,當(dāng) ApplicationContext 啟動時,您的 bean 將被創(chuàng)建。

或者,使用 @Parallel 注釋任何 @Singleton-scoped bean,這允許在不影響整體啟動時間的情況下并行初始化 bean。

如果您的 bean 未能并行初始化,應(yīng)用程序?qū)⒆詣雨P(guān)閉。

單例的急切初始化

在某些情況下,@Singleton bean 的急切初始化可能是可取的,例如在 AWS Lambda 上,分配給 Lambda 構(gòu)建的 CPU 資源多于執(zhí)行。

您可以指定是否使用 ApplicationContextBuilder 接口預(yù)先初始化 @Singleton-scoped bean:

啟用單例的急切初始化

public class Application {

    public static void main(String[] args) {
        Micronaut.build(args)
            .eagerInitSingletons(true) (1)
            .mainClass(Application.class)
            .start();
    }
}
  1. 將 eager init 設(shè)置為 true 會初始化所有單例

當(dāng)您在無服務(wù)器函數(shù)等環(huán)境中使用 Micronaut 時,您將沒有應(yīng)用程序類,而是擴展了 Micronaut 提供的類。在這些情況下,Micronaut 提供了一些方法,您可以重寫這些方法來增強 ApplicationContextBuilder

覆蓋 newApplicationContextBuilder()

public class MyFunctionHandler extends MicronautRequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
...
    @Nonnull
    @Override
    protected ApplicationContextBuilder newApplicationContextBuilder() {
        ApplicationContextBuilder builder = super.newApplicationContextBuilder();
        builder.eagerInitSingletons(true);
        return builder;
    }
    ...
}

@ConfigurationReader beans,例如@EachProperty 或@ConfigurationProperties 是單例bean。要急切地初始化配置但保持其他 @Singleton-scoped bean 創(chuàng)建惰性,請使用 eagerInitConfiguration:

啟用配置的急切初始化

public class Application {

    public static void main(String[] args) {
        Micronaut.build(args)
            .eagerInitConfiguration(true) (1)
            .mainClass(Application.class)
            .start();
    }
}
  1. 將 eager init 設(shè)置為 true 會初始化所有配置讀取器 bean。

可刷新 Scope

Refreshable 范圍是一個自定義范圍,允許通過以下方式刷新 bean 的狀態(tài):

  • /refresh endpoint.
  • RefreshEvent 的發(fā)布。

以下示例說明了 @Refreshable 范圍行為。

 Java Groovy  Kotlin 
@Refreshable // (1)
public static class WeatherService {
    private String forecast;

    @PostConstruct
    public void init() {
        forecast = "Scattered Clouds " + new SimpleDateFormat("dd/MMM/yy HH:mm:ss.SSS").format(new Date());// (2)
    }

    public String latestForecast() {
        return forecast;
    }
}
@Refreshable // (1)
static class WeatherService {

    String forecast

    @PostConstruct
    void init() {
        forecast = "Scattered Clouds ${new SimpleDateFormat("dd/MMM/yy HH:mm:ss.SSS").format(new Date())}" // (2)
    }

    String latestForecast() {
        return forecast
    }
}
@Refreshable // (1)
open class WeatherService {
    private var forecast: String? = null

    @PostConstruct
    open fun init() {
        forecast = "Scattered Clouds " + SimpleDateFormat("dd/MMM/yy HH:mm:ss.SSS").format(Date())// (2)
    }

    open fun latestForecast(): String? {
        return forecast
    }
}
  1. WeatherService 使用 @Refreshable 范圍進行注釋,該范圍存儲一個實例,直到觸發(fā)刷新事件

  2. forecast 屬性的值在創(chuàng)建 bean 時設(shè)置為固定值,并且在刷新 bean 之前不會更改

如果調(diào)用 latestForecast() 兩次,您將看到相同的響應(yīng),例如“Scattered Clouds 01/Feb/18 10:29.199”。

當(dāng)調(diào)用 /refresh 端點或發(fā)布 RefreshEvent 時,該實例將失效,并在下次請求該對象時創(chuàng)建一個新實例。例如:

 Java Groovy  Kotlin 
applicationContext.publishEvent(new RefreshEvent());
applicationContext.publishEvent(new RefreshEvent())
applicationContext.publishEvent(RefreshEvent())

元注釋的范圍

可以在元注釋上定義范圍,然后您可以將其應(yīng)用于您的類??紤]以下示例元注釋:

Driver.java Annotation

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

import jakarta.inject.Singleton;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Requires(classes = Car.class) // (1)
@Singleton // (2)
@Documented
@Retention(RUNTIME)
public @interface Driver {
}
import io.micronaut.context.annotation.Requires

import jakarta.inject.Singleton
import java.lang.annotation.Documented
import java.lang.annotation.Retention

import static java.lang.annotation.RetentionPolicy.RUNTIME

@Requires(classes = Car.class) // (1)
@Singleton // (2)
@Documented
@Retention(RUNTIME)
@interface Driver {
}
import io.micronaut.context.annotation.Requires
import jakarta.inject.Singleton
import kotlin.annotation.AnnotationRetention.RUNTIME

@Requires(classes = [Car::class]) // (1)
@Singleton // (2)
@MustBeDocumented
@Retention(RUNTIME)
annotation class Driver
  1. 該范圍使用 Requires 聲明對 Car 類的要求

  2. 注解聲明為@Singleton

在上面的示例中,@Singleton 注釋應(yīng)用于 @Driver 注釋,這導(dǎo)致每個用 @Driver 注釋的類都被視為單例。

請注意,在這種情況下,無法在應(yīng)用注釋時更改范圍。例如,以下不會覆蓋@Driver 聲明的范圍并且是無效的:

Declaring Another Scope

@Driver
@Prototype
class Foo {}

對于可覆蓋的范圍,請改為使用 @Driver 上的 DefaultScope 批注,它允許在不存在其他范圍的情況下指定默認(rèn)范圍:

Using @DefaultScope

 Java Groovy  Kotlin 
@Requires(classes = Car.class)
@DefaultScope(Singleton.class) (1)
@Documented
@Retention(RUNTIME)
public @interface Driver {
}
@Requires(classes = Car.class)
@DefaultScope(Singleton.class) (1)
@Documented
@Retention(RUNTIME)
@interface Driver {
}
@Requires(classes = [Car::class])
@DefaultScope(Singleton::class) (1)
@Documented
@Retention(RUNTIME)
annotation class Driver
  1. 如果未指定,則 DefaultScope 聲明要使用的范圍


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號