We are using Karaf
and a number of OSGI Blueprint services
to implement a system.
Is it possible to make a "BundleListener"
type of bundle that, when present in the OSGI
container, decorates our Blueprint services
with a proxy so bundles referring these services will call the proxy instead?
(I guess this could be accomplished either by somehow adding the proxy in front of the service already in the Service Registry, or by changing the reference obtained by the referring bundle - ServiceTracker.addingService
style)
The standard way to do these hacks is to use the service hooks in the OSGi core framework. The hooks allow you to remove a service from the view of one or more bundles. You can then register another service that proxies the first service and that is not removed from the bundle's view.
Existing:
+----------+ +----------+
| register |------<|------| using |
+----------+ +----------+
Proxied
+----------+ hide +----------+
| register |------<|-+--X-| using |---|>---+ proxied
+----------+ | +----------+ |
| |
| +----------+ |
+----| manager |--------+
+----------+
Though at first a bit odd, this "remove from view" capability allows you to control in detail what service a bundle is exposed to while keeping the overall complexity minimal. See chapter 55 in the OSGi 5.0.0 Core. Section 55.3.1 details this proxying.
<soapbox>
I call these things hacks because proxies this way have bad runtime temporal ordering qualities. If your manager bundle (the one that hides and creates the proxies) is started later than the bundle using the service you're in trouble since the using bundle is temporarily exposed to the non-proxied service.
Though there are ways you to solve start ordering this problem, they all basically suck since you now have a undeclared (ordering) dependency. It is thus MUCH better to ensure that the bundle that uses the proxy has a special dependency, like another service type or a special service property. Since the dependency then is explicit, you have no more worries about ordering, the temporal dependency has now become an ordinary service dependency problem which is handled very well by DS and other service managers in OSGi.
Using property/other type to proxy
+----------+ +----------+ proxied=true
| register | | using |---|>---+
+----------+ +----------+ |
| |
| +----------+ |
+-----------<|------| manager |--------+
+----------+
You obviously do not want to modify the bundle that registers the service nor the bundle that uses the service since this would kill the whole idea of a reusable aspect. The programmers of the registering/using bundles should be blissfully unaware of the manager's scheme. So how do you se the filter on the using bundle?
If you use Declarative Services (DS), then you're in luck! With DS you can set a filter on a service reference through Configuration Admin with the 'target.' configuration property. So the manager bundle sees a service to be proxied, it registers a second service with a special property (e.g. 'proxied=true'). The using bundle then has a filter set through Configuration Admin DS' target reference property like '(proxied=*)'.
</soapbox>
Although not implemented as a proxy, a Blueprint Interceptor might do what you want; you can intercept method invocations before or after the call to the original bean. I assume this is what you'd be doing with your proxy anyway. The Aries Blueprint implementation in Karaf should definitely support interceptors. However, I can't find good documentation or examples outside the Aries source itself, which makes this answer less useful than I'd hoped!
来源:https://stackoverflow.com/questions/16341488/can-i-inject-proxies-in-front-of-blueprint-services-published-by-other-bundles