머리말
코드를 저장하기 위해 HttpservletRequest는 방법 본문에서 선언되지 않았으며 드릴 구덩이는 Autowire를 직접 주입했습니다.
결론 : 불안한 사람들에게. @autowire를 사용하여 컨트롤러의 멤버 변수에서 httpservletrequest를 직접 선언하십시오.
@ControllerPublic 클래스 TestController {@autowire httpservletrequest 요청; @requestmapping ( "/") public void test () {request.getAttribute ( "uid"); }}결론은 위와 같습니다.
배경
이것은 사실입니다. 프로젝트의 요청 헤드에 인증 정보를 추가하고 인터셉터가 정보를 가로 채고 확인을 전달 한 후 현재 사용자의 ID를 요청의 속성에 추가하여 컨트롤러 계층에서 재사용하는 데 편리합니다.
질문 : @requestheader를 사용하여 컨트롤러에서 직접 검색하지 않는 이유는 무엇입니까? 헤더에는 암호화 된 데이터가 포함되어 있으며 복잡한 인증 및 판단이 필요하기 때문에이 단계는 실행을 위해 인터셉터에 직접 던져집니다.
따라서 암호 해독 후 사용자 정보 (예 : UID)를 request.setAttribute() 로 설정하여 컨트롤러에서 추출합니다.
요청을 사용해야하는 경우 일반적으로 다음과 같은 방법에 따라 요청을 선언해야합니다.
공개 결과 저장 (httpservletrequest 요청) {// dosomething ();}따라서 각 메소드에 UID를 사용하는 경우 중복 단계를 저장하기 위해 모든 메소드가 요청 매개 변수를 선언하는 것은 아닙니다. 나는 기본 수업을 썼습니다.
공개 클래스 CommonController {@autowire httpservletreqeust 요청; public String getUid () {return (string) request.getAttribute ( "uid"); }}나중에 나는 컨트롤러가 싱글 톤이기 때문에, 이로 인해 이전 요청을 다루는 후속 통찰력이 발생하고 동시성 조건 하에서 스레드 안전 문제가 발생한다고 걱정했다. 그래서 나는 Segmentfault에 대한 질문을했고, 대부분의 Netizens는 실제로 스레딩 문제가 있다고 말했습니다! SegmentFault 문제 주소 ### 검증 프로세스 대부분의 네티즌 의견은 방법 측면에서만 선언 할 수 있다는 것입니다. 자연스럽게 많은 코드를 포기하고 싶지 않기 때문에 확인 프로세스를 시작했습니다. 열정적 인 프로그래머는 몇 가지 솔루션을 제공했습니다. 나는 그것을 증명하기 위해 노력했기 때문에, 나는 결과를 여기에 넣고 당신과 공유 할 것입니다.
방법 1
첫 번째 방법은 컨트롤러 메소드에 선언 httpservletreqeust를 표시하는 것입니다. 코드는 다음과 같습니다.
@requestmapping ( "/test")@restControllerPublic Class Ctest {logger = loggerfactory.getLogger (getClass ()); @requestmapping ( "/iiii") 공개 문자열 테스트 (httpservletrequest request) {logger.info (request.hashcode () + ""); 널 리턴; }}브라우저에서 F5를 누릅니다
산출
나는 그 당시 혼란 스러웠다. ** 나는 실 안전이되기로 동의했다! ** 이것은 같은 요청이 아닌가? 농담 해요! hashcode ()를 다시 작성하기 위해 오랜 시간을 찾고 있습니다!
아, 이것은 진실입니다. 브라우저로 F5를 누르기 때문에 아무리 힘든지에 관계없이 동시성을 시뮬레이션 할 수 없습니다. 이는 동일한 스레드를 사용하여 요청을 처리하기 위해 서버와 동일합니다. JDK에 따르면이 요청의 해시 코드는 JVM에서 OBJ의 가상 주소를 기반으로 계산됩니다. 다음에 무슨 일이 있었는지 추측합니다. 당신이 정말로 원하는 것을 알고 있다면 말해 줄게!
추측하다
서버의 각 스레드가 적용한 요청의 메모리 공간은 서버가 시작될 때 수정됩니다. 그런 다음 요청할 때마다 그가 요청한 메모리 공간에서 새로운 요청을 만들 것입니다 (어쩌면 배열과 유사한 구조). (배열의 시작점과 유사한 것은 항상 동일한 메모리 주소입니다). 그런 다음 요청을 시작한 후 시작 위치에 새 요청을 만들어 서블릿으로 전달하고 시작 처리를 시작합니다. 처리가 완료되면 파괴됩니다. 그런 다음 다음 요청으로 생성 된 새 요청이 파괴되므로 시작 주소에서 시작됩니다. 이런 식으로 모든 것이 설명 될 것입니다!
추측이 끝났습니다
추측 확인 :
나는 그가 그것을 파괴 할 시간을 가지지 않을 것입니다. 코드를 테스트 할 수 있습니까?
@requestmapping ( "/test")@restControllerPublic Class Ctest {logger = loggerfactory.getLogger (getClass ()); @requestmapping ( "/oooo") public string testa (httpservletrequest 요청) 예외 {thread.sleep (3000); logger.info (request.hashcode () + ""); logger.info (reqeust.getheader ( "uid"); return null;} @requestmapping ( "/iiii") public String test (httpservletrequest request) {logger.info (reques.hashcode () + "); logger.info ("uid ");위에서 언급했듯이 인터페이스/oooo에서 3 초 동안 자고 있습니다. 그것이 reqeust를 공유하면, 후속 요청은 수면에서 reqeust를 덮어 쓰고, 들어오는 UID는 인터페이스 주소입니다. 먼저 /oooo를 시작한 다음 시작 /iiii
산출
Controller.Ctest : 33-364716268 Controller.ctest : 34 -IIIICONTROLLER.CTEST : 26-1892130707 Controller.ctest : 27 -OOOOO
결론 : 1. 나중에 시작된 /III는 이전 /OOOO 데이터를 덮어 쓰지 않으며 스레드 안전 문제가 없습니다. 2. 요청의 해시 코드는 다릅니다. /OOOO 차단으로 인해 다른 스레드가 처리해야하므로 이전과 동일한 해시 코드 대신 새 요청이 생성됩니다.
두 번째 검증 라운드
public class httptest {public static void main (String [] args)은 예외 {for (int i = 300; i> 0; i--) {final int finali = i; 새 스레드 () {@override public void run () {System.out.println ( "v ###" + finali); httprequest.get ( "http : // localhost : 8080/test/iiii?") .Header ( "uid", "v ###" + finali) .send (); } }.시작(); }}}시뮬레이션 된 동시성 조건에서 헤더의 UID300은 우선없이 완전히 수락합니다.
따라서 이런 식으로 스레드 안전 문제가 없습니다.
방법 2
CommonController에서 @ModelAttribute를 사용하여 처리하십시오.
공개 클래스 CommonController {// @autowired 보호 httpservletrequest 요청; @ModelAttribute public void bindreq (httpservletrequest 요청) {this.request = request; } protected String getUid () {System.out.println (request.toString ()); return request.getAttribute ( "uid") == null? null : (string) request.getAttribute ( "uid"); }}스레드 안전 문제가 있습니다! 후속 요청은 이전 요청을 포괄 할 수 있습니다!
확인 코드
@restcontroller@requestmapping ( "/test") public class ctest extends commonController {logger = loggerfactory.getLogger (getClass ()); @requestmapping ( "/iiii") public String test () {logger.info (request.getheader ( "uid")); 널 리턴; }} 공개 클래스 httptest {public static void main (String [] args)은 예외 {for (int i = 100; i> 0; i--) {Final int finali = i; 새 스레드 () {@override public void run () {System.out.println ( "v ###" + finali); httprequest.get ( "http : // localhost : 8080/test/iiii") .Header ( "uid", "v ###" + finali) .send (); } }.시작(); }}}부분 출력 결과가 차단되었습니다
Controller.Ctest : 26 -V ### 52Controller.ctest : 26 -V ### 13Controller.ctest : 26 -V ### 57 Controller.ctest : 26 -V ### 57 Controller.ctest : 26 -V ### 21controller.ctest : 26 -V ### 10 Controller. v ### 82Controller.ctest : 26 -V ### 82Controller.ctest : 26 -V ### 93Controller.ctest : 26 -V ### 71controller.ctest : 26 -V ### 71controller.ctest : 26 -V ### 71controller.ctest : 26 -v ##### 71cler.ctest. -V ### 71controller.ctest : 26 -V ### 71controller.ctest : 26 -v ### 85controller.ctest : 26 -V ### 85controller.ctest : 26 -V ### 14controller.ctest : 26 -v ## 47 Controller.ctest : 26 -v ####### 47 Controller.ctest. -V ### 69controller.ctest : 26 -V ### 22Controller.ctest : 26 -V ### 55Controller.ctest : 26 -V ### 61
57, 71, 85 및 47이 보장되고 일부 요청이 손실된다는 것을 알 수 있습니다!
그렇게하는 것은 스레드 inscure입니다!
방법 3
CommonController를 기본 클래스로 사용하여 Autowire를 요청하십시오.
공개 클래스 CommonController {@autowired 보호 httpservletrequest 요청; 보호 된 문자열 getUid () {System.out.println (request.toString ()); return request.getAttribute ( "uid") == null? null : (string) request.getAttribute ( "uid"); }}테스트 인터페이스는 위와 동일하며 결과는 만족합니다! 100 개의 요청에 대한 적용 범위가 없습니다. 범위를 늘리고 5-6 번 테스트했으며 수천 개의 요청에 대해서는 적용 범위가 없습니다. 이것은이 글쓰기 방법에 스레드 안전 문제가 없음을 증명할 수 있습니다!
또 다른 흥미로운 점은 얼마나 많은 동시성이 사용 되더라도 요청의 해시 코드는 항상 동일하다는 것입니다. 또한 동일한 컨트롤러에서 다른 인터페이스를 테스트 할 때 동일합니다. 수면을 사용하여 강제 블록을 사용하면 해시 코드가 동일합니다. 그러나 해시 코드는 다른 컨트롤러에 액세스 할 때 다르므로 구현 방법에 대해 더 깊이 파고 들지 않았습니다.
그러나 기사가 처음에 말한 것처럼 결론은 나왔습니다.
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.