#
Lazy Proxies
Parsley supports lazy proxies, a powerful feature that allows for the delayed activation of services. A lazy proxy acts as a placeholder for a dependency, deferring its creation until it’s needed. This is particularly useful for services that are expensive to create or may not always be required immediately.
Once the service is activated, the lazy proxy retains the instance, ensuring that subsequent calls to the Value() method return the same instance. This balances performance and resource management, particularly in complex applications.
#
Example
In this example, we register a Greeter
service using a lazy proxy via the RegisterLazy[T]
method. The NewGreeterFactory
function is passed as the factory for creating Greeter
instances, and the LifetimeTransient
scope is used, meaning a new instance would typically be created each time.
package main
import (
"context"
"github.com/matzefriedrich/parsley-docs/examples/resolving-services/internal"
"github.com/matzefriedrich/parsley/pkg/features"
"github.com/matzefriedrich/parsley/pkg/registration"
"github.com/matzefriedrich/parsley/pkg/resolving"
"github.com/matzefriedrich/parsley/pkg/types"
)
func main() {
registry := registration.NewServiceRegistry()
features.RegisterLazy[internal.Greeter](registry, internal.NewGreeterFactory("Hi"), types.LifetimeTransient)
resolver := resolving.NewResolver(registry)
ctx := resolving.NewScopedContext(context.Background())
lazy, _ := resolving.ResolveRequiredService[features.Lazy[internal.Greeter]](resolver, ctx)
greeter := lazy.Value()
greeter.SayHello("John", true)
}
However, the Greeter
instance is not created immediately using a lazy proxy. Instead, a Lazy[Greeter]
proxy is resolved, and the actual Greeter
instance is only created when lazy.Value()
is called for the first time. This instance is then cached within the proxy, ensuring that the same Greeter
object is returned on subsequent calls to Value()
.
#
Benefits and use cases
Lazy proxies are ideal for optimizing the performance of applications where certain dependencies are resource-intensive to create but may not always be needed immediately. By deferring the creation of such dependencies until they are required, you can improve startup times and reduce unnecessary resource consumption.
This feature is especially useful in scenarios involving complex object graphs, optional dependencies, or services that are conditionally used based on runtime factors.