Spring MVC 가 Controller 층 에 request 를 주입 하 는 구덩이 에 대한 상세 한 설명
코드 를 절약 하기 위해 HttpServletRequest 를 방법 체 에 설명 하지 않 고 autowire 로 드릴 의 구 덩이 를 직접 주입 합 니 다.
결론:마음 이 급 한 사람 에 게.Controller 의 구성원 변수 에 직접@Autowire 를 사용 하여 HttpServletRequest 를 설명 합 니 다.이것 은 스 레 드 가 안전 합 니 다!
@Controller
public class TestController{
@Autowire
HttpServletRequest request;
@RequestMapping("/")
public void test(){
request.getAttribute("uid");
}
}
결론 은 위 와 같다.배경
이 렇 습 니 다.프로젝트 에서 저 는 Request 의 머리 에 인증 정 보 를 넣 었 기 때문에 차단 기 에서 정 보 를 캡 처 하고 검증 을 통과 한 후에 현재 사용자 의 신분 을 request 의 Attribute 에 추가 하여 Controller 층 에서 꺼 내 서 재 활용 할 수 있 습 니 다.
의문:왜 Controller 에서@RequestHeader 를 직접 사용 하지 않 습 니까?header 안 은 암호 화 된 데이터 이 고 복잡 한 인증 을 거 쳐 판단 해 야 하기 때문에 이 단 계 를 차단기 에 버 리 고 실행 합 니 다.
그래서 복호화 한 후에 저 는 사용자 정보(예 를 들 어 uid)를
request.setAttribute()
request 에 설정 하여 Controller 에서 추출 합 니 다.request 를 사용 하려 면 다음 과 같은 방법 으로 설명 해 야 합 니 다.
public Result save(HttpServletRequest request){
// dosomething();
}
그러면 저 는 모든 방법 에 uid 를 사용 해 야 합 니 다.모든 방법 이 하나의 request 인 자 를 설명 하고 불필요 한 절 차 를 절약 하기 위해 서 입 니 다.나 는 기 류 를 하나 썼 다.
public class CommonController{
@Autowire
HttpServletReqeust request;
public String getUid(){
return (String)request.getAttribute("uid");
}
}
나중에 저 는 contrller 가 단일 사례 이기 때문에 이렇게 쓰 면 뒤의 reqeust 가 앞의 request 를 덮어 쓰 고 병발 조건 에서 스 레 드 안전 문제 가 발생 하지 않 을 까 걱정 했 습 니 다.그래서 저 는 segment Fault 에 질문 을 했 습 니 다.대부분의 네티즌 들 은'스 레 드 문제 가 있 습 니 다!'라 고 말 했 습 니 다segmentFault 문제 주소\#\#검증 과정 은 네티즌 들 의 대부분 관점 이 방법 에 만 설명 할 수 있 기 때문에 저 는 자 연 스 럽 게 그렇게 많은 코드 를 쓰 는 것 을 포기 하고 싶 지 않 습 니 다.그래서 제 검증 과정 을 시작 하 겠 습 니 다.열성 적 인 프로그래머 들 이 저 에 게 여러 가지 해결 방안 을 제공 해 주 었 습 니 다.제 가 힘 을 써 서 증명 한 이상 결 과 를 여기에 두 고 여러분 께 공유 하 겠 습 니 다.방법
첫 번 째 방법 은 controller 의 방법 에 Http ServletReqeust 를 표시 하 는 것 입 니 다.코드 는 다음 과 같 습 니 다.
@RequestMapping("/test")
@RestController
public class CTest {
Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/iiii")
public String test(HttpServletRequest request) {
logger.info(request.hashCode() + "");
return null;
}
}
브 라 우 저 에서 F5 미 친 듯 이 누 르 기출력
그때 나 는 어 리 석 었 다.**약속 한 스 레 드 는 안전 하 다!**이 건 뭐야?같은 request 잖 아!왜 놀 리 는 거 야!이 때문에 저 는 오랫동안 request 를 찾 았 습 니 다.hashcode()를 다시 썼 습 니까?
아,사실은 그렇습니다.제 가 브 라 우 저 로 F5 를 미 친 듯 이 눌 렀 기 때문에 아무리 눌 러 도 동시 다발 을 모 의 할 수 없습니다.그러면 서버 가 같은 스 레 드 로 제 요청 을 처리 하 는 것 만으로 도 충분 합 니 다.이 request 의 hashcode 에 대해 jdk 의 말 에 따 르 면 obj 가 jvm 에 있 는 가상 주소 에 따라 계산 한 것 입 니 다.뒤의 일 은 제 가 추측 한 것 입 니 다.만약 에 진정 으로 알 고 싶 은 것 이 있다 면 알려 주 십시오!
추측 하 다.
서버 에 있 는 모든 thread 가 신청 한 request 의 메모리 공간 은 이 서버 가 시 작 될 때 고정 되 어 있 습 니 다.그러면 제 가 요청 할 때마다 그 가 신청 한 메모리 공간(배열 과 같은 구조 일 수 있 습 니 다)에 request 를 새로 만 듭 니 다.(배열 과 같은 시작 점 은 항상 같은 메모리 주소 입 니 다)그러면 제 가 요청 을 하 겠 습 니 다.그 는 시작 위치 에 Request 를 새로 만들어 서 servlet 에 전달 하고 처 리 를 시작 합 니 다.처리 가 끝 난 후에 소각 합 니 다.그러면 그 는 다음 요청 으로 새로 만 든 Request 를 이전 request 가 소각 되 었 기 때문에 시작 주소 부터 만 듭 니 다.그러면 모든 것 이 설명 할 수 있 습 니 다!
추측 이 끝나다
검증 추측:
내 가 없 애 버 릴 시간 없 으 면 되 잖 아.테스트 코드.
@RequestMapping("/test")
@RestController
public class CTest {
Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/oooo")
public String testA(HttpServletRequest request) throws 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.getHeader("uid");
return null;
}
}
위 와 같이 인터페이스/ooo 에서 3 초 동안 휴면 합 니 다.만약 그 가 reqeust 를 함께 사용한다 면 뒤의 요청 은 이 휴면 중의 reqeust 를 덮어 씁 니 다.들 어 오 는 uid 는 인터페이스 주소 입 니 다.먼저 시작/ooo 후 시작/iii출력
controller.CTest:33 - 364716268
controller.CTest:34 - iiii
controller.CTest:26 - 1892130707
controller.CTest:27 - oooo
결론:1.나중에 시 작 된/ii 는 앞/ooo 의 데 이 터 를 덮어 쓰 지 않 았 고 스 레 드 안전 문제 가 없습니다.2.request 의 hashcode 는 다 릅 니 다./ooo 의 차단 으로 인해 다른 스 레 드 를 처리 해 야 하기 때문에 그 는 이전 과 같은 모든 hashcode 가 아 닌 request 를 새로 만 들 었 습 니 다.이차 검증
public class HttpTest {
public static void main(String[] args) throws Exception {
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();
}
}.start();
}
}
}
아 날로 그 병행 조건 에서 header 의 uid 300 개 는 완전히 받 아들 여 덮어 쓰 지 않 았 습 니 다.그래서 이런 방식 은 라인 안전 문제 가 없다.
방법
CommonController 에서@ModelAttribute 로 처리 합 니 다.
public class CommonController {
// @Autowired
protected HttpServletRequest request;
@ModelAttribute
public void bindreq(HttpServletRequest request) {
this.request = request;
}
protected String getUid() {
System.out.println(request.toString());
return request.getAttribute("uid") == null ? null : (String) request.getAttribute("uid");
}
}
이렇게 하 는 것 은 라인 안전 문제 가 있다!뒤의 request 는 이전의 것 을 덮어 쓸 수 있 습 니 다!인증 코드
@RestController
@RequestMapping("/test")
public class CTest extends CommonController {
Logger logger = LoggerFactory.getLogger(getClass());
@RequestMapping("/iiii")
public String test() {
logger.info(request.getHeader("uid"));
return null;
}
}
public class HttpTest {
public static void main(String[] args) throws Exception {
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();
}
}.start();
}
}
}
일부 출력 결 과 를 캡 처 하 였 습 니 다.
controller.CTest:26 - v###52
controller.CTest:26 - v###13
controller.CTest:26 - v###57
controller.CTest:26 - v###57
controller.CTest:26 - v###21
controller.CTest:26 - v###10
controller.CTest:26 - v###82
controller.CTest:26 - v###82
controller.CTest:26 - v###93
controller.CTest:26 - v###71
controller.CTest:26 - v###71
controller.CTest:26 - v###85
controller.CTest:26 - v###85
controller.CTest:26 - v###14
controller.CTest:26 - v###47
controller.CTest:26 - v###47
controller.CTest:26 - v###69
controller.CTest:26 - v###22
controller.CTest:26 - v###55
controller.CTest:26 - v###61
57,71,85,47 이 덮 여 있 고 일부 request 를 잃 어 버 렸 습 니 다!이렇게 하 는 것 은 라인 이 안전 하지 않다!
방법
CommonController 를 기본 클래스 로 사용 하여 request Autowire 를 사용 합 니 다.
public class CommonController {
@Autowired
protected HttpServletRequest request;
protected String getUid() {
System.out.println(request.toString());
return request.getAttribute("uid") == null ? null : (String) request.getAttribute("uid");
}
}
테스트 인터페이스 가 같 아서 결과 가 반 갑 습 니 다!100 개의 request 는 덮어 쓰 지 않 았 습 니 다.저 는 범 위 를 넓 혀 서 대여섯 번 을 측 정 했 습 니 다.수천 번 의 요청 은 덮어 쓰 지 않 았 습 니 다.이런 쓰기 방법 은 스 레 드 안전 문제 가 없다 는 것 을 증명 할 수 있 습 니 다!또 하나의 재 미 있 는 것 은 아무리 많은 병발 을 사용 하 더 라 도 request 의 hashcode 는 항상 같 습 니 다.또한 같은 Controller 의 서로 다른 인 터 페 이 스 를 테스트 하 는 것 도 마찬가지 입 니 다.sleep 를 사용 하여 강제로 막 고 hashcode 도 마찬가지 입 니 다.그러나 서로 다른 contrller 를 방문 하면 hashcode 는 다 릅 니 다.구체 적 으로 어떻게 실현 하 는 지 저도 계속 깊이 파고 들 지 않 았 습 니 다.
그러나 결론 은 글 이 처음 말 한 것 처럼 나 왔 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
springmvc application/octet-stream problemmistake: Source code: Solution: Summarize: application/octet-stream is the original binary stream method. If the convers...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.