머리말
멀티 스레드에서의 작동 순서는 적절한 동기화없이 예측할 수 없기 때문에 멀티 스레딩의 스레드 안전 문제는 미묘하고 예상치 못한 일입니다. 동일한 공유 변수에 액세스하는 다중 스레드는 특히 여러 스레드가 스레드 안전을 보장하기 위해 공유 변수를 작성해야 할 때 특히 동시성 문제가 발생하기 쉽습니다.
일반적으로 사용자는 아래 그림과 같이 공유 변수에 액세스 할 때 적절한 동기화를 수행해야합니다.
동기화 측정 값은 일반적으로 잠금이며, 이는 사용자가 잠금에 대한 특정 이해를 요구하므로 사용자의 부담을 분명히 증가시킵니다. 변수를 만들 때 각 스레드가 액세스 할 때 자체 스레드의 변수에 액세스 할 수있는 방법이 있습니까? 사실, Threalocal은 이것을 할 수 있습니다. Threadlocal의 출현은 위의 문제를 해결하는 것으로 보이지 않습니다.
ThreadLocal은 JDK 패키지로 제공됩니다. 스레드-로컬 변수를 제공합니다. 즉, ThreadLocal 변수를 작성하면이 변수에 액세스하는 각 스레드에는 로컬 사본이 있습니다. 여러 스레드 가이 변수를 작동하면 실제로 자체 로컬 메모리에서 변수를 작동시켜 스레드 안전 문제를 피합니다. ThreadLocal 변수를 작성한 후
각 스레드는 아래 그림과 같이 변수를 로컬 메모리에 복사합니다.
자, 이제 ThreadLocal의 구현 원리와 ThreadLocal은 어떻게 내부적으로 가변 스레드 격리 방법으로 구현됩니까?
먼저, 다음 그림과 같이 Threadlocal의 클래스 다이어그램 구조를 살펴 봐야합니다.
좋다
위의 클래스 다이어그램에서 볼 수 있듯이 스레드 클래스에는 ThreadLocals 및 inheritableThreadlocals가 있습니다. 두 가지 유형의 변수 모두 ThreadLocalMap이고 ThreadLocalMap은 사용자 정의 된 해시 맵입니다. 기본적으로 각 스레드의 두 변수는 NULL입니다. 스레드가 ThreadLocal 세트를 호출하거나 처음으로 메소드를 얻을 때만 생성됩니다.
실제로, 각 스레드의 로컬 변수는 ThreadLocal 인스턴스에 저장되지 않지만 호출 스레드의 ThreadLocals 변수에 저장됩니다. 다시 말해, Type ThreadLocal의 로컬 변수는 특정 스레드 메모리 공간에 저장됩니다.
ThreadLocal은 실제로 쉘입니다. 설정 방법을 통해 값 값을 호출 스레드 스레드 스레드 Locals에 넣고 저장합니다. 호출 스레드가 get 메소드를 호출하면 현재 스레드의 ThreadLocals 변수에서 꺼집니다. 호출 스레드가 종료되지 않으면 로컬 변수는 호출 스레드의 ThreadLocals 변수에 저장됩니다.
따라서 로컬 변수를 사용할 필요가 없으면 ThreadLocal 변수의 제거 메소드를 호출하여 현재 스레드의 ThreadLocals 변수에서 로컬 변수를 삭제할 수 있습니다. 어떤 사람들은 ThreadLocals가 맵 구조로 설계된 이유를 물어볼 수 있습니까? 각 스레드는 다중 스레드 Local 변수와 연관 될 수 있음이 명백합니다.
다음으로 다음 코드에 표시된대로 ThreadLocal에 소스 코드를 입력 할 수 있습니다.
주로 세 가지 메소드의 구현 로직을 살펴보고, get 및 제거합니다.
먼저 세트 (t var1) 메소드를 살펴 보겠습니다
public void set (t var1) {// (1) 현재 스레드를 가져옵니다. var2 = thread.currentthread (); // (2) 현재 스레드는 해당 스레드 변수를 찾기 위해 키로 사용됩니다. 발견 된 경우, struchLocal.threadlocalMap var3 = this.getMap (var2)을 설정하십시오. if (var3! = null) {var3.set (this, var1); } else {// (3) 첫 번째 호출은 현재 스레드의 해당 해시 맵을 생성하기 위해 작성됩니다. }}위에서 언급 한 코드 (1)에서 먼저 호출 스레드를 가져온 다음 현재 스레드를 매개 변수로 사용하여 getMap (var2) 메소드를 호출하십시오. getMap (스레드 var2) 코드는 다음과 같습니다.
ThreadLocal.threadlocalMap getMap (스레드 var1) {return var1.threadlocals; }getMap (var2)이하는 일은 스레드의 자체 변수 threadLocals를 얻는 것이며 ThreadLocal 변수는 Thread의 멤버 변수에 바인딩된다는 것을 알 수 있습니다.
getMap (var2)이 비어 있지 않으면 값 값을 readlocals로 설정합니다. ThreadLocals는 해시 맵 구조이며, 여기서 키는 현재 ThreadLocal 인스턴스 객체의 참조이며 값은 설정 메소드를 통해 전달되는 값입니다.
getMap (var2)이 비어 있으면 설정 메소드가 처음이라고 불린 다음 현재 스레드의 ThreadLocals 변수가 생성됨을 의미합니다. Createmap (var2, var1)에서 무엇을하는지 보자?
void createmap (스레드 var1, t var2) {var1.threadlocals = new ThreadLocal.threadlocalMap (this, var2); }당신이 볼 수있는 것은 현재 스레드의 ThreadLocals 변수를 만드는 것입니다.
다음으로 get () 메소드를 살펴 보겠습니다. 코드는 다음과 같습니다.
public t get () {// (4) 현재 스레드 get thread var1 = thread.currentthread (); // (5) ThreadLocals variable threadlocal.threadlocalmap var2 = this.getMap (var1)을 가져옵니다. // (6) ThreadLocals가 NULL이 아닌 경우 해당 로컬 변수 값이 반환됩니다. if (var3! = null) {object var4 = var3.value; 반환 var4; }} // (7) ThreadLocals가 비어 있으면 현재 스레드의 ThreadLocals 멤버 변수가 초기화됩니다. reture this.setinitialValue (); }코드 (4) 먼저 현재 스레드 인스턴스를 가져옵니다. 현재 스레드의 ThreadLocals 변수가 NULL이 아닌 경우 현재 스레드의 로컬 변수를 직접 반환합니다. 그렇지 않으면 초기화를 위해 코드 (7)를 실행하고 setinitialValue () 코드는 다음과 같습니다.
private t setInitialValue () {// (8) null 객체 var1 = this.initialValue ()로 초기화되었습니다. 스레드 var2 = thread.currentthread (); ThreadLocal.threadLocalMap var3 = this.getMap (var2); // (9) 현재 스레드 변수의 ThreadLocals 변수가 비어 있지 않은 경우 (var3! = null) {var3.set (this, var1); // (10) 현재 스레드의 ThreadLocals 변수가 비어있는 경우} else {this.createmap (var2, var1); } return var1; }위에서 언급했듯이 현재 스레드의 ThreadLocals 변수가 비어 있지 않으면 현재 스레드의 로컬 변수 값이 NULL로 설정됩니다. 그렇지 않으면 Createmap은 현재 스레드의 Createmap 변수로 호출됩니다.
다음으로, 우리는 void remove () 메소드를 살펴 봅니다. 코드는 다음과 같습니다.
public void remove () {threadlocal.threadlocalmap var1 = this.getmap (thread.currentthread ()); if (var1! = null) {var1.remove (this); }}위에서 언급 한 바와 같이, 현재 스레드의 ThreadLocals 변수가 비어 있지 않으면 현재 스레드의 ThreadLocal 인스턴스에 지정된 로컬 변수가 삭제됩니다.
다음으로 특정 데모를 살펴 보겠습니다. 코드는 다음과 같습니다.
/*** 2018/6/3에 Cong에 의해 만들어졌습니다. */public class ThreadLocalTest {// (1) 인쇄 함수 정적 무효 인쇄 (문자열 str) {//1.1 현재 스레드 시스템의 로컬 메모리에서 로컬 변수의 값을 인쇄합니다. //1.2 현재 스레드의 로컬 메모리에서 LocalVariable 변수를 지우십시오. //localvariable.remove (); } // (2) STREBREDLOCAL VARIBLE STATIC THREADLOCAL <String> localVariable = New ThreadLocal <> (); public static void main (string [] args) {// (3) 스레드 생성 1 스레드 스레드 든 = 새로운 스레드 (new runnable () {public void run () {//3.1 스레드에서 로컬 변수 로컬 변수의 값을 설정 한 LocalVariable.set ( "스레드 1의 로컬 변수"); "Thread1 ---->"; System.out.println ( "스레드 1" + "의 로컬 변수를 제거한 후 결과 :" + localVariable.get ()); // (4) 스레드 생성 2 스레드 2 스레드 스레드 스레드 (New Runnable () {public void run () {//4.1 스레드 One LocalVariable.set ( "스레드 2"); //4.2 로컬 변수 로컬 변수의 값을 설정합니다. 2 " +": " + localVariable.get ());}}); // (5) 스레드 스레드를 시작합니다. threadtwo.start (); }}코드 (2)는 ThreadLocal 변수를 만듭니다.
코드 (3) 및 (4) 각각 스레드 1과 2를 만듭니다.
코드 (5)는 두 개의 스레드를 시작합니다.
스레드 1의 코드 3.1은 세트 메소드를 통해 LocalVariable의 값을 설정합니다. 이 설정은 실제로 스레드 1의 로컬 메모리의 사본입니다. 이 사본은 스레드 2에 의해 액세스 할 수 없습니다. 그러면 코드 3.2는 인쇄 함수를 호출하고 코드 1.1은 get 함수를 통해 현재 스레드 (스레드 1)의 로컬 변수 값을 얻습니다.
스레드 2는 스레드 1과 유사하게 실행됩니다.
작업 결과는 다음과 같습니다.
여기서 우리는 Threadlocal의 메모리 누출 문제에주의를 기울여야합니다.
각 스레드에는 내부에 ThreadLocals라는 멤버 변수가 있습니다. 변수 유형은 해시 맵입니다. 핵심은 우리가 정의한 ThreadLocal 변수에 대한이 참조이며, 값은 우리가 설정할 때의 값입니다. 각 스레드의 로컬 변수는 스레드 자체의 메모리 변수 ThreadLocals에 저장됩니다. 현재 스레드가 사라지지 않으면 이러한 로컬 변수는까지 저장됩니다.
따라서 메모리 누출이 발생할 수 있으므로 사용 후 Threadlocal의 제거 메소드를 호출하여 해당 스레드의 스레드 로컬에서 로컬 변수를 삭제해야합니다.
코드 1.2에서 주석을 풀고 다시 실행하면 실행 결과는 다음과 같습니다.
우리는 다음과 같은 질문에 대해 생각한 적이 있습니까? 우리는 Child 스레드의 상위 스레드에서 STREBRECAL 변수의 값을 얻습니까?
여기서는 부모 스레드에서 설정된 ThreadLocal 변수의 값을 자식 스레드에서 얻을 수 없음을 알 수 있습니다. 그렇다면 자식 스레드가 상위 스레드의 값에 액세스 할 수있는 방법이 있습니까? 상인 관계자는 미래에 나왔습니다. inheritableThreadlocal은 ThreadLocal에서 상속하고 어린이가 부모 스레드에서 설정된 로컬 변수에 액세스 할 수있는 기능을 제공합니다.
먼저 다음과 같이 읽을 수있는 honeritableThreadlocal 클래스의 소스 코드로 이동하겠습니다.
공개 클래스 inheritableThreadlocal <t>는 strooklocal <t> {public inheritableThreadlocal () {} // (1) 보호 된 t childValue (t var1) {return var1; } // (2) ThreadLocalMap getMap (Thread Var1) {return var1.inheritableThreadlocals; } // (3) void createmap (스레드 var1, t var2) {var1.inheritableThreadlocals = new ThreadLocalMap (this, var2); }}상인 관계가있는 것으로 보입니다. 위의 코드가 표시되었습니다. Code (3) 상인 관계가있는 것은 Createmap 메소드를 다시 작성한다는 것을 알 수 있으므로, 설정 방법이 처음으로 호출되면 현재 스레드의 inheritableThreadLocals 변수의 인스턴스가 스레드 로컬이 아니라 생성된다는 것을 알 수 있습니다.
코드 (2) 현재 스레드의 내부 맵 변수를 얻기 위해 get 메소드가 호출되면 threadLocals가 아닌 inheritableThreadlocals가 얻어진다는 것을 알 수 있습니다.
다시 작성된 코드 (1)가 실행되면 핵심 사항이 있으며, 자식 스레드가 상위 스레드의 로컬 변수에 액세스 할 수있는 방법을 구현하는 방법. 스레드에 의해 생성 된 코드, 스레드의 기본 생성자 및 Thread.java 클래스의 생성자는 다음과 같습니다.
/*** 2018/6/3에 Cong에 의해 만들어졌습니다. */ public Thread (runnable target) {init (null, target, "strule-" + nextthreadnum (), 0); } private void init (ThreadGroup G, Runnable Target, String Name, Long StackSize, AccessControlContext Acc) {// ... // (4) 현재 스레드 스레드 parent = currentthread (); // ... // (5) 부모 스레드의 상인방이 아닌 경우 (부모가 NULL이 아닌 경우 (parent.InheritableThreadLocals! = null) // (6) chired 스레드에서 inheritableThreadlocals 변수를 설정합니다. this.stacksize = stacksize; tid = nextthreadid (); }스레드를 생성 할 때는 생성자에서 init 메소드가 호출됩니다. 앞에서 언급했듯이, inheritableThreadlocal 클래스 GET 및 SET 메소드는 변수 InheritableThreadLocals를 작동하므로 여기에서 inheritableThreadLocal 변수는 null이 아니므로 코드 (6)가 실행됩니다. 다음과 같이 CreateInheritedMap 메소드의 소스 코드를 보자.
static roodlocalmap createInHeritedMap (ridureLocalMap parentmap) {return new ThreadLocalMap (parentmap); }CreateInHeritedMap은 부모 스레드의 inheritableThreadLocals 변수를 생성자로 사용하여 새 ThreadLocalMap 변수를 생성 한 다음 하위 스레드의 inheritableThreadLocals 변수에 할당한다는 것을 알 수 있습니다. 그런 다음 ThreadLocalMap의 생성자를 입력하십시오. 소스 코드는 다음과 같습니다.
개인 ThreadLocalMap (strooklocalmap parentmap) {entry [] parenttable = parentmap.table; int len = parenttable.length; setThreshold (Len); 테이블 = 새 항목 [렌]; for (int j = 0; if (e! = null) {@suppresswarnings ( "선택 취소") ThreadLocal <botor> key = (ThreadLocal <botor>) e.get (); if (key! = null) {// (7) 재정의 메소드 객체 값 value = key.childValue (e.value); // return e.value entry c = 새 입력 (key, value); int h = key.threadlocalhashcode & (len -1); while (표 [h]! = null) h = NextIndex (h, len); 표 [H] = C; 크기 ++; }}}}}}위의 코드는 상위 스레드의 inheritableThreadlocals 멤버 변수의 값을 새로운 ThreadLocalMap 객체에 복사하는 것입니다. 코드 (7) inheritableThreadlocal 클래스에 의해 다시 작성된 코드 (1) 코드도 보입니다.
일반적으로 : inheritableThreadlocal 클래스는 코드 (2) 및 (3)을 다시 작성하고 로컬 변수를 특정 스레드의 inheritableThreadlocals 변수에 저장합니다. 스레드가 세트를 통해 변수를 설정하거나 inheritableThreadlocals 인스턴스의 GET 메소드를 설정하면 현재 스레드의 inheritableThreadLocals 변수가 생성됩니다. 상위 스레드가 자식 스레드를 생성 할 때
생성자는 상위 스레드의 inheritableThreadlocals 변수의 로컬 변수를 복사하여 하위 스레드의 inheritableThreadlocals 변수로 복사합니다.
원칙이 잘 이해 된 후에는 다음과 같이 위에서 알고있는 내용을 확인하기 위해 예를 들어 봅시다.
COM.HJC;/*** PACKED CONG가 2018/6/3에 작성했습니다. */public class inheritableThreadLocalTest {// (1) 스레드 생성 공개 static strook <streldlocal = new ThreadLocal <string> (); public static void main (string [] args) {// (2) set stured variable streadlocal.set ( "hello java"); // (3) START Child Thread Thread 스레드 = 새 스레드 (new Runnable () {public void run () {// (4) 자식 스레드의 값은 스레드 변수 system.out.println을 출력합니다 ( "subthread :" + stroodlocal.get ());}); thread.start (); // (5) 기본 스레드는 스레드 변수 값 system.out.println을 출력합니다 ( "부모 스레드 :" + threadLocal.get ()); }}작업 결과는 다음과 같습니다.
즉, 동일한 ThreadLocal 변수가 상위 스레드에서 설정된 후에는 자식 스레드에서 얻을 수 없습니다. 이전 섹션의 소개에 따르면, 현재 스레드는 자식 스레드가 GET 메소드를 호출 할 때 현재 스레드가 하위 스레드이기 때문에 정상적인 현상이어야하며, 스레드 변수를 설정하도록 설정 메소드가 호출되기 때문입니다. 둘은 다른 스레드이며, 자연스럽게 액세스 할 때 자식 스레드가 Null을 반환합니다.
그렇다면 자식 스레드가 상위 스레드의 값에 액세스 할 수있는 방법이 있습니까? 대답은 예이므로 위의 원리에 의해 분석 된 HeritableThreadlocal을 사용하십시오.
위의 예제의 코드 (1)를 다음과 같이 수정하십시오.
// (1) 스레드 생성 변수 public static strandlocal <string> threadlocal = new heritableThreadlocal <string> ();
작업 결과는 다음과 같습니다.
스레드 변수 값은 이제 자식 스레드에서 정상적으로 얻을 수 있음을 알 수 있습니다. 그래서 어떤 상황에서 아이들은 부모 스레드에서 스레드 로컬 변수를 얻어야합니까?
사용자 로그인 정보를 저장하는 ThreadLocal 변수와 같은 많은 상황이 있습니다. 하위 스레드는 사용자 로그인 정보를 사용해야 할 가능성이 높습니다. 예를 들어, 일부 미들웨어는 통합 추적 ID를 사용하여 전체 호출 링크를 기록해야합니다.
스프링 요청 범위 스코프 Bean에서 ThreadLocal 사용
스프링에 XML에서 Bean을 구성 할 때 싱글 톤, 프로토 타입, 요청, 세션 등으로 Bean의 범위를 구성하기 위해 스코프 속성을 지정할 수 있음을 알고 있습니다. Bean의 범위의 구현 원리는 ThreadLocal을 사용하여 구현됩니다. 스프링 컨테이너의 콩이 웹의 범위를 갖기를 원한다면
Bean 레벨을 구성하는 데 필요한 해당 스코프 속성 외에도 다음과 같이 web.xml에서 구성해야합니다.
<Leater> <Leater-Class> org.springframework.web.context.request.requestContextListener </Leater-Class> </liareer>
여기서 우리는 주로 요청 contextListener의 두 가지 방법을 살펴 봅니다.
공개 void requestInitialized (servletrequestevent requestevent)
그리고
public void requestDestroyed (servletrequestevent requestevent)
웹 요청이 오면 requestInitialized 메소드가 실행됩니다.
public void requestInitialized (servletrequestevent requestEvent) {..... avit httpservletRequest request = (httpservletRequest) requestEvent.getServletRequest (); servletrequestattributes 속성 = 새로운 servletrequestattributes (요청); request.setattribute (request_attributes_attribute, attributes); LocalEcontexTholder.setLocale (request.getLocale ()); // 속성을 threadLocal 변수로 설정합니다. } public static void setRequestAttributes (requestAttributes 속성) {setRequestAttributes (속성, false); } public static void setRequestAttributes (requestAttributes 속성, 부울 상속 가능) {if (attributes == null) {resetRequestAttributes (); } else {// default hentable = false if (inheritable) {inheritableRequestAttributeSholder.set (attributes); requestAttributeSholder.remove (); } else {requestAttributeSholder.set (attributes); inheritableRequestAttributeSholder.remove (); }}}위의 소스 코드를 볼 수 있습니다. 기본 상속 가능성은 False이므로 속성 값은 requestAttributeShoder에 배치되며 그 정의는 다음과 같습니다.
Private STATIC FINNS THREADLOCAL <RequiverTributes> requestAttributeSholder = 새 namedThreadLocal <RequibleTtributes> ( "요청 속성"); Private STATIC FINNS THREADLOCAL <RequiverTibutes> inheritableRequestAttributeSholder = 새로운 지정된 heritableThreadLocal <requestAttributes> ( "request context");
그중에서도 The RestreadLocal <t>는 ThreadLocal <t>를 확장하므로 상속되지 않습니다.
그중에서도 The RestreadLocal <t>는 ThreadLocal <t>를 확장하므로 상속되지 않습니다.
NameInHeritableThreadlocal <t>는 상인 관계가 있으므로 상속이 있으므로 기본적으로 requestContexTholder에 배치 된 속성 값은 하위 스레드에서 얻을 수 없습니다.
요청이 종료되면 requestDestroyed 메소드가 호출되고 소스 코드는 다음과 같습니다.
public void requestDestroyed (servletRequestevent requestEvent) {servletRequestAttributes attributes = (servletRequestAttributes) requestEvent.getServleTrequest (). getAttribute (request_attributes_attribute); ServletRequestAttributes ResdleAttributes = (servletRequestAttributes) requestContexTholder.getRequestAttributes (); if (readattributes! = null) {// 우리는 초기 요청 스레드에서 현재 스레드의 스레드를 지울 가능성이 매우 높습니다. if (attributes == null) {attributes = rdudeTatributes; } // 요청이 종료되면 현재 스레드의 스레드 변수를 지우십시오. localecontextholder.resetlocalecontext (); requestContexTholder.ResetRequestAttributes (); } if (attributes! = null) {attributes.RequestCompleTed (); }}다음으로 타이밍 차트에서 호출하는 웹 요청의 논리를 살펴 보겠습니다.
즉, Tomcat에서 컨텍스트 (특정 응용 프로그램)를 처리하기 전에 웹 요청이 시작될 때마다 요청 ContexTholder 속성이 호스트 일치 후에 설정되므로 requestAttributeSholder가 비어 있지 않아 요청의 끝에서 지워집니다.
따라서 기본적으로 RequestContexTholder에 배치 된 속성 하위 스레드에 액세스 할 수 없으며 스프링 요청 범위의 Bean은 ThreadLocal을 사용하여 구현됩니다.
다음으로 예제 시뮬레이션 요청이 수행되며 코드는 다음과 같습니다.
Web.xml 구성은 다음과 같습니다.
요청 범위이기 때문에 웹 프로젝트이어야하며 requestContextListener는 web.xml로 구성되어야합니다.
<Leater> <Leater-Class> org.springframework.web.context.request.requestContextListener </Leater-Class> </liareer>
그런 다음 요청 스코프 Bean을 IOC 컨테이너에 주입하십시오. 코드는 다음과 같습니다.
<bean id = "requestbean"scope = "request"> <속성 이름 = "name"value = "hjc" /> <aop : scoped-proxy /> < /bean>
테스트 코드는 다음과 같습니다.
@webresource ( "/testservice") public class testrpc {@autowired private requestbean requestInfo; @ResourceMapping ( "Test") public actionResult Test (ErrorContext Context) {ActionResult result = new ActionResult (); pvginfo.setName ( "hjc"); 문자열 이름 = requestInfo.getName (); result.setValue (이름); 반환 결과; }}위에서 언급했듯이 먼저 requestContextListener를 web.xml로 구성한 다음 요청 범위를 사용하여 요청 비인 인스턴스를 IOC 컨테이너에 주입하십시오. 마지막으로, requestbean 인스턴스가 testrpc에 주입됩니다. 메소드 테스트는 먼저 requestInfo method setName을 호출하여 이름 속성을 설정 한 다음 이름 속성을 가져 와서 반환합니다.
여기서, requestInfo 객체가 싱글 톤 인 경우, 여러 스레드가 테스트 메소드를 동시에 호출 한 후 각 스레드는 세트 게이트 작업입니다. 이 작업은 원자가 아니며 실 안전 문제를 일으 킵니다. 여기에 선언 된 범위는 요청 레벨이며 각 스레드에는 requestInfo가있는 로컬 변수가 있습니다.
위의 예제 메소드 요청의 타이밍 차트는 다음과 같습니다.
우리는 테스트를 호출 할 때 발생하는 일에 중점을 두어야합니다.
실제로, 이전에 생성 된 요청은 CGLIB에 의해 프록시 된 후 (관심이 있으시면 ScopedProxyFactoryBean 및 기타 유형을 연구 할 수 있음) SetName 또는 GetName을 호출하면 DynamicAdVistorceptor에 의해 가로 채립니다. 인터셉터는 결국 GET requestScope 메소드를 호출하여 현재 스레드에서 로컬 변수를 유지합니다.
열쇠가 여기 있습니다. 다음과 같이 requestScope get 메소드의 소스 코드를 살펴 봐야합니다.
공개 객체 get (문자열 이름, ObjectFactory ObjectFactory) {requestAttributes 속성 = requestContexTholder.currentRequestAttributes (); // (1) Object ScopedObject = attributes.getAttribute (이름, getScope ()); if (scopedObject == null) {scopedObject = ObjectFactory.getObject (); // (2) attributes.setAttribute (이름, scopedObject, getScope ()); // (3)} return scopedObject; }요청이 시작되면 requestContextListener.setRequestAttributess에서 requestContextListener.RequestInitialized를 호출하여 요청이 시작됩니다.
그런 다음 요청이 TestRPC의 테스트 메소드로 라우팅 된 후 테스트 메소드에서 SetName 메소드가 처음 호출되면 requestScope.get () 메소드가 호출됩니다. get 메소드 (1)의 코드는 requestContextListener.requestInitialized를 통해 설정된 스레드-로컬 변수 requestTributeSholder에 의해 저장된 속성 세트의 값을 가져옵니다.
그런 다음 속성 세트에 requestInfo라는 속성이 있는지 확인하십시오. 첫 번째 호출이므로 존재하지 않으므로 코드가 실행되고 (2) Spring이 requestInfo 객체를 생성 한 다음 속성 세트 속성으로 설정하면 현재 요청 스레드의 로컬 메모리에 저장됩니다. 그런 다음 생성 된 객체를 반환하고 생성 된 객체의 세트 이름을 호출하십시오.
마지막으로, getName 메소드는 테스트 메소드에서 호출되며 requestScope.get () 메소드가 호출됩니다. get 메소드 (1)의 코드는 requestContextListener.requestInitialized를 통해 설정된 스레드 로컬 변수 requesttributes를 가져온 다음 속성 세트에 requestInfo라는 속성이 있는지 확인합니다.
BEAN이 처음으로 setName을 요구할 때 requestInfo라는 Bean이 ThreadLocal 변수로 설정되었고 SetName 및 getName을 위해 동일한 스레드가 호출되므로 SetName을 호출 할 때 생성 된 requestInfo 객체가 여기에서 직접 반환 된 다음 getName 메소드가 호출됩니다.
지금까지, 우리는 ThreadLocal의 구현 원칙을 이해하고 ThreadLocal이 상속을지지하지 않는다고 지적했습니다. 그런 다음 우리는 상인 관계가 어떻게 threadLocal이 상속을지지하지 않는 기능을 어떻게 보상하는지 즉시 설명했습니다. 마지막으로, 우리는 Spring Framework에서 ThreadLocal을 사용하여 Reqeust 범위의 Bean을 구현하는 방법을 간단히 소개했습니다.
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.