Skip to main content

Scopes

A Scope in ActiveJ Inject allows you to reuse instances. A scoped instances are independent of instances in other scopes. By default, every instance obtained from the Injector is a singleton. This means that it is cached, and a second attempt to retrieve an instance of the same type returns a cached instance. But there are situations where we need to recreate some instances as they are bound to some semantic scope (application scope, request scope, process scope).

For example, we may have a dedicated HTTP scope. Each request will be bound to the HTTP scope and each instance created within this scope is valid only for the lifetime of the HTTP request (the time between receiving an HTTP request and returning an HTTP response).

An Injector can "enter" the scope. This means that a new scoped Injector will be created from the main injector. This "scoped" injector will have a reference to the parent injector, so it will fall back to the parent injector in case it cannot obtain some instance from within its own scope.

Scopes can be nested. You can have a scope inside another scope, and so on. When you try to retrieve an instance from a nested scope injector, the innermost injector is queried first. If it fails to return an instance, the next upper scope injector will be queried and so on until it succeeds in returning an instance.

Defining scopes

A scope is represented by a special scope annotation. A scope annotation is a marker annotation (that is, it has no members or data), that is itself annotated with a special marker annotation @ScopeAnnotation.

This is how we can have define an annotation for an HTTP scope:

@ScopeAnnotation@Target(ElementType.METHOD)@Retention(RUNTIME)public @interface HttpScope {}

Then we can define a binding within the HTTP scope using the ModuleBuilder DSL:

bind(Integer.class).toInstance(123).in(HttpScope.class)

Another way to define a scoped binding is to use scope annotation with @Provides-annotated methods, as shown below:

@Provides@HttpScopeInteger integer() {    return 123;}
note

We have annotated the scope annotation with @Retention(RUNTIME) annotation becasue scopes are processed at the runtime.

The @Target(ElementType.METHOD) annotation is present because we use scope annotations on methods.

Entering a scope

To enter a particular scope, we use the Injector#enterScope(Scope) method, which returns a "scoped" injector.

For example, let's enter the HTTP scope defined earlier:

Injector scopedInjector = injector.enterScope(Scope.of(HttpScope.class));

Now we can use scopedInjector to retrieve instances from within HTTP scope.

You can find a full example of HTTP scope on Github