Prefacio
Tenga en cuenta que para guardar el código, HttpServletRequest no se declaró en el cuerpo del método, y el pozo perforado se inyectó directamente con AutoWire.
Conclusión: para aquellos que están ansiosos. Declare httpservletRequest directamente en la variable miembro del controlador usando @AUTOWIRE, ¡que es seguro!
@ControllerPublic Class TestController {@AUTOWIRE httpservletRequest solicitud; @RequestMapping ("/") public void test () {request.getAttribute ("uid"); }}La conclusión es la anterior.
fondo
Esto es cierto. Dado que agregué información de autenticación al jefe de la solicitud en el proyecto, y después de que el interceptor intercepta la información y transfiera la verificación, agregaré la identidad del usuario actual al atributo de la solicitud, lo cual es conveniente para reutilizarla en la capa del controlador.
Pregunta: ¿Por qué no usar @RQUESTHEADER para recuperarlo directamente en el controlador? Debido a que el encabezado contiene datos cifrados y requiere una autenticación y juicio complejos, este paso se arroja directamente al interceptor para su ejecución.
Entonces, después del descifrado, establecí la información del usuario (como UID) en request.setAttribute() para extraerla en el controlador.
Si necesita usar la solicitud, generalmente debe declararla en el método, como:
Public Result Save (httpservletRequest solicitud) {// dosomething ();}Entonces, si uso UID para cada método, ¿no todos los métodos declararían un parámetro de solicitud para guardar un paso redundante? Escribí una clase base.
Public Class CommonController {@AUTOWIRE httpservletreqeust solicitud; public String getuid () {return (string) request.getAttribute ("uid"); }}Más tarde, me preocupó que debido a que el controlador es un singleton, esto dará como resultado el requisito posterior que cubre la solicitud anterior, y hay problemas de seguridad de subprocesos en condiciones de concurrencia. ¡Así que hice una pregunta en SegmentFault, y la mayoría de los internautas dijeron que de hecho hay un problema de enhebrado! SegmentFault Problem Dirección ### Proceso de verificación Debido a que la mayoría de las opiniones de los internautas son que solo pueden declararlos en términos de métodos, naturalmente no quiero dejar de escribir tanto código en este momento, así que comencé mi proceso de verificación. Los entusiastas programadores me han proporcionado varias soluciones. Como me he esforzado por demostrarlo, pondré los resultados aquí y los compartiré contigo.
Método 1
El primer método es mostrar la declaración httpservletreqeust en el método del controlador, el código es el siguiente:
@RequestMapping ("/Test")@RestControllerPublic Class CTest {logger logger = loggerFactory.getLogger (getClass ()); @RequestMapping ("/iiii") prueba de cadena pública (solicitud httpservletRequest) {logger.info (request.hashcode () + ""); regresar nulo; }}Presione F5 en el navegador
Producción
Estaba confundido en ese momento, ** ¡Acordé ser la seguridad del hilo! ** ¿No es esta la misma solicitud? ¡Me estás tomando el pelo! ¡He estado buscando mucho tiempo para reescribir para reescribir hashcode ()!
Ah, esta es la verdad, porque presiono F5 con mi navegador, y no importa cuánto lo presione, no puedo simular la concurrencia. Eso es equivalente al servidor que usa el mismo hilo para procesar mi solicitud. En cuanto al hashcode de esta solicitud, según JDK, se calcula en función de la dirección virtual de OBJ en JVM. Supongo que lo que pasó después. Si sabes lo que realmente quieres, ¡me diré!
adivinar
El espacio de memoria de la solicitud solicitada por cada hilo en el servidor se soluciona cuando se inicia el servidor. Luego, cada vez que solicito, creará una nueva solicitud en el espacio de memoria que solicitó (tal vez una estructura similar a una matriz). (Similar al punto de partida de la matriz es siempre la misma dirección de memoria). Luego inicio una solicitud, y él creará una nueva solicitud en la posición de inicio y la pasará al servlet y comenzará a procesar. Después de completar el procesamiento, será destruido. Luego, la nueva solicitud creada por su próxima solicitud se destruye, por lo que comienza desde la dirección inicial. De esta manera, ¡todo se explicará!
La suposición está terminada
Verificar conjetura:
No dejaré que tenga tiempo para destruirlo, ¿puedo probar el código?
@RequestMapping ("/Test")@RestControllerPublic Class CTest {logger logger = loggerFactory.getLogger (getClass ()); @RequestMapping ("/oooo") public String testa (httpservletRequest solicitud) lanza la excepción {Thread.sleep (3000); logger.info (request.hashcode () + ""); logger.info (reqeust.getheader ("uid"); return null;} @RequestMapping ("/iiii") Test de cadena pública (httpservletRequest request) {logger.info (request.hashcode () + ""); logger.info (reqeusust.getheader ("uid"); regreso null;}Como se mencionó anteriormente, duermo en la interfaz/oooo durante 3 segundos. Si comparte un reqeust, la solicitud posterior sobrescribirá el reqeust en el sueño, y el UID entrante es la dirección de la interfaz. Iniciar /oooo primero y luego comenzar /iiii
Producción
controlador.ctest: 33 - 364716268Controller.ctest: 34 - iiiicontroller.ctest: 26 - 1892130707Controller.ctest: 27 - ooooo
Conclusión: 1. El /III iniciado más tarde no sobrescribe los datos anteriores /OOOO y no hay un problema de seguridad de hilos. 2. El húsico de la solicitud es diferente. Debido a que el bloqueo de /oooo hace que otro hilo necesite procesarlo, crea una nueva solicitud en lugar del mismo hashcode que antes.
Segunda ronda de verificación
public class httptest {public static void main (string [] args) lanza excepción {for (int i = 300; i> 0; i--) {final int finali = i; new Thread () {@Override public void run () {system.out.println ("v ###" + finali); Httprequest.get ("http: // localhost: 8080/test/iiii?") .Header ("uid", "v ###" + finali) .send (); } }.comenzar(); }}}En condiciones de concurrencia simuladas, UID300 en el encabezado acepta completamente sin anular
Así que de esta manera, no hay problema de seguridad de hilos.
Método 2
En CommonController, use @modelattribute para manejar.
Public Class CommonController {// @aUtowired HTTPServletRequest solicitud; @Modelattribute public void bindReq (httpservletrequest solicitud) {this.request = request; } Cadena protegida getuid () {System.out.println (request.ToString ()); return request.getAttribute ("uid") == null? nulo: (string) request.getAttribute ("uid"); }}¡Esto tiene problemas de seguridad de hilos! ¡La solicitud posterior puede cubrir la anterior!
Código de verificación
@RestController@requestmapping ("/test") public class CTest extiende CommonController {logger logger = loggerFactory.getLogger (getClass ()); @RequestMapping ("/iiii") public String test () {logger.info (request.getheader ("uid")); regresar nulo; }} public class httptest {public static void main (string [] args) lanza excepción {for (int i = 100; i> 0; i--) {final int finali = i; new Thread () {@Override public void run () {system.out.println ("v ###" + finali); Httprequest.get ("http: // localhost: 8080/test/iiii") .header ("uid", "v ###" + finali) .send (); } }.comenzar(); }}}Los resultados de la salida parcial fueron interceptados
controlador.ctest: 26 - v ### 52Controller.ctest: 26 - V ### 13Controller.ctest: 26 - V ### 57Controller.ctest: 26 - V ### 57Controller.ctest: 26 - V ###11Controller.ctest: 26 - V ### 10Controller.ctest: 26 - V ## 32Controller.ctest V ### 82Controller.Ctest: 26 - V ### 93Controller.Ctest: 26 - V ### 71Controller.ctest: 26 - V ### 71Controller.ctest: 26 - V ### 71Controller.ctest: 26 - V ### 71Controller.ctest: 26 - V ## 31Controller v###71controller.CTest:26 - v###85controller.CTest:26 - v###85controller.CTest:26 - v###14controller.CTest:26 - v###47controller.CTest:26 - v###47controller.CTest:26 - v###69controller.CTest:26 - V ### 22Controller.Ctest: 26 - V ### 55Controller.Ctest: 26 - V ### 61
Puede ver que se cubren 57, 71, 85 y 47, ¡y se pierden algunas solicitudes!
¡Hacerlo es Insecure de hilo!
Método 3
Use CommonController como la clase base para solicitar AutoWire.
Public Class CommonController {@aUtowired HTTPServletRequest solicitud; Cadena protegida getuid () {System.out.println (request.ToString ()); return request.getAttribute ("uid") == null? nulo: (string) request.getAttribute ("uid"); }}La interfaz de prueba es la misma que la anterior, ¡y los resultados son gratificantes! No hay cobertura para 100 solicitudes. Aumenté el alcance y lo probé cinco o seis veces, y no tenía cobertura para miles de solicitudes. ¡Esto puede demostrar que no hay ningún problema de seguridad en el hilo en este método de escritura!
Otra cosa interesante es que no importa cuánta concurrencia se use, el cloqueo de la solicitud es siempre el mismo. Además, al probar diferentes interfaces en el mismo controlador, es lo mismo. Cuando se usa Sleep to Force Block, el HASHCODE es el mismo. Sin embargo, el húsico es diferente cuando se accede a diferentes controladores, por lo que no seguí profundizando en cómo implementarlo.
Pero la conclusión sale, tal como dijo el artículo al principio.
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.