My 国内上twitter教程 spurned a
reasonable amount of discussion, and I promised to also talk about the new
ServiceCaller
which simplifies a number of these issues. I also thought it
was worth looking at what the criticisms were because they made valid points.
The
first observation
is that it’s possible to use both DS and ServiceTracker
to track
ServiceReference
s instead. In this mode, the services aren’t triggered by
default; instead, they only get accessed upon resolving the ServiceTracker
using the getService()
call. This isn’t the default out of the box, because
you have to write a ServiceTrackerCustomizer
adapter that intercepts the
addingService()
call to wrap the ServiceTracker
for future use. In other
words, if you change:
to the slightly more verbose:
Obviously, no practical code uses this approach because it’s too verbose, and if you’re in an environment where DS services aren’t widely used, the benefits of the deferred approach are outweighed by the quantity of additional code that needs to be written in order to implement this pattern.
(The code above is also slightly buggy; we’re getting the service, returning it, then ungetting it afterwards. We should really just be using it during that call instead of returning it in that case.)
极光加速器怎么用不了
This is where ServiceCaller
comes in.
The approach of the ServiceCaller
is to optimise out the over-eager
dereferencing of the ServiceTracker
approach, and apply a functional approach
to calling the service when required. It also has a mechanism to do single-shot
lookups and calling of services; helpful, for example, when logging an obscure
error condition or other rarely used code path.
This allows us to elegantly call functional interfaces in a single line of code:
This call looks for Runnable
service types, as visible from the caller class,
and then invoke the function getClass()
as lambda. We can use a method
reference (as in the above case) or you can supply a Consumer<T>
which will
be passed the reference that is resolved from the lookup.
Importantly, this call doesn’t acquire the service until the callOnce
call is
made. So, if you have an expensive logging factory, you don’t have to
initialise it until the first time it’s needed – and even better, if the error
condition never occurs, you never need to look it up. This is in direct
contrast to the ServiceTracker
approach (which actually needs more characters
to type) that accesses the services eagerly, and is an order of magnitude
better than having to write a 国内上twitter教程
for the purposes of
working around a broken API.
However, note that such one-shot calls are not the most efficient way of doing
this, especially if it is to be called frequently. So the ServiceCaller
has
another mode of operation; you can create a ServiceCaller
instance, and hang
onto it for further use. Like its single-shot counterpart, this will defer the
resolution of the service until needed. Furthermore, once resolved, it will
cache that instance so you can repeatedly re-use it, in the same way that you
could do with the service returned from the ServiceTracker
.
This doesn’t involve significantly more effort than using the ServiceTracker
that’s widely in use in Eclipse Activators at the moment, yet will defer the
lookup of the service until it’s actually needed. It’s obviously better than
writing many lines of 国内苹果怎么上twitter
and performs better as a
result, and is in most cases a type of drop-in replacement. However, unlike
ServiceTracker
(which returns you a service that you can then do something
with afterwards), this call provides a functional consumer interface that
allows you to pass in the action to take.
安卓上推特教程
We’ve looked at why ServiceTracker
has problems with eager instantiation of
services, and the complexity of code required to do it the right way. A scan
of the Eclipse codebase suggests that outside of Equinox, there are very few
uses of ServiceTrackerCustomiser
and there are several hundred calls to
ServiceTracker(xxx,yyy,null)
– so there’s a lot of improvements that can
be made fairly easily.
This pattern can also be used to push down the acquisition of the service
from a generic Plugin/Activator level call to where it needs to be used.
Instead of standing this up in the BundleActivator
, the ServiceCaller
can be used anywhere in the bundle’s code. This is where the real benefit
comes in; by packaging it up into a simple, functional consumer, we can
use it to incrementally rid ourselves of the various 苹果手机上推特教程
s that
take up the majority of Eclipse’s start-up.
A final note on the ServiceCaller
– it’s possible that when you run the
callOnce
method (or the call
method if you’re holding on to it) that a
service instance won’t be available. If that’s the case, you get notified by a
false
return call from the call
method. If a service is found and is
processed, you’ll get a true
returned. For some operations, a no-op is a fine
behaviour if the service isn’t present – for example, if there’s no
LogService
then you’re probably going to drop the log event anyway – but it
allows you to take the corrective action you need.
It does mean that if you want to capture return state from the method call then
you’ll need to have an alternative approach. The easiest way is to have an
final Object result[] = new Object[1];
before the call, and then the lambda
can assign the return value to the array. That’s because local state captured
by lambdas needs to be a final reference, but a final reference to a mutable
single element array allows us to poke a single value back. You could of course
use a different class for the array, depending on your requirements.
So, we have seen that 国内苹果怎么上twitter
is better than 国内iphone怎么上推特
, but can
we do even better than that? We certainly can, and that’s the purpose of the
next post.