Préface
Notez que pour enregistrer le code, HttpServLetRequest n'a pas été déclaré dans le corps de la méthode et la fosse percée a été directement injectée avec Autowire.
Conclusion: pour ceux qui sont anxieux. DÉCLAREZ HTTPSERVETREQUEST directement sur la variable membre du contrôleur à l'aide de @Autowire, qui est en toute sécurité!
@ControllerPublic Class TestController {@autowire httpServLetRequest Request; @RequestMapping ("/") public void test () {request.getAttribute ("uid"); }}La conclusion est comme ci-dessus.
arrière-plan
C'est vrai. Étant donné que j'ai ajouté des informations d'authentification à la tête de la demande dans le projet, et après que l'intercepteur intercepte les informations et transmet la vérification, j'ajouterai l'identité de l'utilisateur actuel à l'attribut de la demande, ce qui est pratique pour le réutiliser dans la couche de contrôleur.
Question: Pourquoi ne pas utiliser @RequestHeader pour le récupérer directement sur le contrôleur? Étant donné que l'en-tête contient des données cryptées et nécessite une authentification et un jugement complexes, cette étape est directement jetée dans l'intercepteur pour exécution.
Ainsi, après décryptage, j'ai défini les informations utilisateur (telles que UID) dans request.setAttribute() pour l'extraire dans le contrôleur.
Si vous devez utiliser la demande, vous devez généralement le déclarer sur la méthode, telle que:
Résultat public Save (HttpServLetRequest Request) {// DoSomething ();}Donc, si j'utilise UID pour chaque méthode, toutes les méthodes ne déclareraient-elles pas de paramètre de demande, afin de sauvegarder une étape redondante? J'ai écrit une classe de base.
classe publique CommonController {@autowire httpservletReqeUst request; public String getUID () {return (string) request.getAttribute ("uid"); }}Plus tard, je craignais que, parce que le contrôleur soit un singleton, cela entraînera la demande ultérieure couvrant la demande précédente, et il y a des problèmes de sécurité de fil dans des conditions de concurrence. J'ai donc posé une question sur segmentfault, et la plupart des internautes ont dit qu'il y avait en effet un problème de filetage! Adresse du problème du segmentfault ### Processus de vérification Parce que la plupart des opinions des internautes sont qu'ils ne peuvent les déclarer qu'en termes de méthodes, je ne veux naturellement pas abandonner autant de code tout à l'heure, alors j'ai commencé mon processus de vérification. Les programmeurs enthousiastes m'ont fourni plusieurs solutions. Depuis que j'ai fait l'effort pour le prouver, je vais mettre les résultats ici et les partager avec vous.
Méthode 1
La première méthode consiste à afficher la déclaration httpsservletReqeust dans la méthode du contrôleur, le code est le suivant:
@RequestMapping ("/ test") @ restControllerPublic class ctest {logger logger = loggerfactory.getLogger (getClass ()); @RequestMapping ("/ iiii") Public String Test (HttpServLetRequest Request) {logger.info (request.hashcode () + ""); retourner null; }}Appuyez sur F5 dans le navigateur
Sortir
J'étais confus à ce moment-là, ** J'ai accepté d'être la sécurité des fils! ** n'est-ce pas la même demande? Vous plaisantez j'espère! Je recherche depuis longtemps la demande de réécriture de HashCode ()!
Ah, c'est la vérité, parce que j'appuie F5 avec mon navigateur, et peu importe à quel point je le presse, je ne peux pas simuler la concurrence. Cela équivaut au serveur en utilisant le même thread pour traiter ma demande. En ce qui concerne le code de hash de cette demande, selon JDK, il est calculé sur la base de l'adresse virtuelle de l'OBJ dans JVM. Je suppose que ce qui s'est passé ensuite. Si vous savez ce que vous voulez vraiment, je vais me le dire!
deviner
L'espace mémoire de la demande demandée par chaque thread du serveur est corrigé lorsque le serveur est démarré. Ensuite, chaque fois que je demande, il créera une nouvelle demande dans l'espace mémoire qu'il a demandé (peut-être une structure similaire à un tableau). (Similaire au point de départ du tableau est toujours la même adresse mémoire). Ensuite, je lance une demande, et il créera une nouvelle demande en position de départ et la transmet au servlet et commencera à traiter. Une fois le traitement terminé, il sera détruit. Ensuite, la nouvelle demande créée par sa prochaine demande est détruite, donc elle commence à partir de l'adresse de départ. De cette façon, tout sera expliqué!
La supposition est terminée
Vérifiez la conjecture:
Je ne le laisserai pas avoir le temps de le détruire, puis-je tester le code
@RequestMapping ("/ test") @ restControllerPublic class ctest {logger logger = loggerfactory.getLogger (getClass ()); @RequestMapping ("/ oooo") public String testa (httpServleRequest request) lève l'exception {thread.sleep (3000); logger.info (request.hashcode () + ""); logger.info (reqeust.getheader ("uid"); return null;} @RequestMapping ("/ iiii") Public String test (httpservletRequest request) {logger.info (request.hashcode () + ""); logger.info (reqeust.getheder ("uid"); renvoyer null;}.Comme mentionné ci-dessus, je dors dans l'interface / oooo pendant 3 secondes. S'il partage une demande, la demande suivante écrasera la demande dans le sommeil, et l'UID entrant est l'adresse d'interface. Démarrer / Oooo d'abord puis démarrer / IIII
Sortir
Controller.CTEST: 33 - 364716268Controller.CTEST: 34 - IIIIController.CTEST: 26 - 1892130707Controller.CTEST: 27 - OOOOO
Conclusion: 1. Le / III initié plus tard ne remplace pas les données précédentes / OOOO et il n'y a pas de problème de sécurité de thread. 2. Le code de hash de la demande est différent. Parce que le blocage / oooo provoque un autre fil à le traiter, il crée une nouvelle demande au lieu du même code de hash qu'auparavant.
Deuxième cycle de vérification
classe publique httpTest {public static void main (String [] args) lève une exception {pour (int i = 300; i> 0; i--) {final int finali = i; nouveau thread () {@Override public void run () {System.out.println ("v ###" + fini); Httprequest.get ("http: // localhost: 8080 / test / iiii?") .Header ("uid", "v ###" + fini) .send (); } }.commencer(); }}}Dans des conditions de concurrence simulées, UID300 dans l'en-tête accepte pleinement sans remplacer
Donc, de cette façon, il n'y a pas de problème de sécurité de fil.
Méthode 2
Dans CommonController, utilisez @ModelAttribute pour gérer.
classe publique CommonController {// @autowired protected httpservletRequest request; @ModelAttribute public void bindReq (httpServleRequest request) {this.request = request; } String protégé getUID () {System.out.println (request.toString ()); return request.getAttribute ("uid") == null? null: (String) request.getAttribute ("uid"); }}Cela a des problèmes de sécurité des fils! La demande suivante peut couvrir la précédente!
Le code de vérification
@ RestController @ requestmapping ("/ test") public class CTest étend CommonController {logger logger = loggerfactory.getLogger (getClass ()); @RequestMapping ("/ iiii") public String test () {logger.info (request.getheader ("uid")); retourner null; }} classe publique httpTest {public static void main (String [] args) lève une exception {pour (int i = 100; i> 0; i--) {final int finali = i; nouveau thread () {@Override public void run () {System.out.println ("v ###" + fini); Httprequest.get ("http: // localhost: 8080 / test / iiii") .header ("uid", "v ###" + fini) .send (); } }.commencer(); }}}Les résultats de sortie partiels ont été interceptés
Controller.CTEST: 26 - V ### 52Controller.CTEST: 26 - V ### 13Controller.CTEST: 26 - V ### 57Controller.CTEST: 26 - V ### 57Controller.CTEST: 26 - V ### 21Controller. V ### 82Controller.CTEST: 26 - V ### 93Controller.CTEST: 26 - V ### 71Controller.CTEST: 26 - V ### 71Controller.CTEST: 26 - V ### 71Controller.CTOT v ### 71Controller.CTEST: 26 - V ### 85Controller.CTEST: 26 - V ### 85Controller.CTEST: 26 - V ### 14Controller.CTEST: 26 - V ### 47Controller.CTOT V ### 22Controller.CTEST: 26 - V ### 55Controller.CTEST: 26 - V ### 61
Vous pouvez voir que 57, 71, 85 et 47 sont couverts, et certaines demandes sont perdues!
Le faire est l'insecture par le thread!
Méthode 3
Utilisez CommonController comme classe de base pour demander Autowire.
classe publique CommonController {@autowired protected httpservletRequest request; String protégé getUID () {System.out.println (request.toString ()); return request.getAttribute ("uid") == null? null: (String) request.getAttribute ("uid"); }}L'interface de test est la même que ci-dessus, et les résultats sont gratifiants! Il n'y a pas de couverture pour 100 demandes. J'ai augmenté la portée et l'ai testé cinq ou six fois, et aucune couverture pour des milliers de demandes. Cela peut prouver qu'il n'y a pas de problème de sécurité de fil dans cette méthode d'écriture!
Une autre chose intéressante est que, peu importe la quantité de concurrence utilisée, le code de hash de la demande est toujours le même. De plus, lors du test de différentes interfaces dans le même contrôleur, c'est la même chose. Lors de l'utilisation du bloc pour forcer le bloc, le code de hash est le même. Cependant, le HashCode est différent lors de l'accès à différents contrôleurs, donc je n'ai pas continué à approfondir la façon de l'implémenter.
Mais la conclusion est terminée, tout comme l'article l'a dit au début.
Résumer
Ce qui précède est l'intégralité du contenu de cet article. J'espère que le contenu de cet article a une certaine valeur de référence pour l'étude ou le travail de chacun. Si vous avez des questions, vous pouvez laisser un message pour communiquer. Merci pour votre soutien à wulin.com.