@Scopeโ
The Scope of Bean is a way to define when Bean will be created and how it is managed by container.
Clawject provides @Scope
decorator to define a scope and have 3 built-in scopes:
singleton
and transient
, default value is singleton
.
If you wish to implement your own scope, you can do it by implementing Scope
interface.
Read more about it in Creating Scope section.
Singleton scope (default)โ
When you define a bean with the singleton scope, the container creates a single instance of that bean, all requests for that bean will return the same object, which is cached. Any modifications to the object will be reflected in all references to the bean. This scope is the default value if no other scope is specified.
- Declare a Bean with default singleton scope
- Declare Scope of Bean using decorator
class Foo {
name = 'foo';
}
class Bar {
constructor(public foo: Foo) {}
setName(): void {
this.foo.name = 'bar';
}
}
class Baz {
constructor(public foo: Foo) {}
}
@ClawjectApplication
class Application {
foo = Bean(Foo);
bar = Bean(Bar);
baz = Bean(Baz);
@PostConstruct
postConstruct(
bar: Bar,
baz: Baz,
) {
bar.setName();
console.log(bar.foo === baz.foo); // <- prints "true"
console.log(bar.foo.property); // <- prints "bar"
console.log(baz.foo.property); // <- prints "bar"
}
}
class Foo {
name = 'foo';
}
class Bar {
constructor(public foo: Foo) {}
setName(): void {
this.foo.name = 'bar';
}
}
class Baz {
constructor(public foo: Foo) {}
}
@ClawjectApplication
class Application {
@Scope("singleton")
foo = Bean(Foo);
bar = Bean(Bar);
baz = Bean(Baz);
@PostConstruct
postConstruct(
bar: Bar,
baz: Baz,
) {
bar.setName();
console.log(bar.foo === baz.foo); // <- prints "true"
console.log(bar.foo.property); // <- prints "bar"
console.log(baz.foo.property); // <- prints "bar"
}
}
Transient scopeโ
A Bean with the transient
scope will return a different instance every time it is requested from the container.
Methods decorated with @PreDestroy will not be called for beans with transient
scope.
class Foo {
name = 'foo';
}
class Bar {
constructor(public foo: Foo) {}
setName(): void {
this.foo.name = 'bar';
}
}
class Baz {
constructor(public foo: Foo) {}
}
@ClawjectApplication
class Application {
@Scope("transient")
foo = Bean(Foo);
bar = Bean(Bar);
baz = Bean(Baz);
@PostConstruct
postConstruct(
bar: Bar,
baz: Baz,
) {
bar.setName();
console.log(bar.foo === baz.foo); // <- prints "false"
console.log(bar.foo.property); // <- prints "bar"
console.log(baz.foo.property); // <- prints "foo"
}
}
Scope on @Configuration classโ
When you put @Scope
decorator over the @Configuration
or @ClawjectApplication
class,
it indicates that all the beans that are declared in context should have scope defined in decorator.
Let's have a look here:
class Foo {
constructor() {
console.log('Foo has been created');
}
}
@ClawjectApplication
@Scope('transient')
class Application {
foo = Bean(Foo);
@PostConstruct
postConstruct(
foo1: Foo, // <- logs "Foo has been created"
foo2: Foo, // <- logs "Foo has been created",
) {}
}
As we see, foo
bean will be created twice,
because it's requested 2 times and it inherits transient
scope from context.
Scope on Beansโ
We can also put @Scope
decorator over the bean declaration.
class Foo {
@PostConstruct
postConstruct() {
console.log('Foo bean has been created');
}
}
@ClawjectApplication
class Application {
@Scope('transient') foo = Bean(Foo);
@PostConstruct
postConstruct(
foo1: Foo, // <- logs "Foo bean has been created"
foo2: Foo, // <- logs "Foo bean has been created",
) {}
}
As you can see - we've defined scope on foo
bean, and foo was instantiated two times.
Combining @Scope on @Configuration and Beanโ
We can also combine @Scope
decorator @Configuration
and Bean
.
If Bean is decorated with @Scope
, it overrides the @Scope
on @Configuration
level for this bean,
if not - value from @Configuration
is used.
class Foo {
@PostConstruct
postConstruct() {
console.log('Foo bean has been created');
}
}
class Bar {
@PostConstruct
postConstruct() {
console.log('Bar bean has been created');
}
}
@ClawjectApplication
@Scope('transient')
class Application {
foo = Bean(Foo);
@Scope('singleton') bar = Bean(Bar);
@PostConstruct
postConstruct(
foo1: Foo, // <- logs "Foo bean has been created"
foo2: Foo, // <- logs "Foo bean has been created",
bar1: Bar, // <- logs "Bar bean has been created"
bar2: Bar, // <- logs nothing, because Bar is a singleton
) {}
}