9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

Hallo, ich heiße Bruder A (YourBatman).

Spring hat die org.springframework.format.FormatterAbstraktion der Formatierungsschnittstelle entworfen und den Formatierer vereinheitlicht, sodass Sie sich nur um die einheitliche API anstatt um die spezifische Implementierung kümmern müssen. Die zugehörigen Themen werden im vorherigen Artikel ausführlich beschrieben .

Es gibt viele Formatierungsimplementierungen, die im Frühjahr erstellt wurden, und es gibt spezielle Komponenten, die für deren Verwaltung, Planung und Verwendung verantwortlich sind. Sie können als eindeutige und klare Verantwortlichkeiten beschrieben werden. Dieser Artikel konzentriert sich auf das Formatter-Registrierungscenter FormatterRegistryund führt Sie ein, wie Spring das Registrierungsmanagement elegant und geschickt implementiert.

Das Erlernen des Codierens ist ein Prozess der Nachahmung . Meistens müssen Sie nichts erstellen. Natürlich handelt es sich bei der hier genannten Nachahmung nicht um ein gewöhnliches CV-Modell , sondern darum, die Essenz für Ihren eigenen Gebrauch zu nutzen. Das in diesem Artikel beschriebene geniale Design ist die Essenz, und Sie können es extrahieren.

In den letzten Tagen hat es ein kleines kaltes Wetter gegeben. Peking hat eine Gefriertemperatur von -20 ° C und -11 ° C. Halten Sie sich warm, wenn Sie ausgehen.

Umriss dieses Artikels

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

Versionskonvention

  • Spring Framework: 5.3.x.
  • Spring Boot: 2.4.x.

✍Text

Nachdem Sie den Quellcode von Spring so oft gelesen und analysiert haben, werden Sie feststellen, dass die allgemeine Idee der Komponentenverwaltung dieselbe ist und diese Komponenten untrennbar miteinander verbunden sind: Registrierung (Registrar) + Verteiler .

Ein Drache bringt neun Kinder zur Welt, von denen jedes anders ist. Obwohl die allgemeine Idee dieselbe bleibt, hat jede Erkenntnis ihren eigenen Raum in ihrem Szenario, der unserer Sehnsucht würdig ist.

FormatterRegistry: Formatierungsregistrierung

Die Registry (Registrierungsstelle) des Feldattributformatierer. Bitte beachten Sie: Die Existenz des Feldes wird hier hervorgehoben. Sie werden zuerst damit vertraut sein und später ein tieferes Verständnis haben.

public interface FormatterRegistry extends ConverterRegistry {

    void addPrinter(Printer<?> printer);
    void addParser(Parser<?> parser);
    void addFormatter(Formatter<?> formatter);
    void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
    void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);

    void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);
}

Diese Schnittstelle wird von der Typkonverterregistrierung geerbt ConverterRegistry, daher ist die Formatregistrierung eine erweiterte Version der Konverterregistrierung , eine Obermenge davon und immer leistungsfähiger.

Über die Art der Konverterregistrierung ConverterRegistrykönnen Details in dieser Serie in diesem Artikel gelesen werden, lesen Sie die Hintertür frei

Obwohl FormatterRegistryviele Hinzufügungsmethoden bereitgestellt werden, beschreiben sie im Wesentlichen dasselbe: fieldTypeHinzufügen eines Formatierers (Drucker oder Parser) zum angegebenen Typ , und die Zeichnung lautet wie folgt:

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

Hinweis: Mit Ausnahme der letzten Schnittstellenmethode addFormatterForFieldAnnotation()bezieht sie sich auf das Formatieren von Anmerkungen, da dies sehr wichtig ist. Daher werde ich einen Artikel schreiben, um dies weiter unten zu erläutern

Der Vererbungsbaum der FormatterRegistry-Schnittstelle lautet wie folgt:

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

Mit der Erfahrung des Lernens von ConverterRegistry ist diese Entwurfsroutine leicht zu durchschauen. Diese beiden Implementierungsklassen sind hierarchisch unterteilt:

  • FormattingConversionService: Implementieren Sie alle Schnittstellenmethoden
  • DefaultFormattingConversionService: Vom obigen FormattingConversionService geerbt und den Standardformatierer darauf basierend registriert

Tatsächlich ist eine funktionale Klassifizierung tatsächlich der Fall. Dieser Artikel konzentriert sich auf FormattingConversionServicedas Design und die Implementierung dieser Klasse. Es gibt viele Tricks. Solange Sie kommen, möchten Sie, dass Sie gut aussehen.

FormattingConversionService

Es ist FormatterRegistrydie Implementierungsklasse der Schnittstelle, die alle ihre Schnittstellenmethoden implementiert .

FormatterRegistryJa ConverterRegistry, alle Methoden der ConverterRegistry-Schnittstelle wurden GenericConversionServicevollständig implementiert, sodass Sie die Implementierung der ConverterRegistry-Schnittstellenmethoden indirekt abschließen können, indem Sie sie erben. Die Vererbungsstruktur dieser Klasse sieht also folgendermaßen aus (bitte singen Sie diese Struktur):

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

FormattingConversionService erhält die "linke Hälfte" (übergeordnete Schnittstelle ConverterRegistry) durch Erben von GenericConversionService . Nur die "rechte Hälfte" muss noch verarbeitet werden. Dies ist die neue Schnittstellenmethode von FormatterRegistry.

FormattingConversionService:

    @Override
    public void addPrinter(Printer<?> printer) {
        Class<?> fieldType = getFieldType(printer, Printer.class);
        addConverter(new PrinterConverter(fieldType, printer, this));
    }
    @Override
    public void addParser(Parser<?> parser) {
        Class<?> fieldType = getFieldType(parser, Parser.class);
        addConverter(new ParserConverter(fieldType, parser, this));
    }
    @Override
    public void addFormatter(Formatter<?> formatter) {
        addFormatterForFieldType(getFieldType(formatter), formatter);
    }
    @Override
    public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) {
        addConverter(new PrinterConverter(fieldType, formatter, this));
        addConverter(new ParserConverter(fieldType, formatter, this));
    }
    @Override
    public void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser) {
        addConverter(new PrinterConverter(fieldType, printer, this));
        addConverter(new ParserConverter(fieldType, parser, this));
    }

An der Implementierung der Schnittstelle können Sie dieses "schockierende Geheimnis" erkennen: Alle Formatierer (einschließlich Drucker, Parser, Formatierer) gelten als Converterregistriert, was bedeutet, dass es nur eine echte Registrierung gibt ConverterRegistry.

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

Das Registrierungsmanagement des Formatierers ist weitaus weniger kompliziert als das des Konverters, da es auf der Idee der Anpassung der oberen Ebene basiert und schließlich an den Konverter angepasst wird, um die Registrierung abzuschließen. Gehen Sie also in die eigentliche endgültige Registrierung über den Formatierer an den Konverter angepasst, verwenden Sie den komplexen Satz von Konverter-Verwaltungslogik perfekt wieder .

Diese Designidee kann "Lebenslauf" in unser eigenes Programmierdenken sein.

Unabhängig davon, ob es sich um einen Drucker oder einen Parser handelt, werden beide an GenericConverter angepasst, um hinzugefügt ConverterRegistryund als Konverter verwaltet zu werden. Jetzt sollten Sie wissen, warum die FormatterRegistrySchnittstelle nur eine Add-Methode, keine Löschmethode bereitstellen muss.

Natürlich steht auch die Implementierung der Drucker- / Parser-Anpassung im Mittelpunkt dieses Artikels. Es gibt viele Artikel, lass uns gehen!

PrinterConverter: Druckerschnittstellenadapter

Die Printer&lt;?&gt;Anpassung ist ein Konverter und das Konvertierungsziel ist fieldType -&gt; String.

private static class PrinterConverter implements GenericConverter {

    private final Class<?> fieldType;
    // 从Printer<?>泛型里解析出来的类型,有可能和fieldType一样,有可能不一样
    private final TypeDescriptor printerObjectType;
    // 实际执行“转换”动作的组件
    private final Printer printer;
    private final ConversionService conversionService;

    public PrinterConverter(Class<?> fieldType, Printer<?> printer, ConversionService conversionService) {
        ...
        // 从类上解析出泛型类型,但不一定是实际类型
        this.printerObjectType = TypeDescriptor.valueOf(resolvePrinterObjectType(printer));
        ...
    }

    // fieldType -> String
    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(this.fieldType, String.class));
    }

}

Da es sich um einen Konverter handelt, ist der entscheidende Punkt natürlich die Konvertierungskonvertierungsmethode:

PrinterConverter:

    @Override
    @SuppressWarnings("unchecked")
    public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        // 若sourceType不是printerObjectType的子类型
        // 就尝试用conversionService转一下类型试试
        // (也就是说:若是子类型是可直接处理的,无需转换一趟)
        if (!sourceType.isAssignableTo(this.printerObjectType)) {
            source = this.conversionService.convert(source, sourceType, this.printerObjectType);
        }
        if (source == null) {
            return "";
        }

        // 执行实际转换逻辑
        return this.printer.print(source, LocaleContextHolder.getLocale());
    }

Der Konvertierungsschritt ist in zwei Schritte unterteilt:

  1. Wenn der Quelltyp (tatsächlicher Typ) kein Subtyp des generischen Typs des Druckertyps ist, versuchen Sie, den ConversionService zum Übertragen zu verwenden
    1. Beispiel: Der Drucker verarbeitet den Nummerntyp, aber Sie übergeben den Personentyp. Diesmal kommt der Konvertierungsdienst ins Spiel
  2. Lassen Sie den Zielformatierer Drucker die eigentliche Konvertierungslogik ausführen

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

Der Drucker kann sagen, dass es direkt übertragen werden kann, es kann ein ConversionService auf einem Konverter erstellt werden: Solange die Quelle ein Typ ist , mit dem ich umgehen kann , oder nachdem der ConversionService meine Energiebehandlung sein kann, kann er konvertiert werden. Es gibt eine perfekte Wiederverwendung von Fähigkeiten .

Apropos, ich denke, einige Freunde können immer noch nicht verstehen, was es bedeutet und welche Probleme gelöst werden können. Deshalb werde ich Ihnen Beispiele für Codes geben, um Ihr Verständnis zu vertiefen.

Bereiten Sie eine Java Bean vor:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {

    private Integer id;
    private String name;
}

Vorbereiten eines Druckers: Fügen Sie dem Integer-Typ 10 hinzu und konvertieren Sie ihn dann in den String-Typ

private static class IntegerPrinter implements Printer<Integer> {

    @Override
    public String print(Integer object, Locale locale) {
        object += 10;
        return object.toString();
    }
}

Beispiel 1: Verwenden des Druckers, keine Zwischenkonvertierung

Testfall:

@Test
public void test2() {
    FormattingConversionService formattingConversionService = new FormattingConversionService();
    FormatterRegistry formatterRegistry = formattingConversionService;
    // 说明:这里不使用DefaultConversionService是为了避免默认注册的那些转换器对结果的“干扰”,不方便看效果
    // ConversionService conversionService = new DefaultConversionService();
    ConversionService conversionService = formattingConversionService;

    // 注册格式化器
    formatterRegistry.addPrinter(new IntegerPrinter());

    // 最终均使用ConversionService统一提供服务转换
    System.out.println(conversionService.canConvert(Integer.class, String.class));
    System.out.println(conversionService.canConvert(Person.class, String.class));

    System.out.println(conversionService.convert(1, String.class));
    // 报错:No converter found capable of converting from type [cn.yourbatman.bean.Person] to type [java.lang.String]
    // System.out.println(conversionService.convert(new Person(1, "YourBatman"), String.class));
}

Führen Sie das Programm aus und geben Sie Folgendes aus:

true
false
11

perfekt.

Die Person -&gt; StringTypkonvertierung kann jedoch nicht abgeschlossen werden. Generell haben wir zwei Möglichkeiten, um dieses Ziel zu erreichen:

  1. Direkter Weg: Schreiben Sie einen dedizierten Person-zu-String-Konverter
    1. Nachteile liegen auf der Hand: Schreiben Sie mehr Code
  2. Kombinationen ( empfohlen ): Wenn bereits vorhanden sind Person -&gt; Integerund wir sie dann mit einer sehr praktischen kombinieren, zeigt Ihnen das folgende Beispiel, wie Sie diese Methode verwenden, um die "Nachfrage" zu vervollständigen.
    1. Die Mängel sind nicht offensichtlich: Konverter benötigen im Allgemeinen nichts mit Geschäftsdaten zu tun, sind also vielseitig und sollten so oft wie möglich wiederverwendet werden

Das folgende Beispiel 2 hilft Ihnen dabei, den Zweck zu lösen, der durch die Wiederverwendung vorhandener Funktionen erreicht wird Person -&gt; String.

Beispiel 2: Verwenden eines Druckers mit Zwischenkonvertierung

Wenn Sie dies anhand von Beispiel 1 erreichen möchten Person -&gt; String, müssen Sie nur einen weiteren Person -&gt; IntegerKonverter in das Programm schreiben ConversionService.

Hinweis: Im Allgemeinen verfügt ConversionService bereits über viele "Funktionen". Verwenden Sie diese einfach. In diesem Beispiel wird eine " saubere " ConversionService-Instanz verwendet, um Ihnen die Erläuterung der zugrunde liegenden Prinzipien zu erleichtern

@Test
public void test2() {
    FormattingConversionService formattingConversionService = new FormattingConversionService();
    FormatterRegistry formatterRegistry = formattingConversionService;
    // 说明:这里不使用DefaultConversionService是为了避免默认注册的那些转换器对结果的“干扰”,不方便看效果
    // ConversionService conversionService = new DefaultConversionService();
    ConversionService conversionService = formattingConversionService;

    // 注册格式化器
    formatterRegistry.addFormatterForFieldType(Person.class, new IntegerPrinter(), null);
    // 强调:此处绝不能使用lambda表达式代替,否则泛型类型丢失,结果将出错
    formatterRegistry.addConverter(new Converter<Person, Integer>() {
        @Override
        public Integer convert(Person source) {
            return source.getId();
        }
    });

    // 最终均使用ConversionService统一提供服务转换
    System.out.println(conversionService.canConvert(Person.class, String.class));
    System.out.println(conversionService.convert(new Person(1, "YourBatman"), String.class));
}

Führen Sie das Programm aus und geben Sie Folgendes aus:

true
11

perfekt.

In diesem Beispiel gibt es folgende Bedenken:

  1. Verwenden Sie die addFormatterForFieldType()Methode, um IntegerPrinter zu registrieren und die Art der Verarbeitung eindeutig anzugeben : Es wird nur der Personentyp verarbeitet
    1. Hinweis: IntegerPrinter kann mehrfach registriert werden, um verschiedene Typen zu verarbeiten. Zum Beispiel können Sie es behalten formatterRegistry.addPrinter(new IntegerPrinter());, um mit Integer umzugehen -> String ist ein Problem
  2. Da IntegerPrinter eigentlich nur konvertieren kann Integer -&gt; String, muss ein Konverter für die Person -&gt; IntegerÜberbrückung registriert werden , damit er verbunden werden kann Person -&gt; Integer -&gt; String. Es sieht nur so aus, als ob diese von IntegerPrinter von außen hergestellt werden, was sehr ordentlich ist
  3. Hervorheben: Wenn Sie einen Konverter bei addConverter () registrieren, verwenden Sie bitte keine Lambda-Ausdrücke anstelle von Eingaben, da sonst der generische Typ verloren geht und Fehler auftreten
    1. Wenn Sie Lambda-Ausdrücke verwenden möchten, verwenden Sie bitte die Überladungsmethode addConverter (Klasse, Klasse, Konverter), um die Registrierung abzuschließen

ParserConverter: Parser-Schnittstellenadapter

Die Parser&lt;?&gt;Anpassung ist ein Konverter und das Konvertierungsziel ist String -&gt; fieldType.

private static class ParserConverter implements GenericConverter {

    private final Class<?> fieldType;
    private final Parser<?> parser;
    private final ConversionService conversionService;

    ... // 省略构造器

    // String -> fieldType
    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, this.fieldType));
    }

}

Da es sich um einen Konverter handelt, ist der entscheidende Punkt natürlich die Konvertierungskonvertierungsmethode:

ParserConverter:

    @Override
    @Nullable
    public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        // 空串当null处理
        String text = (String) source;
        if (!StringUtils.hasText(text)) {
            return null;
        }

        ...
        Object result = this.parser.parse(text, LocaleContextHolder.getLocale());
        ...

        // 解读/转换结果
        TypeDescriptor resultType = TypeDescriptor.valueOf(result.getClass());
        if (!resultType.isAssignableTo(targetType)) {
            result = this.conversionService.convert(result, resultType, targetType);
        }
        return result;
    }

Der Konvertierungsschritt ist in zwei Schritte unterteilt:

  1. Konvertieren Sie den String über Parser und Ergebnis in den angegebenen Typ (wenn dies fehlschlägt, wird eine Ausnahme ausgelöst).
  2. Stellen Sie fest, ob das Ergebnis ein Subtyp des Zieltyps ist , geben Sie direkt zurück, andernfalls rufen Sie ConversionService zum Konvertieren auf

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

Sie können sehen, dass dies das Gegenteil der "Reihenfolge" des Druckers ist, und es macht viel Aufhebens um den Rückgabewert. In ähnlicher Weise werden die folgenden zwei Beispiele verwendet, um das Verständnis zu vertiefen.

private static class IntegerParser implements Parser<Integer> {

    @Override
    public Integer parse(String text, Locale locale) throws ParseException {
        return NumberUtils.parseNumber(text, Integer.class);
    }
}

Beispiel 1: Mit Parser keine Zwischenkonvertierung

Testfälle schreiben:

@Test
public void test3() {
    FormattingConversionService formattingConversionService = new FormattingConversionService();
    FormatterRegistry formatterRegistry = formattingConversionService;
    ConversionService conversionService = formattingConversionService;

    // 注册格式化器
    formatterRegistry.addParser(new IntegerParser());

    System.out.println(conversionService.canConvert(String.class, Integer.class));
    System.out.println(conversionService.convert("1", Integer.class));
}

Führen Sie das Programm aus und geben Sie Folgendes aus:

true
1

perfekt.

Beispiel 2: Verwenden Sie Parser mit Zwischenkonvertierung

Das folgende Beispiel gibt eine Zeichenfolge von "1" ein und gibt ein Personenobjekt aus (aufgrund der Vorahnung des obigen Beispiels ist hier "einfach").

@Test
public void test4() {
    FormattingConversionService formattingConversionService = new FormattingConversionService();
    FormatterRegistry formatterRegistry = formattingConversionService;
    ConversionService conversionService = formattingConversionService;

    // 注册格式化器
    formatterRegistry.addFormatterForFieldType(Person.class, null, new IntegerParser());
    formatterRegistry.addConverter(new Converter<Integer, Person>() {
        @Override
        public Person convert(Integer source) {
            return new Person(source, "YourBatman");
        }
    });

    System.out.println(conversionService.canConvert(String.class, Person.class));
    System.out.println(conversionService.convert("1", Person.class));
}

Führen Sie das Programm, Pop, Nullzeiger aus:

java.lang.NullPointerException
    at org.springframework.format.support.FormattingConversionService$PrinterConverter.resolvePrinterObjectType(FormattingConversionService.java:179)
    at org.springframework.format.support.FormattingConversionService$PrinterConverter.<init>(FormattingConversionService.java:155)
    at org.springframework.format.support.FormattingConversionService.addFormatterForFieldType(FormattingConversionService.java:95)
    at cn.yourbatman.formatter.Demo.test4(Demo.java:86)
    ...

Gemäß den Informationen zum Ausnahmestapel kann der Grund geklärt werden: addFormatterForFieldType()Der zweite Parameter der Methode kann nicht null übergeben, andernfalls einen Nullzeiger. Dies ist eigentlich Spring Frameworkein Fehler. Ich habe ein Problem bei der Community eingereicht und hoffe, dass es behoben werden kann:

9. Einzelheiten finden Sie im eigentlichen Kapitel. Das Design der Formatter-Registrierung ist sehr niedlich

Um dieses Beispiel ordnungsgemäß auszuführen, ändern Sie es folgendermaßen:

// 第二个参数不传null,用IntegerPrinter占位
formatterRegistry.addFormatterForFieldType(Person.class, new IntegerPrinter(), new IntegerParser());

Führen Sie das Programm erneut aus und geben Sie Folgendes aus:

true
Person(id=1, name=YourBatman)

perfekt.

In diesem Beispiel gibt es folgende Bedenken:

  1. Verwenden Sie die addFormatterForFieldType()Methode, um IntegerParser zu registrieren und den Verarbeitungstyp für die Verarbeitung des Personentyps eindeutig anzugeben
    1. Das heißt, wird dieser IntegerParser speziell auf convert verwendet Attribute , dessen Zieltypen ist Person
  2. Da IntegerParser eigentlich nur konvertieren kann String -&gt; Integer, muss ein Konverter für das Integer -&gt; PersonBridging registriert werden , damit er aneinander gereiht werden kann String -&gt; Integer -&gt; Person. Es sieht so aus, als ob diese von IntegerParser gemacht wurden, sehr ordentlich
  3. Hervorheben: Wenn Sie den Konverter bei addConverter () registrieren, achten Sie darauf, keine Lambda-Ausdrücke anstelle von Eingaben zu verwenden, da sonst der generische Typ verloren geht und Fehler auftreten

Welche Verbesserungen bringt das Halten von ConversionService?

Hinweis: Sie kennen einen so wichtigen ConversionService. Wenn Sie ihn vergessen, können Sie mit dem Aufzug zu dieser Überprüfung fahren

Für PrinterConverter und ParserConverter besteht ihr Quellzweck darin, Folgendes zu erreichen String &lt;-&gt; Object, und die Eigenschaften sind:

  • PrinterConverter: Der Exit muss vom Typ String sein, und der Eintragstyp wurde ebenfalls bestimmt, dh Printer&lt;T&gt;der generische Typ, der nur verarbeitet werden kannT(或T的子类型) -&gt; String
  • ParserConverter: Der Eintrag muss vom Typ String sein, und der Exit-Typ wurde ebenfalls bestimmt, dh Parser&lt;T&gt;der generische Typ, der nur verarbeitet werden kannString -&gt; T(或T的子类型)

Nach den festgelegten "Regeln" ist der Umfang ihrer Fähigkeiten noch recht begrenzt. Hier ist Spring so leistungsstark, dass es die Funktionen vorhandener Komponenten durch Kombination geschickt erweitern kann. Beispielsweise wird die ConversionService-Referenz in PrinterConverter / ParserConverter in den Gewinn einbezogen, um diesen Effekt zu erzielen:

ConversionService

Durch die Kombination von Fähigkeiten und Zusammenarbeit spielt es eine Rolle in Serie und erweitert dadurch den "Ein- / Ausgabebereich", der sich wie eine Lupe anfühlt. Dieses Design ist immer noch sehr niedlich.

✍Zusammenfassung

Dieser Artikel FormatterRegistrykonzentriert sich auf die Einführung der Benutzeroberfläche und auf die Implementierung dieser Benutzeroberfläche. Er stellte fest, dass selbst ein kleines Registrierungszentrum umfangreiche Highlights für Lernen und Lebenslauf bietet.

Im Allgemeinen ist es ConversionService mit sehr leistungsstarken Konvertierungsfunktionen ausgestattet. Wenn Sie also einen Drucker / Parser anpassen müssen, besteht eine hohe Wahrscheinlichkeit, dass Sie keinen zusätzlichen Konverterkonverter selbst hinzufügen müssen. Das heißt, der zugrunde liegende Mechanismus lässt Sie bereits stehen Auf den Schultern der "Riesen".

"Dieser Artikel denkt Fragen"

Nachdem Sie es gelesen haben, verstehen Sie es möglicherweise nicht und Sie verstehen es möglicherweise nicht. Hier helfen Ihnen 3 Gedankenfragen am Ende des Artikels bei der Überprüfung:

  1. FormatterRegistry als Registrierungszentrum kann nur hinzugefügt werden. Warum?
  2. Warum wird es im Beispiel hervorgehoben: Wenn Sie einen Konverter bei addConverter () registrieren, achten Sie darauf, keine Lambda-Ausdrücke anstelle von Eingaben zu verwenden. Was ist das Problem?
  3. Können Sie sich andere Fälle dieses cleveren Designs von Funktionskombination / Überbrückung vorstellen?

"Empfohlene Lektüre"

"Erklärung"

Dieser Artikel gehört zur Spalte: Spring-Typkonvertierung , die Backstage-Antwort des öffentlichen Kontos auf den Spaltennamen, um den gesamten Inhalt abzurufen.

Teilen, wachsen, sich nicht verstecken und aufhören. Achten Sie auf [BAT Utopia] und antworten Sie auf die Keyword- Spalte mit kleinen und schönen Originalspalten wie Spring Technology Stack und Middleware zum kostenlosen Lernen. Dieser Artikel wurdehttps://www.yourbatman.cn enthalten.

Dieser Artikel ist ein Originalartikel von Bruder A (YourBatman) und kann nicht ohne die Erlaubnis / Eröffnung des Autors reproduziert werden. Vielen Dank für Ihre Mitarbeit.

Ich denke du magst

Origin blog.51cto.com/3631118/2592729
Empfohlen
Rangfolge