Le livre du Dr Yan Hong « JAVA and Patterns » commence par une description du modèle de chaîne de responsabilité :
Le modèle de chaîne de responsabilité est un modèle de comportement d’objet. Dans le modèle de chaîne de responsabilité, de nombreux objets sont connectés pour former une chaîne par la référence de chaque objet à son descendant. La requête est transmise dans la chaîne jusqu'à ce qu'un objet de la chaîne décide de traiter la requête. Le client qui fait la demande ne sait pas quel objet de la chaîne gère finalement la demande, ce qui permet au système de se réorganiser et d'attribuer dynamiquement les responsabilités sans affecter le client.
Commencer par battre des tambours et répandre des fleurs
Jouer du tambour et passer des fleurs est un jeu à boire vivant et tendu. Pendant le banquet, les invités s'assoient dans l'ordre et une personne joue du tambour. L'endroit où le tambour est joué et l'endroit où les fleurs sont distribuées sont séparés pour montrer l'équité. Lorsque le tambour commence, les bouquets commencent à circuler, et dès que les tambours tombent, si le bouquet est dans la main de quelqu'un, celui-ci doit boire.
Par exemple, Jia Mu, Jia She, Jia Zheng, Jia Baoyu et Jia Huan sont cinq passeurs de fleurs qui participent au jeu de tambour et de passage de fleurs. Ils forment une chaîne. Le batteur a passé les fleurs à Jia Mu et a commencé le jeu de passe de fleurs. La fleur est passée de Jia Mu à Jia She, de Jia She à Jia Zheng, de Jia Zheng à Jia Baoyu, de Jia Baoyu à Jia Huan, de Jia Huan à Jia Mu, et ainsi de suite, comme le montre la figure ci-dessous. Lorsque le tambour s'arrête, la personne qui tient la fleur à la main doit exécuter l'ordre de boire.
Battre le tambour et répandre des fleurs est l’application du modèle de chaîne de responsabilité. La chaîne de responsabilité peut être une ligne droite, une chaîne ou une partie d’une structure arborescente.
La structure du modèle de chaîne de responsabilité
La mise en œuvre la plus simple d’un modèle de chaîne de responsabilité est utilisée ci-dessous.
Les rôles impliqués dans le modèle de chaîne de responsabilité sont les suivants :
● Rôle de gestionnaire abstrait (Handler) : définit une interface de traitement des requêtes. Si nécessaire, l'interface peut définir une méthode pour définir et renvoyer une référence à l'interface suivante. Ce rôle est généralement implémenté par une classe abstraite Java ou une interface Java. La relation d'agrégation de la classe Handler dans la figure ci-dessus donne la référence de la sous-classe spécifique à la suivante. La méthode abstraite handleRequest() standardise le fonctionnement de la sous-classe dans le traitement des requêtes.
● Rôle de gestionnaire de béton (ConcreteHandler) : après avoir reçu la demande, le gestionnaire de béton peut choisir de traiter la demande ou de transmettre la demande à la partie suivante. Étant donné que le processeur de béton détient une référence à la prochaine maison, il peut accéder à la prochaine maison si nécessaire.
code source
rôle de gestionnaire abstrait
Copiez le code comme suit :
Gestionnaire de classe abstraite publique {
/**
* Détient les objets de responsabilité du successeur
*/
successeur du gestionnaire protégé ;
/**
* Indique la méthode de traitement de la requête, bien que cette méthode ne passe pas en paramètres
* Cependant, les paramètres peuvent effectivement être transmis. Vous pouvez choisir de transmettre ou non les paramètres en fonction de besoins spécifiques.
*/
public abstract void handleRequest();
/**
* Méthode de valeur
*/
Gestionnaire public getSuccessor() {
renvoyer le successeur ;
}
/**
* Méthode d'affectation pour définir les objets de responsabilité ultérieurs
*/
public void setSuccessor (successeur du gestionnaire) {
this.successor = successeur ;
}
}
Rôle de processeur spécifique
Copiez le code comme suit :
classe publique ConcreteHandler étend Handler {
/**
* Méthode de traitement, appelez cette méthode pour traiter la demande
*/
@Outrepasser
public void handleRequest() {
/**
* Déterminer s'il existe un objet responsable successeur
* Si c'est le cas, transmettre la demande à l'objet responsable suivant
*Sinon, traitez la demande
*/
si(getSuccessor() != null)
{
System.out.println("Laisser passer la requête");
getSuccessor().handleRequest();
}autre
{
System.out.println("Traitement de la demande");
}
}
}
Classe de clients
Copiez le code comme suit :
Client de classe publique {
public static void main (String[] arguments) {
// Assembler la chaîne de responsabilité
Gestionnaire handler1 = new ConcreteHandler();
Gestionnaire handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
// Soumettre la demande
handler1.handleRequest();
}
}
On peut voir que le client crée deux objets gestionnaires et spécifie que l'objet gestionnaire suivant du premier objet gestionnaire est le deuxième objet gestionnaire, tandis que le deuxième objet gestionnaire n'a pas de prochain domicile. Le client transmet ensuite la demande au premier objet gestionnaire.
Parce que la logique de transfert de cet exemple est très simple : tant qu'il y a un prochain propriétaire, il sera transmis au prochain propriétaire pour traitement s'il n'y a pas de prochain propriétaire, il sera traité par lui-même ; Par conséquent, une fois que le premier objet gestionnaire aura reçu la demande, il transmettra la demande au deuxième objet gestionnaire. Puisque le deuxième objet gestionnaire n’a pas de domicile, il gère la demande par lui-même. Le diagramme de séquence d’activités est présenté ci-dessous.
Scénarios d'utilisation
Considérons une telle fonction : postuler à la gestion des frais de dîner.
De nombreuses entreprises bénéficient de ce type d'avantages, c'est-à-dire que l'équipe de projet ou le département peut demander à l'entreprise certaines dépenses de dîner, qui sont utilisées pour organiser des dîners pour les membres de l'équipe de projet ou du département.
Le processus général de demande de frais de dîner est généralement le suivant : le demandeur remplit d'abord le formulaire de demande, puis le soumet au chef pour approbation. Si la demande est approuvée, le chef informera le demandeur que l'approbation a été obtenue. puis le demandeur se rendra au service des finances pour percevoir les frais. S'il n'est pas approuvé, le dirigeant le fera. Le demandeur sera informé que l'approbation n'a pas été obtenue et l'affaire sera abandonnée.
Les dirigeants à différents niveaux ont des limites d'approbation différentes. Par exemple, le chef de projet ne peut approuver que les demandes avec une limite de 500 yuans ; les chefs de département peuvent approuver les demandes avec une limite de 1 000 yuans et le directeur général peut approuver les demandes avec n'importe quel montant ;
Autrement dit, lorsque quelqu'un fait une demande de frais de dîner, la demande sera traitée en conséquence par l'un des chefs de projet, chefs de service et directeurs généraux, mais la personne qui a fait la demande ne sait pas ce qui se passera au final. . Qui va traiter sa demande ? Généralement, le demandeur soumet sa candidature au chef de projet, et peut-être que le directeur général traite finalement sa demande.
Vous pouvez utiliser le modèle de chaîne de responsabilité pour réaliser la fonction ci-dessus : lorsque quelqu'un fait une demande de dépenses pour un dîner, la demande sera transmise dans une chaîne de traitement de leadership telle que chef de projet -> chef de service -> directeur général La personne. qui a fait la demande ne sait pas qui traitera sa demande, chaque dirigeant jugera s'il doit traiter la demande ou la confier à un dirigeant de niveau supérieur en fonction de son propre champ de responsabilités. le transfert est terminé.
Il est nécessaire d'isoler le traitement de chaque leader et de l'implémenter dans un objet de traitement de responsabilité distinct, puis de leur fournir un objet de responsabilité parent commun et abstrait, afin que la chaîne de responsabilité puisse être combinée dynamiquement sur le client pour répondre à différentes exigences fonctionnelles. .
code source
Classe de rôle de gestionnaire abstrait
Copiez le code comme suit :
Gestionnaire de classe abstraite publique {
/**
* Contient l'objet qui gère la prochaine requête
*/
successeur du gestionnaire protégé = null ;
/**
* Méthode de valeur
*/
Gestionnaire public getSuccessor() {
renvoyer le successeur ;
}
/**
* Définir l'objet suivant pour gérer la demande
*/
public void setSuccessor (successeur du gestionnaire) {
this.successor = successeur ;
}
/**
* Traiter les demandes de dépenses de fête
* Candidat utilisateur @param
* @param fee Le montant demandé
* @return Notification spécifique de réussite ou d'échec
*/
public abstract String handleFeeRequest (utilisateur String, frais doubles);
}
Rôle de processeur spécifique
Copiez le code comme suit :
la classe publique ProjectManager étend le gestionnaire {
@Outrepasser
public String handleFeeRequest (utilisateur String, frais doubles) {
Chaîne str = "" ;
//L'autorité du chef de projet est relativement faible et ne peut être que de 500
si (frais < 500)
{
// Par souci de test, restez simple et n'acceptez que la demande de Zhang San.
if("Zhang San".equals(utilisateur))
{
str = "Succès : le chef de projet accepte les frais de dîner de [" + utilisateur + "], le montant est de " + frais + "yuan" ;
}autre
{
// Personne d'autre n'est d'accord
str = "Échec : le chef de projet n'est pas d'accord avec les frais de dîner de [" + utilisateur + "], le montant est de " + frais + "yuan" ;
}
}autre
{
//S'il dépasse 500, continuez à le transmettre aux personnes de niveau supérieur pour traitement.
si(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(user, fee);
}
}
return str;
}
}
Copiez le code comme suit :
la classe publique DeptManager étend le gestionnaire {
@Outrepasser
public String handleFeeRequest (utilisateur String, frais doubles) {
Chaîne str = "" ;
//L'autorité du chef de service ne peut être que dans la limite de 1000
si (frais < 1000)
{
// Par souci de test, restez simple et n'acceptez que la demande de Zhang San.
if("Zhang San".equals(utilisateur))
{
str = "Succès : le chef de service accepte les frais de dîner de [" + utilisateur + "], le montant est de " + frais + "yuan" ;
}autre
{
// Personne d'autre n'est d'accord
str = "Échec : le chef de service n'est pas d'accord avec les frais de dîner de [" + utilisateur + "], le montant est de " + frais + "yuan" ;
}
}autre
{
// S'il dépasse 1 000, continuez à le transmettre aux personnes de niveau supérieur pour traitement.
si(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(user, fee);
}
}
return str;
}
}
Copiez le code comme suit :
la classe publique GeneralManager étend le gestionnaire {
@Outrepasser
public String handleFeeRequest (utilisateur String, frais doubles) {
Chaîne str = "" ;
//Le directeur général a une grande autorité. Tant que la demande arrive ici, il peut la gérer.
si (frais >= 1000)
{
// Par souci de test, restez simple et n'acceptez que la demande de Zhang San.
if("Zhang San".equals(utilisateur))
{
str = "Succès : le directeur général accepte les dépenses de dîner de [" + utilisateur + "], le montant est de " + frais + "yuan" ;
}autre
{
// Personne d'autre n'est d'accord
str = "Échec : le directeur général n'est pas d'accord avec les frais de dîner de [" + utilisateur + "], le montant est de " + frais + "yuan" ;
}
}autre
{
//S'il y a des objets de traitement ultérieurs, continuez à les transmettre
si(getSuccessor() != null)
{
return getSuccessor().handleFeeRequest(user, fee);
}
}
return str;
}
}
Classe de clients
Copiez le code comme suit :
Client de classe publique {
public static void main (String[] arguments) {
// Assemblez d'abord la chaîne de responsabilité
Gestionnaire h1 = new GeneralManager();
Gestionnaire h2 = new DeptManager();
Gestionnaire h3 = new ProjectManager();
h3.setSuccessor(h2);
h2.setSuccessor(h1);
// Commencer les tests
Chaîne test1 = h3.handleFeeRequest("Zhang San", 300);
System.out.println("test1 = " + test1);
String test2 = h3.handleFeeRequest("李思", 300);
System.out.println("test2 = " + test2);
System.out.println("---------------------------------------");
Chaîne test3 = h3.handleFeeRequest("Zhang San", 700);
System.out.println("test3 = " + test3);
String test4 = h3.handleFeeRequest("李思", 700);
System.out.println("test4 = " + test4);
System.out.println("---------------------------------------");
Chaîne test5 = h3.handleFeeRequest("Zhang San", 1500);
System.out.println("test5 = " + test5);
String test6 = h3.handleFeeRequest("李思", 1500);
System.out.println("test6 = " + test6);
}
}
Les résultats en cours d'exécution sont les suivants :
Modèles de chaîne de responsabilité pure et impure
Un modèle de chaîne de responsabilité pure exige qu'un objet processeur spécifique ne puisse choisir qu'une des deux actions suivantes : l'une consiste à assumer la responsabilité, mais à transmettre la responsabilité à la partie suivante. Il n'est pas permis à un objet processeur spécifique de transmettre la responsabilité après avoir assumé certaines responsabilités.
Dans un modèle de chaîne de responsabilité pure, une demande doit être reçue par un objet gestionnaire ; dans un modèle de chaîne de responsabilité impur, une demande ne peut être reçue par aucun objet récepteur.
Il est difficile de trouver des exemples réels du modèle de chaîne de responsabilité pure, et les exemples généralement vus sont des mises en œuvre du modèle de chaîne de responsabilité impur. Certaines personnes pensent qu’une chaîne de responsabilité impure n’est pas du tout un modèle de chaîne de responsabilité, et cela peut avoir du sens. Mais dans les systèmes actuels, il est difficile de trouver une pure chaîne de responsabilité. Si vous insistez sur le fait que la chaîne de responsabilité est impure et qu’elle n’est pas un modèle de chaîne de responsabilité, alors le modèle de chaîne de responsabilité n’aura pas beaucoup de sens.
Application du modèle de chaîne de responsabilité dans Tomcat
Comme nous le savons tous, Filter dans Tomcat utilise le modèle de chaîne de responsabilité. En plus d'effectuer les configurations correspondantes dans le fichier web.xml, la création d'un filtre nécessite également l'implémentation de l'interface javax.servlet.Filter.
Copiez le code comme suit :
la classe publique TestFilter implémente Filter{
public void doFilter (demande ServletRequest, réponse ServletResponse,
Chaîne FilterChain) lance IOException, ServletException {
chain.doFilter(demande, réponse);
}
public void destroy() {
}
public void init (FilterConfig filterConfig) lance ServletException {
}
}
Les résultats observés en mode DEBUG sont les suivants :
En fait, avant d'exécuter réellement la classe TestFilter, celle-ci passera par de nombreuses classes internes de Tomcat. À propos, le paramètre de conteneur de Tomcat est également un modèle de chaîne de responsabilité. Faites attention aux classes entourées par la case rouge Du moteur à l'hôte en passant par le contexte et le wrapper. Il existe une classe appelée ApplicationFilterChain à l'endroit entouré par la case verte. La classe ApplicationFilterChain joue le rôle de processeur abstrait, et le rôle de processeur spécifique est joué par chaque filtre.
La première question est de savoir où ApplicationFilterChain stocke tous les filtres ?
La réponse est stockée dans un tableau d'objets ApplicationFilterConfig dans la classe ApplicationFilterChain.
Copiez le code comme suit :
/**
*Filtres.
*/
filtres privés ApplicationFilterConfig[] =
nouveau ApplicationFilterConfig[0] ;
Alors, qu'est-ce que l'objet ApplicationFilterConfig ?
ApplicationFilterConfig est un conteneur de filtre. Voici la déclaration de la classe ApplicationFilterConfig :
Copiez le code comme suit :
/**
* Implémentation d'un <code>javax.servlet.FilterConfig</code> utile dans
* gestion des instances de filtre instanciées lors d'une application web
* est démarré pour la première fois.
*
* @auteur Craig R. McClanahan
* @version $Id : ApplicationFilterConfig.java 1201569 2011-11-14 01:36:07Z kkolinko $
*/
ApplicationFilterConfig est automatiquement instancié lorsqu'une application Web est démarrée pour la première fois. Il lit les informations de filtre configurées à partir du fichier web.xml de l'application Web, puis les charge dans le conteneur.
Je viens de voir que la longueur du tableau ApplicationFilterConfig créé dans la classe ApplicationFilterChain est nulle. Quand a-t-il été réaffecté ?
Copiez le code comme suit :
filtres privés ApplicationFilterConfig[] =
nouveau ApplicationFilterConfig[0] ;
C'est lors de l'appel de la méthode addFilter() de la classe ApplicationFilterChain.
Copiez le code comme suit :
/**
* L'int qui donne le nombre actuel de filtres dans la chaîne.
*/
entier privé n = 0 ;
public static final int INCREMENT = 10 ;
Copiez le code comme suit :
void addFilter (ApplicationFilterConfig filterConfig) {
// Empêche que le même filtre soit ajouté plusieurs fois
pour (filtre ApplicationFilterConfig : filtres)
si(filter==filterConfig)
retour;
si (n == filtres.longueur) {
ApplicationFilterConfig[] newFilters =
nouveau ApplicationFilterConfig[n + INCREMENT] ;
System.arraycopy(filters, 0, newFilters, 0, n);
filtres = nouveauxFilters ;
}
filtres[n++] = filtreConfig;
}
La variable n est utilisée pour enregistrer le nombre de filtres dans la chaîne de filtres actuelle. Par défaut, n est égal à 0, et la longueur du tableau d'objets ApplicationFilterConfig est également égale à 0, donc lorsque la méthode addFilter() est appelée. la première fois, if (n == filters .length) est vrai et la longueur du tableau ApplicationFilterConfig est modifiée. Ensuite, filters[n++] = filterConfig; placez la variable filterConfig dans le tableau ApplicationFilterConfig et ajoutez 1 au nombre de filtres dans la chaîne de filtres actuelle.
Alors, où est appelée la méthode addFilter() d'ApplicationFilterChain ?
C'est dans la méthode createFilterChain() de la classe ApplicationFilterFactory.
Copiez le code comme suit :
public ApplicationFilterChain créerFilterChain
(Requête ServletRequest, wrapper Wrapper, servlet Servlet) {
// récupère le type du répartiteur
Répartiteur DispatcherType = null ;
if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
répartiteur = (DispatcherType) request.getAttribute(DISPATCHER_TYPE_ATTR);
}
Chaîne requestPath = null ;
Attribut d'objet = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
if (attribut != null){
requestPath = attribut.toString();
}
// S'il n'y a pas de servlet à exécuter, renvoie null
si (servlet == null)
retour (nul);
comète booléenne = faux ;
// Créer et initialiser un objet chaîne de filtres
ApplicationFilterChain filterChain = null ;
if (demande instance de requête) {
Demande req = (Demande) demande ;
comète = req.isComet();
si (Globals.IS_SECURITY_ENABLED) {
// Sécurité : Ne pas recycler
filterChain = new ApplicationFilterChain();
si (comète) {
req.setFilterChain(filterChain);
}
} autre {
filterChain = (ApplicationFilterChain) req.getFilterChain();
si (filterChain == null) {
filterChain = new ApplicationFilterChain();
req.setFilterChain(filterChain);
}
}
} autre {
//Répartiteur de requêtes utilisé
filterChain = new ApplicationFilterChain();
}
filterChain.setServlet(servlet);
filterChain.setSupport
(((StandardWrapper)wrapper).getInstanceSupport());
// Acquérir les mappages de filtres pour ce contexte
Contexte StandardContext = (StandardContext) wrapper.getParent();
FilterMap filterMaps[] = context.findFilterMaps();
// S'il n'y a pas de mappages de filtres, nous avons terminé
if ((filterMaps == null) || (filterMaps.length == 0))
retour (filterChain);
// Acquérir les informations dont nous aurons besoin pour faire correspondre les mappages de filtres
String servletName = wrapper.getName();
// Ajoutez les filtres mappés de chemin pertinents à cette chaîne de filtres
pour (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continuer;
}
si (!matchFiltersURL(filterMaps[i], requestPath))
continuer;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
si (filterConfig == null) {
// FIXME - problème de configuration du journal
continuer;
}
booléen isCometFilter = false ;
si (comète) {
essayer {
isCometFilter = filterConfig.getFilter() instance de CometFilter ;
} attraper (Exception e) {
// Remarque : le try catch est là car getFilter a beaucoup de
// exceptions déclarées Cependant, le filtre est beaucoup alloué.
// plus tôt
Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
}
si (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} autre {
filterChain.addFilter(filterConfig);
}
}
// Ajoute des filtres qui correspondent au nom du servlet en second
pour (int i = 0; i < filterMaps.length; i++) {
if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
continuer;
}
si (!matchFiltersServlet(filterMaps[i], servletName))
continuer;
ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
context.findFilterConfig(filterMaps[i].getFilterName());
si (filterConfig == null) {
// FIXME - problème de configuration du journal
continuer;
}
booléen isCometFilter = false ;
si (comète) {
essayer {
isCometFilter = filterConfig.getFilter() instance de CometFilter ;
} attraper (Exception e) {
// Remarque : le try catch est là car getFilter a beaucoup de
// exceptions déclarées Cependant, le filtre est beaucoup alloué.
// plus tôt
}
si (isCometFilter) {
filterChain.addFilter(filterConfig);
}
} autre {
filterChain.addFilter(filterConfig);
}
}
// Renvoie la chaîne de filtres terminée
retour (filterChain);
}
Le code ci-dessus peut être divisé en deux sections, la première section avant la ligne 51 et la deuxième section après la ligne 51.
L'objectif principal du premier paragraphe est de créer l'objet ApplicationFilterChain et de définir certains paramètres.
L'objectif principal du deuxième paragraphe est d'obtenir toutes les informations de filtre à partir du contexte, puis d'utiliser une boucle for pour parcourir et appeler filterChain.addFilter(filterConfig); mettre filterConfig dans le tableau ApplicationFilterConfig de l'objet ApplicationFilterChain.
Alors, où est appelée la méthode createFilterChain() de la classe ApplicationFilterFactory ?
Il est appelé dans la méthode Invoke() de la classe StandardWrapperValue.
Puisque la méthode Invoke() est longue, de nombreux endroits sont omis.
Copiez le code comme suit :
appel public final void (demande de demande, réponse de réponse)
lance IOException, ServletException {
...Omettre le code intermédiaire // Créer la chaîne de filtres pour cette requête
Usine ApplicationFilterFactory =
ApplicationFilterFactory.getInstance();
ApplicationFilterChain filtreChain =
factory.createFilterChain(requête, wrapper, servlet) ;
...omettre le code intermédiaire
filterChain.doFilter(request.getRequest(), réponse.getResponse());
...omettre le code intermédiaire
}
Le processus normal devrait être le suivant :
Appelez la méthode createFilterChain() de la classe ApplicationFilterChai dans la méthode Ensure() de la classe StandardWrapperValue ---> appelez la méthode addFilter() de la classe ApplicationFilterChain dans la méthode createFilterChain() de la classe ApplicationFilterChai ---> appelez la Méthode addFilter() de la classe ApplicationFilterChain Attribue une valeur au tableau ApplicationFilterConfig.
D'après le code ci-dessus, on peut voir que la méthode Invocation() de la classe StandardWrapperValue continuera à exécuter la méthode doFilter() de la classe ApplicationFilterChain après avoir exécuté la méthode createFilterChain(), puis la méthode internalDoFilter() sera appelé dans la méthode doFilter().
Ce qui suit fait partie du code de la méthode internalDoFilter()
Copiez le code comme suit :
// Appelle le filtre suivant s'il y en a un
si (pos < n) {
//Obtenir le filtre suivant et déplacer le pointeur vers le bas d'une position
//pos, il identifie le filtre que l'ApplicationFilterChain actuelle (chaîne de filtres actuelle) exécute
ApplicationFilterConfig filterConfig = filtres[pos++];
Filtre filtre = nul ;
essayer {
//Obtenir l'instance du filtre actuellement pointé
filtre = filtreConfig.getFilter();
support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
filtre, requête, réponse) ;
if (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
Booléen.FALSE);
}
si (Globals.IS_SECURITY_ENABLED) {
finale ServletRequest req = requête ;
finale ServletResponse res = réponse ;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege
("doFilter", filtre, classType, arguments, principal);
} autre {
//Appelle la méthode doFilter() de Filter
filter.doFilter(requête, réponse, ceci);
}
Le filter.doFilter(request, response, this); consiste ici à appeler la méthode doFilter() dans le TestFilter que nous avons créé précédemment. La méthode doFilter() dans TestFilter continuera à appeler la méthode chain.doFilter(request, Response); et cette chaîne est en fait la ApplicationFilterChain, donc le processus appelant revient à appeler le dofilter et à appeler la méthode internalDoFilter ci-dessus, et ceci l'exécution continue jusqu'à ce que le filtre à l'intérieur les exécute tous.
Si deux filtres sont définis, les résultats du débogage sont les suivants :