Heim >Java >javaLernprogramm >So verwenden Sie SPI, um eine Entkopplung in Java zu erreichen

So verwenden Sie SPI, um eine Entkopplung in Java zu erreichen

王林
王林nach vorne
2023-05-19 21:58:151445Durchsuche

Übersicht

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.

Implementierungsfall

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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen