Common Service Registry

前端 未结 2 1246
孤城傲影
孤城傲影 2021-01-20 19:14

For a long time now we\'ve been fortunate enough to have the Common Service Locator (CSL) to resolve services from an unknown source. However, there has never been any conta

相关标签:
2条回答
  • 2021-01-20 19:49

    There are a number of tricks you can use to avoid having to depend on a specific IoC container throughout most of your code, the simplest of which is to use constructor injection. If you're dead-set on using a Service Locator pattern, just create your own Service Locator class, which wraps the actual IoC container kernel you're planning to use.

    That said, the point of an IoC container is to achieve "Inversion of Control": i.e. to move the control from the bottom levels to the top. This means that you need to have a point near the "top" (or "root") of your application that is actually aware of all the service implementations it's going to use, as well as your specific IoC implementation. This should be restricted to a handful of classes. Generally the "Context Root" of an application is the place where you will initialize your IoC container and Service Locator. There should be a specific module or group of modules that takes care of setting up all your bindings.

    If you want to allow for plugins, you need to create a specific API for them to use and conform to. Simply allowing other packages to define new IoC bindings willy-nilly is a recipe for disaster, since you don't know how well these different packages will play together.

    ASP.NET MVC 3 is a good example of this. They have specific service factory locators that you override within the Global Application_Start method. In order to implement one of these factories, you have to abide by the API that they provide you. But you can create an implementation that uses any IoC container you want, or none at all. You're not changing "bindings" at all. You're just telling the framework that for the current application, you want it to use "this factory" to create controllers or model metadata providers instead of using the default factory.

    To use another example that's more applicable to your specific example, let's take the case of an ISearchProvider. You might have a built-in LuceneProvider, and maybe one of your plugins can provide a GoogleProvider. Which of these providers do you want to use? Does the mere presence of the GoogleProviderPlugin mean that the LuceneProvider is no longer available? Should searches somehow combine the results of both of these providers? Should the user be able to choose one or more providers from within the user interface?

    Regardless of the answer to these questions, the ultimate point is that you want your application to control this, not the plugin. Rather than giving the plugin carte blanche to muck with your DI bindings, you want to tell the plugin, "I am allowing you to define additional search providers, and here is how you can register them." They can be registered by a variety of means, including class annotations/attributes or the mere presence of a class that implements a given interface. But the important point is that there is an API that specifically defines what they can "plug in" to, and what you require of anyone who builds a plugin.

    Now, if the GoogleProvider has dependencies that are defined within the plugin, that plugin can resolve those dependencies however it wants. Hopefully it will use some kind of IoC container, but if it doesn't, that's no skin off your back. You can still be agnostic as to the kind of container they use, if any.

    If there are certain services that you expect a SearchProvider to require, you can either include those services, or factories for those services, as part of the initialization API for your plugin. That way your plugin can access those services without needing to be aware of your application's IoC container.

    0 讨论(0)
  • 2021-01-20 20:07

    The most decoupled (and the best) solution you can achieve is to realize that loose coupling is best achieved through principles and patterns instead of particular technologies.

    Use Constructor Injection throughout your application. The ensures that none of your application layers need reference any container at all. Then compose the entire application graph in the root of the application.

    You don't need to use a DI Container for this, but if you choose to use a DI Container, you must isolate it to the Composition Root. This means that if you later decide to migrate to a different container, you only need to change the Composition Root. However, Poor Man's DI is also an option.

    0 讨论(0)
提交回复
热议问题