Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [sisu-users] Bean locator implementation

On 21 Oct 2013, at 05:33, Shahim Essaid wrote:

> Hi Stuart,
> 
> I am new to Guice and Sisu and I'm starting to look through the source code to gain a better understanding of both. I have few basic questions about the implementation of the default bean locator.
> 
> The current implementation uses a "mediator" pattern and I understand it. But, it appears that this could be simplified to the usual "listener/observer" pattern and the specific observer implementation could mediate to other objects when needed without having the locator aware of this.

Hi Shahim,

The mediator pattern was designed to minimise client-side knowledge of a central service/locator; and to remove the need to register, track, and unregister listeners from user code. It lets us tie the life of the mediator to the life of the watcher object, so we can automatically unregister the mediator when the watcher disappears (ie. eligible for GC). This is important when the registration is triggered behind the scenes by Guice injection, because there is no other way to know that a mediator is no longer required without exposing some knowledge of the locator to user code and getting the client to track/manage the listener.

Btw ideally components should not use the BeanLocator API directly, preferring instead the org.eclipse.sisu types and standard JSR330 injection. For example, using @Named on your mediator implementation means that Sisu will automatically register and de-register the mediator as required, you don't need to track it yourself. See http://eclipse.org/sisu/docs/api/org.eclipse.sisu.inject/reference/org/eclipse/sisu/Mediator.html for examples.

Moving back to the observer pattern would break this automatic de-registration, and force clients to hold onto listeners (and know about their component's lifecycle) so they can be removed and cleared up.

> Also, the current implementation doesn't allow for the removal of a registered mediator.

That's by design, the registration expires when the watcher is no longer reachable (ie. when it becomes eligible for GC). Same with the dynamic sequences returned by the locate method, the contents of those sequences continue to update until the sequence is no longer reachable. While this may look odd when dealing directly with the BeanLocator API, it hopefully makes more sense when you consider JSR330 components that have these sequences injected into them (eg. as simple @Inject List<Widget> widgets) who then don't need to know anything about the backing bean locator.

> Another issue is that the current implementation is final and it is hard coded in few other classes.

The use of final is also by design. The codebase was written to prefer composition over inheritance (http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance) so by default implementations are locked down as much as possible, but this doesn't mean you can't change the behaviour.

The current default implementation is only referenced in a couple of classes:

	a)  the @ImplementedBy annotation on MutableBeanLocator, which is a hint to Guice to use this as the implementation unless someone explicitly binds the interface to another implementation
	b)  as a static injection request in ChildWireModule - this invokes staticAutoPublish which bootstraps whatever implementation is bound to MutableBeanLocator using the current Guice injector
	c)  the default implementation used in the example OSGi Activator (SisuActivator)

Of these only the last one (SisuActivator) is a hard reference, but this will be made customisable. The other two references actually don't enforce use of the default implementation.

> This makes it difficult to experiment with new bean locator implementations when needed. 

If you want to extend the DefaultBeanLocator implementation you can use the BindingPublisher SPI to contribute bindings; this uses a lazy pub-sub model to defer searching for bindings until they are definitely required, which is useful when working with remote/large registries. You can also use a delegation approach to intercept requests and responses. Similarly the space and wire modules now support custom strategies for finding, binding, and wiring classes. Individual classes and packages can also be (re-)used independently since they are designed with minimal coupling in mind.

If you find there's something else in the locator that you need to customise then feel free to mention it on the sisu-dev list along with some example use-cases.

> As I said, I'm still very new to Sisu. However, would it be useful to consider:
> 1. The observer pattern (with addition and removal of listeners) for the locator?

IMHO this would be taking a backward step, as the mediator pattern was originally developed in response to limitations of the observer pattern. But I'm happy discuss this further on sisu-dev or the wiki.

> 2  Have a configuration file (or some other runtime configuration mechanism) to specify the locator implementation to allow for custom implementations when needed, and to avoid hard coding this in other classes? 

In general the preferred approach is to explicitly bind the locator in your Guice module when bootstrapping Sisu. You could always write a Guice module that read from a configuration file.

Also if you want separate injectors to share components and collaborate then you need to bind to the same locator instance in both injectors (this will be covered soon in the OSGi tutorial)

> 3. Make the locator and few of the related classes non-final to allow for customization if needed?  

There would have to be a clear, definite need to extend them that couldn't be satisfied by composition. Delegation and the Binding pub-sub SPI have catered for every need so far.

HTH

--
Cheers, Stuart

> Best,
> Shahim
> _______________________________________________
> sisu-users mailing list
> sisu-users@xxxxxxxxxxx
> https://dev.eclipse.org/mailman/listinfo/sisu-users



Back to the top