Dr. Yan Hongs Buch „JAVA and Patterns“ beginnt mit einer Beschreibung des Chain of Responsibility-Modells:
Das Chain-of-Responsibility-Muster ist ein Objektverhaltensmuster. Im Chain-of-Responsibility-Muster sind viele Objekte durch den Verweis jedes Objekts auf seinen Nachkommen zu einer Kette verbunden. Die Anfrage wird in der Kette nach oben weitergeleitet, bis ein Objekt in der Kette beschließt, die Anfrage zu bearbeiten. Der Client, der die Anfrage stellt, weiß nicht, welches Objekt in der Kette die Anfrage letztendlich bearbeitet, was es dem System ermöglicht, sich dynamisch neu zu organisieren und Verantwortlichkeiten zuzuweisen, ohne dass dies Auswirkungen auf den Client hat.
Angefangen beim Trommeln und Ausbreiten von Blumen
Trommeln und Blumen verteilen ist ein lebhaftes und spannendes Trinkspiel. Während des Banketts setzen sich die Gäste in der richtigen Reihenfolge zusammen und eine Person spielt die Trommel. Der Ort, an dem die Trommel gespielt wird, und der Ort, an dem Blumen verteilt werden, sind aus Fairnessgründen getrennt. Wenn das Trommeln beginnt, beginnen die Blumensträuße herumgereicht zu werden, und sobald die Trommeln fallen, muss jemand, der den Blumenstrauß in der Hand hat, trinken.
Zum Beispiel sind Jia Mu, Jia She, Jia Zheng, Jia Baoyu und Jia Huan fünf Blumenpassanten, die am Trommel- und Blumenpassspiel teilnehmen. Sie bilden eine Kette. Der Schlagzeuger reichte Jia Mu die Blumen und begann mit dem Blumenweitergabespiel. Die Blume wurde von Jia Mu an Jia She, von Jia She an Jia Zheng, von Jia Zheng an Jia Baoyu, von Jia Baoyu an Jia Huan, von Jia Huan an Jia Mu usw. weitergegeben, wie in der Abbildung unten gezeigt. Wenn das Trommeln aufhört, muss die Person mit der Blume in der Hand den Trinkbefehl ausführen.
Die Trommel zu schlagen und Blumen zu verteilen ist die Anwendung des Chain-of-Responsibility-Modells. Die Verantwortungskette kann eine gerade Linie, eine Kette oder Teil einer Baumstruktur sein.
Die Struktur des Chain-of-Responsibility-Modells
Im Folgenden wird die einfachste Implementierung eines Verantwortungskettenmusters verwendet.
Die am Chain-of-Responsibility-Modell beteiligten Rollen sind wie folgt:
● Rolle des abstrakten Handlers (Handler): Definiert eine Schnittstelle zur Verarbeitung von Anfragen. Bei Bedarf kann die Schnittstelle eine Methode definieren, um einen Verweis auf die nächste Schnittstelle festzulegen und zurückzugeben. Diese Rolle wird normalerweise durch eine abstrakte Java-Klasse oder eine Java-Schnittstelle implementiert. Die Aggregationsbeziehung der Handler-Klasse in der obigen Abbildung gibt den Verweis der spezifischen Unterklasse auf die nächste an. Die abstrakte Methode handleRequest() standardisiert die Operation der Unterklasse bei der Verarbeitung von Anforderungen.
● Rolle Betonbearbeiter (ConcreteHandler): Nach Erhalt der Anfrage kann der Betonbearbeiter wählen, ob er die Anfrage bearbeiten oder an die nächste Partei weiterleiten möchte. Da der konkrete Prozessor einen Verweis auf das nächste Zuhause hält, kann der konkrete Prozessor bei Bedarf auf das nächste Zuhause zugreifen.
Quellcode
abstrakte Handlerrolle
Kopieren Sie den Codecode wie folgt:
öffentliche abstrakte Klasse Handler {
/**
* Enthält Nachfolgeverantwortungsobjekte
*/
geschützter Handler-Nachfolger;
/**
* Gibt die Methode zur Verarbeitung der Anfrage an, obwohl diese Methode keine Parameter übergibt
* Parameter können jedoch tatsächlich übergeben werden. Sie können wählen, ob Parameter entsprechend den spezifischen Anforderungen übergeben werden sollen.
*/
öffentliches abstraktes void handleRequest();
/**
* Wertmethode
*/
öffentlicher Handler getSuccessor() {
Nachfolger zurückgeben;
}
/**
* Zuweisungsmethode zum Festlegen nachfolgender Verantwortungsobjekte
*/
public void setSuccessor(Handler-Nachfolger) {
this.successor = Nachfolger;
}
}
Spezifische Prozessorrolle
Kopieren Sie den Codecode wie folgt:
öffentliche Klasse ConcreteHandler erweitert Handler {
/**
* Verarbeitungsmethode. Rufen Sie diese Methode auf, um die Anforderung zu verarbeiten
*/
@Override
public void handleRequest() {
/**
* Stellen Sie fest, ob es ein Nachfolger-Verantwortungsobjekt gibt
* Wenn ja, leiten Sie die Anfrage an die nachfolgend zuständige Stelle weiter
* Wenn nicht, bearbeiten Sie die Anfrage
*/
if(getSuccessor() != null)
{
System.out.println("Anfrage loslassen");
getSuccessor().handleRequest();
}anders
{
System.out.println("Anfrage wird verarbeitet");
}
}
}
Client-Klasse
Kopieren Sie den Codecode wie folgt:
öffentliche Klasse Client {
public static void main(String[] args) {
//Stellen Sie die Verantwortungskette zusammen
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
//Anfrage senden
handler1.handleRequest();
}
}
Es ist ersichtlich, dass der Client zwei Handlerobjekte erstellt und angibt, dass das nächste Handlerobjekt des ersten Handlerobjekts das zweite Handlerobjekt ist, während das zweite Handlerobjekt kein nächstes Zuhause hat. Der Client übergibt die Anfrage dann an das erste Handlerobjekt.
Da die Übertragungslogik dieses Beispiels sehr einfach ist: Solange es einen nächsten Eigentümer gibt, wird es zur Verarbeitung an den nächsten Eigentümer übergeben. Wenn es keinen nächsten Eigentümer gibt, wird es von selbst verarbeitet. Nachdem das erste Handlerobjekt die Anforderung erhalten hat, leitet es die Anforderung daher an das zweite Handlerobjekt weiter. Da das zweite Handlerobjekt kein Zuhause hat, bearbeitet es die Anfrage selbst. Das Aktivitätssequenzdiagramm ist unten dargestellt.
Nutzungsszenarien
Betrachten wir eine solche Funktion: Beantragung der Verwaltung der Ausgaben für Dinnerpartys.
Viele Unternehmen haben diese Art von Vorteil, das heißt, das Projektteam oder die Abteilung kann beim Unternehmen einen Teil der Dinnerparty-Kosten beantragen, der für die Organisation von Dinnerpartys für Projektteammitglieder oder Abteilungsmitglieder verwendet wird.
Das allgemeine Verfahren zur Beantragung von Kosten für eine Dinnerparty ist im Allgemeinen: Der Antragsteller füllt zunächst das Antragsformular aus und reicht es dann zur Genehmigung beim Leiter ein. Wenn der Antrag genehmigt wird, benachrichtigt der Leiter den Antragsteller darüber, dass die Genehmigung bestanden wurde. Anschließend geht der Antragsteller zur Finanzabteilung, um die Gebühr einzuziehen. Wenn die Gebühr nicht genehmigt wird, wird der Antragsteller benachrichtigt, dass die Genehmigung nicht erteilt wurde, und die Angelegenheit wird fallen gelassen.
Führungskräfte auf verschiedenen Ebenen haben unterschiedliche Genehmigungslimits. Beispielsweise kann der Projektmanager nur Anträge mit einem Limit von 500 Yuan genehmigen; der General Manager kann Anträge mit einem beliebigen Betrag genehmigen.
Mit anderen Worten: Wenn jemand eine Anfrage für die Kosten einer Dinnerparty stellt, wird die Anfrage von einem der Projektmanager, Abteilungsleiter und Geschäftsführer entsprechend bearbeitet, aber die Person, die die Anfrage gestellt hat, weiß nicht, was am Ende passieren wird . Wer wird seine Anfrage bearbeiten? Im Allgemeinen reicht der Antragsteller seine Bewerbung beim Projektmanager ein, und möglicherweise bearbeitet der Geschäftsführer seine Anfrage.
Sie können das Verantwortungskettenmodell verwenden, um die obige Funktion zu realisieren: Wenn jemand eine Anfrage für die Kosten einer Dinnerparty stellt, wird die Anfrage an eine Führungsverarbeitungskette wie Projektmanager -> Abteilungsleiter -> General Manager weitergeleitet Wer die Anfrage gestellt hat, weiß nicht, wer seine Anfrage bearbeiten wird, und jeder Leiter wird anhand seines eigenen Verantwortungsbereichs entscheiden, ob er die Anfrage bearbeiten oder an einen übergeordneten Leiter übergeben soll. Die Übertragung ist beendet.
Es ist notwendig, die Verarbeitung jedes Leiters zu isolieren und in ein separates Verantwortungsverarbeitungsobjekt zu implementieren und ihnen dann ein gemeinsames, abstraktes übergeordnetes Verantwortungsobjekt bereitzustellen, damit die Verantwortungskette auf dem Client dynamisch kombiniert werden kann, um unterschiedliche Funktionsanforderungen zu erfüllen . .
Quellcode
Abstrakte Handler-Rollenklasse
Kopieren Sie den Codecode wie folgt:
öffentliche abstrakte Klasse Handler {
/**
* Enthält das Objekt, das die nächste Anfrage verarbeitet
*/
protected Handler-Nachfolger = null;
/**
* Wertmethode
*/
öffentlicher Handler getSuccessor() {
Nachfolger zurückgeben;
}
/**
* Legen Sie das nächste Objekt fest, um die Anfrage zu verarbeiten
*/
public void setSuccessor(Handler-Nachfolger) {
this.successor = Nachfolger;
}
/**
* Bearbeitung von Anträgen für Partykosten
* @param Benutzer Bewerber
* @param fee Der beantragte Geldbetrag
* @return Spezifische Benachrichtigung über Erfolg oder Misserfolg
*/
öffentlicher abstrakter String handleFeeRequest(String user, double fee);
}
Spezifische Prozessorrolle
Kopieren Sie den Codecode wie folgt:
Die öffentliche Klasse ProjectManager erweitert den Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
// Die Autorität des Projektmanagers ist relativ gering und kann nur innerhalb von 500 liegen
wenn (Gebühr < 500)
{
// Halten Sie es zum Testen einfach und stimmen Sie nur der Bitte von Zhang San zu.
if("Zhang San".equals(user))
{
str = „Erfolg: Der Projektmanager stimmt der Dinnerparty-Gebühr von [“ + Benutzer + „] zu, der Betrag beträgt „ + Gebühr + „Yuan“;
}anders
{
//Niemand sonst stimmt zu
str = „Fehler: Der Projektmanager ist mit der Dinnerparty-Gebühr von [“ + Benutzer + „] nicht einverstanden, der Betrag beträgt „ + Gebühr + „Yuan“;
}
}anders
{
//Wenn es 500 überschreitet, wird es weiterhin zur Verarbeitung an höherrangige Personen weitergegeben.
if(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(user, fee);
}
}
return str;
}
}
Kopieren Sie den Codecode wie folgt:
öffentliche Klasse DeptManager erweitert Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//Die Autorität des Abteilungsleiters kann nur innerhalb von 1000 liegen
if(Gebühr < 1000)
{
// Halten Sie es zum Testen einfach und stimmen Sie nur der Bitte von Zhang San zu.
if("Zhang San".equals(user))
{
str = „Erfolg: Der Abteilungsleiter stimmt der Dinnerparty-Gebühr von [“ + Benutzer + „] zu, der Betrag beträgt „ + Gebühr + „Yuan“;
}anders
{
//Niemand sonst stimmt zu
str = „Fehler: Der Abteilungsleiter ist mit der Dinnerparty-Gebühr von [“ + Benutzer + „] nicht einverstanden, der Betrag beträgt „ + Gebühr + „Yuan“;
}
}anders
{
//Wenn es 1000 überschreitet, wird es weiterhin zur Verarbeitung an höherrangige Personen übergeben.
if(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(user, fee);
}
}
return str;
}
}
Kopieren Sie den Codecode wie folgt:
Die öffentliche Klasse GeneralManager erweitert Handler {
@Override
public String handleFeeRequest(String user, double fee) {
String str = "";
//Der General Manager hat große Autorität, solange die Anfrage hier eintrifft.
if(Gebühr >= 1000)
{
// Halten Sie es zum Testen einfach und stimmen Sie nur der Bitte von Zhang San zu.
if("Zhang San".equals(user))
{
str = „Erfolg: Der Geschäftsführer stimmt den Abendessenkosten von [“ + Benutzer + „] zu, der Betrag beträgt „ + Gebühr + „Yuan“;
}anders
{
//Niemand sonst stimmt zu
str = „Fehler: Der Geschäftsführer ist mit der Dinnerparty-Gebühr von [“ + Benutzer + „] nicht einverstanden, der Betrag beträgt „ + Gebühr + „Yuan“;
}
}anders
{
//Wenn es nachfolgende Verarbeitungsobjekte gibt, übergeben Sie diese weiter
if(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(user, fee);
}
}
return str;
}
}
Client-Klasse
Kopieren Sie den Codecode wie folgt:
öffentliche Klasse Client {
public static void main(String[] args) {
//Stellen Sie zunächst die Verantwortungskette zusammen
Handler h1 = new GeneralManager();
Handler h2 = new DeptManager();
Handler h3 = new ProjectManager();
h3.setSuccessor(h2);
h2.setSuccessor(h1);
//Test starten
String test1 = h3.handleFeeRequest("Zhang San", 300);
System.out.println("test1 = " + test1);
String test2 = h3.handleFeeRequest("李思", 300);
System.out.println("test2 = " + test2);
System.out.println("-------------------------");
String test3 = h3.handleFeeRequest("Zhang San", 700);
System.out.println("test3 = " + test3);
String test4 = h3.handleFeeRequest("李思", 700);
System.out.println("test4 = " + test4);
System.out.println("-------------------------");
String test5 = h3.handleFeeRequest("Zhang San", 1500);
System.out.println("test5 = " + test5);
String test6 = h3.handleFeeRequest("李思", 1500);
System.out.println("test6 = " + test6);
}
}
Die Laufergebnisse sind wie folgt:
Reine und unreine Verantwortungskettenmodelle
Ein reines Verantwortungskettenmodell erfordert, dass ein bestimmtes Prozessorobjekt nur eine von zwei Aktionen auswählen kann: Die eine besteht darin, die Verantwortung zu übernehmen, die Verantwortung jedoch an die nächste Partei weiterzugeben. Es ist nicht zulässig, dass ein bestimmtes Prozessorobjekt die Verantwortung weitergibt, nachdem es einige Verantwortlichkeiten übernommen hat.
In einem reinen Chain-of-Responsibility-Modell muss eine Anfrage von einem Handlerobjekt empfangen werden; in einem unreinen Chain-of-Responsibility-Modell darf eine Anfrage von keinem Empfängerobjekt empfangen werden.
Tatsächliche Beispiele für das reine Chain-of-Responsibility-Modell sind schwer zu finden, und die im Allgemeinen gesehenen Beispiele sind Implementierungen des unreinen Chain-of-Responsibility-Modells. Manche Leute denken, dass eine unreine Verantwortungskette überhaupt kein Modell der Verantwortungskette ist, und das mag durchaus Sinn machen. Aber in tatsächlichen Systemen ist eine reine Verantwortungskette schwer zu finden. Wenn Sie darauf bestehen, dass die Verantwortungskette unrein ist und kein Modell der Verantwortungskette, dann ergibt das Modell der Verantwortungskette keinen großen Sinn.
Anwendung des Chain-of-Responsibility-Modells in Tomcat
Wie wir alle wissen, verwendet Filter in Tomcat das Chain-of-Responsibility-Modell. Zum Erstellen eines Filters müssen nicht nur entsprechende Konfigurationen in der Datei web.xml vorgenommen werden, sondern auch die Schnittstelle javax.servlet.Filter implementiert werden.
Kopieren Sie den Codecode wie folgt:
Die öffentliche Klasse TestFilter implementiert Filter{
public void doFilter(ServletRequest-Anfrage, ServletResponse-Antwort,
FilterChain-Kette) löst IOException, ServletException {
chain.doFilter(Anfrage, Antwort);
}
public void destroy() {
}
public void init(FilterConfig filterConfig) löst eine ServletException {
}
}
Die Ergebnisse im DEBUG-Modus sind wie folgt:
Tatsächlich durchläuft die TestFilter-Klasse viele interne Klassen von Tomcat, bevor sie tatsächlich ausgeführt wird. Übrigens ist die Containereinstellung von Tomcat auch ein Chain-of-Responsibility-Modell. Beachten Sie die durch das rote Kästchen eingekreisten Klassen. Anforderungen werden über eine Kette weitergeleitet. An der durch das grüne Kästchen eingekreisten Stelle gibt es eine Klasse namens ApplicationFilterChain. Die ApplicationFilterChain-Klasse spielt die Rolle eines abstrakten Prozessors, und die spezifische Prozessorrolle wird von jedem Filter übernommen.
Die erste Frage ist, wo ApplicationFilterChain alle Filter speichert.
Die Antwort wird in einem Array von ApplicationFilterConfig-Objekten in der ApplicationFilterChain-Klasse gespeichert.
Kopieren Sie den Codecode wie folgt:
/**
*Filter.
*/
private ApplicationFilterConfig[] Filter =
new ApplicationFilterConfig[0];
Was ist also das ApplicationFilterConfig-Objekt?
ApplicationFilterConfig ist ein Filtercontainer. Das Folgende ist die Deklaration der ApplicationFilterConfig-Klasse:
Kopieren Sie den Codecode wie folgt:
/**
* Implementierung einer <code>javax.servlet.FilterConfig</code> nützlich in
* Verwalten der Filterinstanzen, die bei einer Webanwendung instanziiert werden
* wird zuerst gestartet.
*
* @Autor Craig R. McClanahan
* @version $Id: ApplicationFilterConfig.java 1201569 2011-11-14 01:36:07Z kkolinko $
*/
ApplicationFilterConfig wird beim ersten Start einer Webanwendung automatisch instanziiert. Es liest die konfigurierten Filterinformationen aus der web.xml-Datei der Webanwendung und lädt sie dann in den Container.
Ich habe gerade gesehen, dass die Länge des in der ApplicationFilterChain-Klasse erstellten Arrays ApplicationFilterConfig Null ist. Wann wurde es neu zugewiesen?
Kopieren Sie den Codecode wie folgt:
private ApplicationFilterConfig[] Filter =
new ApplicationFilterConfig[0];
Dies geschieht beim Aufruf der Methode addFilter() der Klasse ApplicationFilterChain.
Kopieren Sie den Codecode wie folgt:
/**
* Der int, der die aktuelle Anzahl der Filter in der Kette angibt.
*/
private int n = 0;
öffentliches statisches final int INCREMENT = 10;
Kopieren Sie den Codecode wie folgt:
void addFilter(ApplicationFilterConfig filterConfig) {
// Verhindern, dass derselbe Filter mehrmals hinzugefügt wird
for(ApplicationFilterConfig filter:filters)
if(filter==filterConfig)
zurückkehren;
if (n == filter.length) {
ApplicationFilterConfig[] newFilters =
new ApplicationFilterConfig[n + INCREMENT];
System.arraycopy(filters, 0, newFilters, 0, n);
filter = newFilters;
}
filter[n++] = filterConfig;
}
Die Variable n wird verwendet, um die Anzahl der Filter in der aktuellen Filterkette aufzuzeichnen. Standardmäßig ist n gleich 0 und die Länge des ApplicationFilterConfig-Objektarrays ist ebenfalls gleich 0, wenn also die Methode addFilter() aufgerufen wird beim ersten Mal, wenn (n == filter .length) wahr ist und die Länge des ApplicationFilterConfig-Arrays geändert wird. Fügen Sie dann filter[n++] = filterConfig; die Variable filterConfig in das Array ApplicationFilterConfig ein und addieren Sie 1 zur Anzahl der Filter in der aktuellen Filterkette.
Wo heißt also die addFilter()-Methode von ApplicationFilterChain?
Es befindet sich in der Methode createFilterChain() der Klasse ApplicationFilterFactory.
Kopieren Sie den Codecode wie folgt:
öffentliche ApplicationFilterChain createFilterChain
(ServletRequest-Anfrage, Wrapper-Wrapper, Servlet-Servlet) {
// Den Dispatcher-Typ abrufen
DispatcherType-Dispatcher = null;
if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
Dispatcher = (DispatcherType) request.getAttribute(DISPATCHER_TYPE_ATTR);
}
String requestPath = null;
Objektattribut = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
if (Attribut != null){
requestPath = attribute.toString();
}
// Wenn kein Servlet zum Ausführen vorhanden ist, geben Sie null zurück
if (servlet == null)
return (null);
boolescher Komet = falsch;
// Ein Filterkettenobjekt erstellen und initialisieren
ApplicationFilterChain filterChain = null;
if (Request-Instanz von Request) {
Anfrage req = (Anfrage) Anfrage;
Comet = req.isComet();
if (Globals.IS_SECURITY_ENABLED) {
// Sicherheit: Nicht recyceln
filterChain = new ApplicationFilterChain();
if (Komet) {
req.setFilterChain(filterChain);
}
} anders {
filterChain = (ApplicationFilterChain) req.getFilterChain();
if (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} anders {
//Anfrage-Dispatcher im Einsatz
filterChain = new ApplicationFilterChain();
}
filterChain.setServlet(servlet);
filterChain.setSupport
(((StandardWrapper)wrapper).getInstanceSupport());
// Erfassen Sie die Filterzuordnungen für diesen Kontext
StandardContext context = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();
// Wenn keine Filterzuordnungen vorhanden sind, sind wir fertig
if ((filterMaps == null) || (filterMaps.length == 0))
return (filterChain);
// Erfassen Sie die Informationen, die wir zum Abgleichen der Filterzuordnungen benötigen
String servletName = wrapper.getName();
// Fügen Sie dieser Filterkette die relevanten Pfadzuordnungsfilter hinzu
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
weitermachen;
}
if (!matchFiltersURL(filterMaps[i], requestPath))
weitermachen;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME – Protokollkonfigurationsproblem
weitermachen;
}
boolean isCometFilter = false;
if (Komet) {
versuchen {
isCometFilter = filterConfig.getFilter() Instanz von CometFilter;
} Catch (Ausnahme e) {
// Hinweis: Der Try-Catch ist vorhanden, weil getFilter viele hat
// deklarierte Ausnahmen. Der Filter ist jedoch stark belegt
// früher
Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
}
if (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} anders {
filterChain.addFilter(filterConfig);
}
}
// Filter hinzufügen, die mit dem Servlet-Namen übereinstimmen, zweitens
for (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
weitermachen;
}
if (!matchFiltersServlet(filterMaps[i], servletName))
weitermachen;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
if (filterConfig == null) {
// FIXME – Protokollkonfigurationsproblem
weitermachen;
}
boolean isCometFilter = false;
if (Komet) {
versuchen {
isCometFilter = filterConfig.getFilter() Instanz von CometFilter;
} Catch (Ausnahme e) {
// Hinweis: Der Try-Catch ist vorhanden, weil getFilter viele hat
// deklarierte Ausnahmen. Der Filter ist jedoch stark belegt
// früher
}
if (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} anders {
filterChain.addFilter(filterConfig);
}
}
// Die vollständige Filterkette zurückgeben
return (filterChain);
}
Der obige Code kann in zwei Abschnitte unterteilt werden, den ersten Abschnitt vor Zeile 51 und den zweiten Abschnitt nach Zeile 51.
Der Hauptzweck des ersten Absatzes besteht darin, das ApplicationFilterChain-Objekt zu erstellen und einige Parameter festzulegen.
Der Hauptzweck des zweiten Absatzes besteht darin, alle Filterinformationen aus dem Kontext abzurufen und dann eine for-Schleife zu verwenden, um filterChain.addFilter(filterConfig) zu durchlaufen und filterConfig in das ApplicationFilterConfig-Array des ApplicationFilterChain-Objekts einzufügen.
Wo heißt also die Methode createFilterChain() der Klasse ApplicationFilterFactory?
Es wird in der invoke()-Methode der StandardWrapperValue-Klasse aufgerufen.
Da die invoke()-Methode lang ist, werden viele Stellen weggelassen.
Kopieren Sie den Codecode wie folgt:
öffentlicher endgültiger Void-Aufruf (Anfrageanfrage, Antwortantwort)
wirft IOException, ServletException {
...Zwischencode weglassen // Filterkette für diese Anfrage erstellen
ApplicationFilterFactory-Fabrik =
ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain =
Factory.createFilterChain(request, wrapper, servlet);
...Zwischencode weglassen
filterChain.doFilter(request.getRequest(), Response.getResponse());
...Zwischencode weglassen
}
Der normale Ablauf sollte wie folgt ablaufen:
Rufen Sie die Methode createFilterChain() der Klasse ApplicationFilterChai in der Methode invoke() der Klasse StandardWrapperValue auf ---> rufen Sie die Methode addFilter() der Klasse ApplicationFilterChain in der Methode createFilterChain() der Klasse ApplicationFilterChai auf ---> rufen Sie auf Methode addFilter() der Klasse ApplicationFilterChain. Weisen Sie dem Array ApplicationFilterConfig einen Wert zu.
Aus dem obigen Code ist ersichtlich, dass die invoke()-Methode der StandardWrapperValue-Klasse nach Ausführung der createFilterChain()-Methode weiterhin die doFilter()-Methode der ApplicationFilterChain-Klasse ausführt und anschließend die internalDoFilter()-Methode wird in der Methode doFilter() aufgerufen.
Das Folgende ist Teil des Codes der internalDoFilter()-Methode
Kopieren Sie den Codecode wie folgt:
// Rufen Sie den nächsten Filter auf, falls vorhanden
if (pos < n) {
//Den nächsten Filter abrufen und den Zeiger um eine Position nach unten bewegen
//pos es identifiziert, welchen Filter die aktuelle ApplicationFilterChain (aktuelle Filterkette) ausführt
ApplicationFilterConfig filterConfig = filter[pos++];
Filter filter = null;
versuchen {
//Holen Sie sich die Instanz des Filters, auf den aktuell verwiesen wird
filter = filterConfig.getFilter();
support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
Filter, Anfrage, Antwort);
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Boolean.FALSE);
}
if(Globals.IS_SECURITY_ENABLED) {
final ServletRequest req = request;
final ServletResponse res = Antwort;
Hauptprinzipal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege
("doFilter", filter, classType, args, Principal);
} anders {
//Rufen Sie die doFilter()-Methode von Filter auf
filter.doFilter(Anfrage, Antwort, dies);
}
Der filter.doFilter(request, response, this); hier dient zum Aufrufen der doFilter()-Methode in dem zuvor erstellten TestFilter. Die doFilter()-Methode in TestFilter ruft weiterhin die Methode chain.doFilter(request, Response) auf, und diese Kette ist eigentlich die ApplicationFilterChain, sodass der aufrufende Prozess zum Aufrufen des dofilters und zum Aufrufen der internalDoFilter-Methode oben zurückkehrt, und zwar so Die Ausführung wird fortgesetzt, bis der Filter im Inneren alle ausführt.
Wenn zwei Filter definiert sind, lauten die Debug-Ergebnisse wie folgt: