Dies ist, was ServiceLoader
ist für.
Ich denke, dass die Reflection-API macht es leichter zu sortieren, was Sie brauchen (d. H. Zum Filtern, aber nicht zum Abfragen der Klassenlader).
Wenn Sie mit dem Ausdruck "die geladenen Klassen durchsuchen" wirklich Klassen meinen, die bereits geladen sind, lesen Sie this question, um sie zu erhalten.
Sie können sich eine Widgets-Bibliothek mit einem Initialisierer vorstellen, der nur dafür sorgt, dass alle Widget-Klassen, die er kennt, geladen werden. Dann muss der Client nur den Initialisierer kennen.
Der Typprüfung ist der gleiche.
val need = typeOf[Whatsit[Cog]]
for (x <- (ServiceLoader load classOf[Whatsit[_]]).asScala) {
val im = currentMirror reflect x
if (im.symbol.toType weak_<:< need)
Console println s"$x is what I need"
else
Console println s"$x is not what I need, I'm looking for a $need"
}
Wo Sie etwas mit Typ-Parameter freuen:
trait Whatsit[+A <: Widget] {
def widget: A
}
class Engine extends Whatsit[Cog] {
def widget = new Cog
}
class FlyWheel extends Whatsit[Sprocket] {
def widget = new Sprocket
}
Probe:
[email protected] is what I need
[email protected] is not what I need, I'm looking for a widgets.Whatsit[widgets.Cog]
Falls es 10 Jahre her, seit Sie ServiceLoader
, verwendet und wer nicht brauchen einen Auffrischer:
[email protected]:~/tmp$ ls -R META-INF
META-INF:
MANIFEST.MF services
META-INF/services:
widgets.Whatsit widgets.Widget
[email protected]:~/tmp$ cat META-INF/services/widgets.Widget
widgets.Cog
widgets.Sprocket
[email protected]:~/tmp$ cat META-INF/services/widgets.Whatsit
widgets.Engine
widgets.FlyWheel
Stuff:
package widgets
trait Widget {
def turn(): Int
override def toString = s"Widget ${getClass.getSimpleName}"
}
class Cog extends Widget {
def turn() = 5
}
class Sprocket extends Widget {
def turn() = 10
}
trait Whatsit[+A <: Widget] {
def widget: A
override def toString = s"Whatsit ${getClass.getSimpleName} of $widget"
}
class Engine extends Whatsit[Cog] {
def widget = new Cog
}
class FlyWheel extends Whatsit[Sprocket] {
def widget = new Sprocket
}
Vergleich Scala und Java. Ich wollte herausfinden, wie viele LOC zu getGenericInterfaces
und finden Sie, was Sie in Scala wollen, aber dann habe ich ein Ende der Übung.
package findwidgets
import reflect._
import reflect.runtime.universe._
import reflect.runtime.currentMirror
import scala.collection.JavaConverters._
import java.util.ServiceLoader
object Test extends App {
import widgets.{ Widget, Whatsit, Cog }
val ws = (ServiceLoader load classOf[Widget]).asScala
for (w <- ws) {
Console println s"Turn a ${w.getClass} by ${w.turn}"
}
val need = typeOf[Whatsit[Cog]]
for (x <- (ServiceLoader load classOf[Whatsit[Cog]]).asScala) {
val im = currentMirror reflect x
if (im.symbol.toType weak_<:< need)
Console println s"$x is what I need"
else
Console println s"$x is not what I need, I'm looking for a $need"
// java says:
if (classOf[Whatsit[Cog]] isAssignableFrom x.getClass)
Console println s"Um, OK, I'll take the $x"
else
Console println s"${classOf[Whatsit[Cog]]} isn't ass'able from ${x.getClass}"
}
}
Muss dies nicht bedeuten, dass der Programmierer seine Schnittstelle explizit als Dienst deklariert und alle seine Implementierungen in 'META-INF/services/...' auflistet? – ghik
Ja, also der Punkt ist, dass die Bibliothek Ihnen sagt, was es bietet. Anstatt zu versuchen, das bekannte Universum nach Widgets zu durchsuchen, gibt es an einem bekannten Speicherort eine Ressource, die Sie für einen bestimmten Klassenlader abfragen können. Ich habe die anderen Stücke eingefügt. –
Ausgezeichnet! Danke, som! Genau das habe ich gebraucht. – Doswell