SPIs vollständiger Name ist Service Provider Interface, mit dem Erweiterungen und Austauschkomponenten des Frameworks initiiert werden können.
Der Kern besteht darin, Schnittstellenimplementierung + Strategiemodus + Konfigurationsdatei zu verwenden, um ein dynamisches Laden von Implementierungsklassen zu erreichen.
Für die spezifische Verwendung gibt es einige Konventionen:
(1) Es ist festgelegt, dass unter META-INF/services/ von classPath die vollständige Namensdatei der Schnittstelle erstellt wird.
(2) Schreiben Sie in diese Datei die Schnittstelle Der vollständige Name der Implementierungsklasse (Pfad + Dateiname). Wenn mehrere Implementierungsklassen vorhanden sind, schreiben Sie diese in separate Zeilen.
(3) Wenn Sie 2 verwenden, verwenden Sie Load(Interface.class) von java.util.ServiceLoader, um die Implementierungsklasse abzurufen, und Sie können sie verwenden.
Es ist zu beachten, dass die Schnittstellenimplementierungsklasse einen Konstruktor ohne Parameter haben muss.
In dieser Anwendung gibt es zwei Module, nämlich Modul A und Modul B. Unter diesen beiden Modulen ist Modul A das Hauptmodul, B das Slave-Modul und Modul B hängt von Modul A ab. Derzeit gibt es jedoch eine Klasse, die in Modul B implementiert ist. Modul A muss die Funktionen dieser Klasse aufrufen, und das Modul kann sich nicht mehr auf Modul B verlassen. Zu diesem Zeitpunkt ist eine Entkopplung erforderlich. In dieser Implementierung wird SPI zur Entkopplungsimplementierung verwendet. Der spezifische Implementierungsplan lautet:
(1) Erstellen Sie eine neue Schnittstelle in Modul A: MyLogAppender. Die spezifische Implementierung lautet:
/** * @author Huang gen(kenfeng) * @description 自定义的appender接口 * @Since 2021/02/21 **/ public interface MyLogAppender { /** * 获取实现的appender * @return 返回新建的appender对象 * */ Appender getAppender(); }
Diese Schnittstelle ist sehr einfach und gibt lediglich ein Appender-Objekt zurück. Für die eigentliche Operation des Objekts wird die Operation in der Implementierung der Schnittstelle ausgeführt.
(2) Fügen Sie die Implementierung dieser Schnittstelle in Modul B hinzu. Die spezifische Operation lautet:
/** * @author Huang gen(kenfeng) * @description 自定义的appender * @Since 2021/02/21 **/ @Component public class MeshLogAppender extends UnsynchronizedAppenderBase<ILoggingEvent> implements MyLogAppender,ApplicationContextAware { private ApplicationContext applicationContext; public MeshLogAppender(){ } @Override public Appender getAppender() { MeshLogAppender meshLogAppender = new MeshLogAppender(); return meshLogAppender; } @Override protected void append(ILoggingEvent iLoggingEvent) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String std = simpleDateFormat.format(new Date(Long.parseLong(String.valueOf(iLoggingEvent.getTimeStamp())))); String log = std + "\t" + iLoggingEvent.getLevel() +"\t"+"--- ["+ iLoggingEvent.getThreadName()+"]\t"+iLoggingEvent.getCallerData()[0]+":\t "+iLoggingEvent.getMessage(); FlowMessage input = new FlowMessage(); MeshFlowService meshFlowService = SandboxSystemServiceFactory.getService(MeshFlowService.class); Map<String, Object> body = new HashMap<>(2); body.put("log",log); input.setTenantCode(DefaultTenant.get()); input.setAppCode("epoch"); input.setFlowCode("log_broadcast"); input.setBody(body); FlowMessage output = meshFlowService.process(input); if(!StringUtils.isEmpty(output.getErrorMessage())){ throw new RuntimeException("发布日志时,广播失败"); } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
Bei der Deklaration dieser Schnittstelle und der Implementierung der Schnittstelle müssen einige kleine Tricks implementiert werden. In der Schnittstelle wird nur der Erwerb einer Klasse deklariert und keine spezifische Methode implementiert. Instanziieren Sie diese Klasse in der Implementierungsklasse, erstellen Sie eine neue Klasse und geben Sie sie zurück. Zu diesem Zeitpunkt kann der Benutzer die Implementierungsklasse gemäß dieser Get-Methode abrufen und dann einige Vorgänge für die Implementierungsklasse ausführen. Das Schreiben auf diese Weise kann zwei Vorteile bringen: i. Der Code ist prägnanter und der Schnittstellencode ist einfach und leicht zu verstehen. ii kann direkt in die get-Methode eingefügt werden.
(3) Fügen Sie eine Konfigurationsdatei in dem Ordner hinzu, in dem sich die Implementierungsklasse befindet, d. h. sandbox-app-epoch-starter. Der Standardpfad der Konfigurationsdatei lautet hier: resources/META-INF/services/ Ordner Erstellen Sie eine neue Frage. Der Dateiname ist der Pfad der Schnittstelle und der Inhalt ist der Pfad der Implementierungsklasse. Daraus kann die Schnittstellen-->Implementierungsklassenzuordnung implementiert werden.
Wie im Bild oben gezeigt, lautet der Dateiname: com.alibaba.halo.sandbox.app.util.MyLogAppender
Der Inhalt der Datei lautet: com.alibaba.lattice2.epoch.util.MeshLogAppender
Der Das Prinzip besteht darin, dass, wenn der Benutzer die Schnittstelle verwendet, alle Dateien unter dem Projekt gescannt werden, um den Dateinamen com.alibaba.halo.sandbox.app.util.MyLogAppender zu finden, und dann die relevante Implementierungsklasse basierend darauf gefunden wird Inhalt
(4) In A können Sie die Schnittstelle direkt zum Aufrufen verwenden. Die spezifische Implementierung lautet wie folgt:
ServiceLoader<MyLogAppender> myLoaderInterfaceServiceLoader = ServiceLoader.load(MyLogAppender.class); Iterator<MyLogAppender> myLoaderInterfaceIterator = myLoaderInterfaceServiceLoader.iterator(); while (myLoaderInterfaceIterator.hasNext()){ MyLogAppender myLoaderInterface = myLoaderInterfaceIterator.next(); Appender newAppender = myLoaderInterface.getAppender(); newAppender.setName("application"); newAppender.setContext(loggerContext); newAppender.start(); rootLogger.addAppender(newAppender); }
Wie Sie oben sehen können, kann die MyLogAppender-Schnittstelle direkt aufgerufen und der erhaltene Appender verwendet werden über diese Schnittstelle und weisen Sie dann den Wert direkt zu. Vor- und Nachteile Vor- und Nachteile kann nicht implementiert werden Lazy Loading
Das obige ist der detaillierte Inhalt vonSo verwenden Sie SPI, um eine Entkopplung in Java zu erreichen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!