当前位置: 首页 > 工具软件 > Micronaut > 使用案例 >

micronaut 微服务框架的Scopes

席烨
2023-12-01


Micronaut具有一个基于JSR-330的可扩展的bean作用域机制。

支持的作用域

类型描述
@SingletonSingleton作用域表示只有一个Bean的实例会存在
@ContextContext作用域表示Bean将与ApplicationContext同时创建(eager initialization)。
@Prototype原型作用域表示每次注入Bean时都会创建一个新的实例。
@Infrastructure基础设施作用域表示一个不能被重写或使用@Replaces替换的Bean,因为它对系统的运行至关重要。
@ThreadLocal@ThreadLocal 作用域是一个自定义作用域,它通过ThreadLocal为每个线程关联一个Bean。
@Refreshable@Refreshable 作用域是一个自定义的作用域,它允许通过 /refresh 端点来刷新 bean 的状态。
@RequestScope@RequestScope作用域是一个自定义作用域,它表示Bean的一个新实例被创建并与每个HTTP请求相关联。

@Prototype注解是@Bean的同义词,因为默认作用域是prototype。

可以通过定义一个实现CustomScope接口的@Singleton bean来添加额外的作用域。

请注意,在启动ApplicationContext时,默认情况下,@Singleton范围的Bean会被懒散地按需创建。这是为优化启动时间而设计的。

如果这对你的用例来说是个问题,你可以选择使用@Context注解,将你的对象的生命周期与ApplicationContext的生命周期绑定在一起。换句话说,当ApplicationContext启动时,你的Bean将被创建。

另外,用@Parallel注解任何@Singleton范围的Bean,它允许并行初始化你的Bean而不影响整体启动时间。

如果你的Bean未能并行初始化,应用程序将被自动关闭。

Singletons 的 Eager 初始化

在某些情况下,@Singleton Bean的Eager 初始化可能是可取的,例如在AWS Lambda上,更多的CPU资源被分配给Lambda构建而不是执行。
你可以使用ApplicationContextBuilder接口指定是否Eager初始化@Singleton范围的Bean。

Application.java 类示例代码

public class Application {

    public static void main(String[] args) {
        Micronaut.build(args)
            .eagerInitSingletons(true) 
            .mainClass(Application.class)
            .start();
    }
}

将eager init设置为true可以初始化所有的singletons。

无服务器Functions时的示例代码

当你在诸如无服务器Functions的环境中使用Micronaut时,你将不会有一个Application类,而是扩展一个Micronaut提供的类。在这些情况下,Micronaut提供了一些方法,你可以重写这些方法来增强ApplicationContextBuilder的功能。

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

@ConfigurationReader Bean的示例代码

@ConfigurationReader Bean,如@EachProperty或@ConfigurationProperties是singleton Bean。要想Eager初始化配置,同时保持其他@Singleton范围的Bean的懒惰初始化,请使用eagerInitConfiguration。

public class Application {

    public static void main(String[] args) {
        Micronaut.build(args)
            .eagerInitConfiguration(true) 
            .mainClass(Application.class)
            .start();
    }
}

Refreshable 作用域

Refreshable 作用域是一个自定义作用域,它允许通过以下方式刷新 bean 的状态。

  • /refresh 端点。
  • 发布一个 RefreshEvent。

@Refreshable 作用域行为的示例代码

@Refreshable
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());// 
    }

    public String latestForecast() {
        return forecast;
    }
}

WeatherService被注解了@Refreshable范围,它存储了一个实例,直到触发了一个刷新事件。
当Bean被创建时,预测属性的值被设置为一个固定值,在Bean被刷新之前不会发生变化。
如果你调用 latestForecast() 两次,你会看到相同的响应。
当调用/refresh端点或发布RefreshEvent时,该实例会失效,并在下次请求该对象时创建一个新的实例。
比如说,

applicationContext.publishEvent(new RefreshEvent());

Meta Annotations(元注解)的作用域

可以在Meta Annotations(元注解)上定义作用域,然后将其应用于你的类。

Driver.java 类示例代码1

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声明了对一个Car类的需求
@Requires(classes = Car.class)
@Singleton
@Documented
@Retention(RUNTIME)
public @interface Driver {
}

@Singleton 注解被应用到 @Driver 注解上,这导致每个被 @Driver 注解的类都被看作是单例。

注意,在这种情况下,当注解被应用时,不可能改变范围。例如,下面的内容不会覆盖 @Driver 所声明的作用域,是无效的。

Foo.java 类示例代码

声明另一个作用域,

@Driver
@Prototype
class Foo {}

Driver.java 类示例代码2

为了使作用域可被覆盖,请在 @Driver 上使用 DefaultScope 注解,它允许在没有其他作用域时指定一个默认的作用域。

@Requires(classes = Car.class)
@DefaultScope(Singleton.class) 
@Documented
@Retention(RUNTIME)
public @interface Driver {
}

完结!

 类似资料: