Prefácio
Observe que, para salvar o código, o httpServletRequest não foi declarado no corpo do método e o poço perfurado foi injetado diretamente com o AutoTeire.
Conclusão: Para aqueles que estão ansiosos. Declare HttpServletRequest diretamente na variável de membro do controlador usando @autowire, que é seguro para seguros!
@ControllerPublic Classe testController {@AUTOWire HttpServletRequest Request; @RequestMapping ("/") public void test () {request.getAttribute ("uid"); }}A conclusão é como acima.
fundo
Isto é verdade. Como adicionei informações de autenticação ao chefe da solicitação no projeto e, após o interceptador interceptar as informações e passar a verificação, adicionarei a identidade do usuário atual ao atributo da solicitação, o que é conveniente para reutilizá -lo na camada do controlador.
Pergunta: Por que não usar @RequestHeader para recuperá -lo diretamente no controlador? Como o cabeçalho contém dados criptografados e requer alguma autenticação e julgamento complexos, esta etapa é jogada diretamente no interceptador para execução.
Então, após a descriptografia, defino as informações do usuário (como o UID) no request.setAttribute() para extraí -las no controlador.
Se você precisar usar a solicitação, geralmente precisará declará -la no método, como:
Resultado público Salvar (httpServletRequest Request) {// doSomething ();}Então, se eu usar o UID para cada método, todo método não declararia um parâmetro de solicitação, a fim de salvar uma etapa redundante? Eu escrevi uma classe base.
classe pública Commoncontroller {@AUTOWire HttPServletReqeust Request; public String getUid () {return (string) request.getAttribute ("uid"); }}Mais tarde, fiquei preocupado com o fato de que, como o controlador é um singleton, isso resultará no Reqeust subsequente que cobre a solicitação anterior e há problemas de segurança de threads em condições de concorrência. Então, fiz uma pergunta sobre o Segmentfault, e a maioria dos internautas disse que realmente há um problema de encadeamento! SegmentFault Problem Endereço ### Processo de verificação Como as opiniões da maioria dos internautas são que elas só podem declará -las em termos de métodos, naturalmente não quero desistir de escrever muito código agora, então iniciei meu processo de verificação. Os programadores entusiasmados me forneceram várias soluções. Desde que fiz o esforço para provar isso, colocarei os resultados aqui e os compartilharei com você.
Método 1
O primeiro método é exibir a declaração httpServletReqeust no método do controlador, o código é o seguinte:
@RequestMapping ("/test")@RestControllerPublic Class cTest {Logger Logger = LoggerFactory.getLogger (getClass ()); @RequestMapping ("/iiii") Teste de String public (httpServLeTrequest Request) {Logger.info (request.hashcode () + ""); retornar nulo; }}Pressione F5 no navegador
Saída
Eu estava confuso naquele momento, ** concordei em ser a segurança do tópico! ** Isso não é o mesmo pedido? Você está brincando comigo! Estou procurando muito tempo para solicitar a reescrita hashcode ()!
Ah, essa é a verdade, porque pressiono F5 com meu navegador, e não importa o quanto eu o pressione, não posso simular a simultaneidade. Isso é equivalente ao servidor usando o mesmo thread para processar minha solicitação. Quanto ao código de hash desta solicitação, de acordo com o JDK, ele é calculado com base no endereço virtual do OBJ na JVM. Eu acho que o que aconteceu a seguir. Se você souber o que realmente quer, eu vou me dizer!
adivinhar
O espaço de memória da solicitação solicitado por cada encadeamento no servidor é corrigido quando o servidor é iniciado. Então, toda vez que solicitar, ele criará uma nova solicitação no espaço de memória que solicitava (talvez uma estrutura semelhante a uma matriz). (Semelhante ao ponto de partida da matriz é sempre o mesmo endereço de memória). Em seguida, inicio uma solicitação e ele criará uma nova solicitação na posição inicial e a passará para o servlet e começará a processar. Após a conclusão do processamento, ele será destruído. Em seguida, a nova solicitação criada por sua próxima solicitação é destruída, para que ela começa a partir do endereço inicial. Dessa forma, tudo será explicado!
O palpite acabou
Verifique a conjectura:
Não vou deixar que ele tenha tempo para destruí -lo, posso testar o código
@RequestMapping ("/test")@RestControllerPublic Class cTest {Logger Logger = LoggerFactory.getLogger (getClass ()); @RequestMapping ("/oooo") public string testa (solicitação httpServletRequest) lança a exceção {thread.sleep (3000); logger.info (request.hashcode () + ""); Logger.info (reqeust.getheader ("uid"); retorna null;} @RequestMapping ("/iiii") Public String Test (httpServletRequest request) {Logger.info (request.hashcode () + "");Como mencionado acima, durmo na interface/oooo por 3 segundos. Se ele compartilha um Reqeust, a solicitação subsequente substituirá o Reqeust no sono e o UID de entrada é o endereço da interface. Iniciar /oooo primeiro e depois start /iiii
Saída
controlador.ctest: 33 - 364716268Controller.Ctest: 34 - iiiicontroller.ctest: 26 - 1892130707Controller.Ctest: 27 - ooooo
Conclusão: 1. O /III iniciado posteriormente não substitui os dados anteriores /oooo e não há problema de segurança de threads. 2. O código de hash da solicitação é diferente. Como o bloqueio /oooo faz com que outro encadeamento precise processá -lo, ele cria uma nova solicitação em vez do mesmo código de hash de antes.
Segunda rodada de verificação
classe pública httptest {public static void main (string [] args) lança exceção {for (int i = 300; i> 0; i--) {final int finali = i; novo thread () {@Override public void run () {System.out.println ("v ###" + finali); Httprequest.get ("http: // localhost: 8080/test/iiii?") .Header ("uid", "v ##" + finali) .send (); } }.começar(); }}}Sob condições simuladas de concorrência, o UID300 no cabeçalho aceita totalmente sem substituir
Portanto, assim, não há problema de segurança de threads.
Método 2
In CommonController, use @modelattribute para manipular.
classe pública Commoncontroller {// @AUTOWIRED HTTPSERVLETREQUEST PROTEIRA PROTECIDADO; @Modelattribute public void bindReq (solicitação httpServletRequest) {this.request = request; } String protegido getUid () {System.out.println (request.toString ()); Return request.getAttribute ("uid") == null? null: (string) request.getAttribute ("uid"); }}Isso tem problemas de segurança de threads! A solicitação subsequente pode cobrir a anterior!
Código de verificação
@RestController@requestmapp ("/test") classe pública ctest estende o CommonController {logger logger = LoggerFactory.getLogger (getClass ()); @RequestMapping ("/iiii") public String test () {Logger.info (request.getheader ("uid")); retornar nulo; }} classe pública httptest {public static void main (string [] args) lança exceção {for (int i = 100; i> 0; i--) {final int finali = i; novo thread () {@Override public void run () {System.out.println ("v ###" + finali); Httprequest.get ("http: // localhost: 8080/test/iiii") .header ("uid", "v ##" + finali) .send (); } }.começar(); }}}Resultados de saída parcial foram interceptados
Controller.Ctest: 26 - V ### 52Controller.Ctest: 26 - V ### 13Controller.Ctest: 26 - V ### 57Controller.CTest: 26 - V ### 57Controller.Ctest: 26 - V ## 21Roller.Ctest: V#26TROLTOL#107 - V #CONTROLT: V #CONTROLLER. v ### 82Controller.Ctest: 26 - V ### 82Controller.Ctest: 26 - V ### 93Controller.CTest: 26 - V ### 71Controller.Ctest: 26 - V ### 71Controller.ctest: 26 - V ### 71Contront.CTront.CTroller.CTOLT.CTROLT. - v ### 71Controller.Ctest: 26 - V ### 71Controller.Ctest: 26 - V ### 85Controller.CTest: 26 - V ### 85Controller.CTest: 26 - V ### 14Controller.Ctest: 26 - V ### 47 47 - V ### 69Controller.Ctest: 26 - V ### 22Controller.Ctest: 26 - V ### 55Controller.CTest: 26 - V ### 61
Você pode ver que 57, 71, 85 e 47 são cobertos e alguns pedidos são perdidos!
Fazer isso é inseguro!
Método 3
Use o CommonController como a classe base para solicitar o AutoTeire.
classe pública CommonController {@AUTOWIRED HTTPSERVLETREQUEST PROTEIRA PROTECIDADA DE ADOUTEDEIRA; String protegido getUid () {System.out.println (request.toString ()); Return request.getAttribute ("uid") == null? null: (string) request.getAttribute ("uid"); }}A interface de teste é a mesma que acima, e os resultados são gratificantes! Não há cobertura para 100 solicitações. Aumentei o escopo e o testei cinco ou seis vezes, e sem cobertura para milhares de solicitações. Isso pode provar que não há problema de segurança de thread neste método de escrita!
Outra coisa interessante é que, não importa quanta simultaneidade seja usada, o código de hash da solicitação é sempre o mesmo. Além disso, ao testar diferentes interfaces no mesmo controlador, é o mesmo. Ao usar o sono para forçar o bloco, o código de hash é o mesmo. No entanto, o HashCode é diferente ao acessar diferentes controladores, então não continuei aprofundando como implementá -lo.
Mas a conclusão foi lançada, assim como o artigo disse no início.
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo tenha certo valor de referência para o estudo ou trabalho de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar. Obrigado pelo seu apoio ao wulin.com.