이전 기사에서는 프록시 클래스 내에서 프록시 클래스가 어떻게 생성되는지 분석했습니다. 캐시 메커니즘이 프록시 내부에서 사용되는 것을 보았습니다. 제공된 클래스 로더 및 인터페이스 어레이를 기반으로 프록시 클래스를 캐시에서 찾을 수있는 경우 프록시 클래스는 직접 반환됩니다. 그렇지 않으면 프록시 클래스를 생성하기 위해 proxyclassfactory 공장이 호출됩니다. 여기에 사용 된 캐시는 보조 캐시이며 첫 번째 레벨 캐시 키는 클래스 로더를 기반으로 생성되며, 두 번째 레벨 캐시 키는 인터페이스 어레이를 기반으로 생성됩니다. 특정 내부 메커니즘을 자세히 설명하기 위해 코드를 직접 게시합니다.
// 참조 참조 대기열 개인 최종 참조 Queue <k> refqueue = new ReferenceQueue <> (); // 캐시의 기본 구현, 키는 첫 번째 수준 캐시이고 값은 두 번째 수준 캐시입니다. NULL을 지원하기 위해 핵심 유형의 맵은 ObjectPrivate 최종 ConcurrentMap <Object, ConcurrentMap <개체, 공급 업체 <v >>> map = new ConcurrenTashMap <> (); // 모든 프록시 클래스 생성기를 사용할 수 있는지 여부를 Reversemap 레코드하도록 설정됩니다. 이것은 캐시 만료 메커니즘 프라이버시 최종 동맥 동의어 <v>, boolean> reversemap = new conscurrenthashmap <> (); // 2 차 캐시 키를 생성하는 공장, 키 플로 토리의 최종 이성 <k, p, p, subkeyfactory; // 이차적 인 values를 생성하는 공장은 여기서 cache를 생성하는 공장을 구현하기위한 것입니다. Bifunction <k, p, v> valueFactory; // 생성자, 2 차 캐시 키와 보조 캐시 값을 생성하는 공장을 생성하는 공장 (bifunction <k, p,?> subkeyfactory, bifunction <k, p, valuefactory) {this.subkeyfactory = requicir = requactory (subkeyfactory); this.ValueFactory = Objects.Requirenonnull (ValueFactory);}먼저, 멤버 변수와 약점의 생성자를 살펴 보겠습니다. 약한 캐시 캐시의 내부 구현은 ConcurrentMap을 통해 완료됩니다. 멤버 변수 맵은 보조 캐시의 기본 구현입니다. 리버시 맵은 캐시 만료 메커니즘을 구현하는 것입니다. SubKeyFactory는 2 차 캐시 키의 생성 공장입니다. 생성자를 통해 전달됩니다. 여기에 전달 된 값은 프록시 클래스의 핵심 요소이며 ValueFactory는 보조 캐시 값의 생성 공장입니다. 생성자를 통해 전달됩니다. 프록시 클래스 ProxyClassFactory가 여기에 전달됩니다. 다음으로, 약한 케이스의 Get 메소드를 살펴 보겠습니다.
public v get (k key, p parameter) {// 여기에서 구현하는 데 필요한 인터페이스는 비어있을 수 없습니다. requirenonnull (매개 변수); // CLEAR 만료 된 캐시 EXPUNGESTALEENTRIES (); // 첫 번째 레벨 캐시 객체 CacheKey = CacheKey.Valueof (key, refqueue)의 키로 Cachekey로 클래스 로더를 랩합니다. // 보조 캐시를 가져옵니다 동의식 <개체, 공급 업체 <V >> valueMap = map.get (CacheKey); // (valuesMap == null) if (valuesMap == null)을 기반으로 해당 값이 얻지 못하는 경우 {// CAS에 넣으십시오. 존재하지 않는 경우, 원래 값 ConcurrentMap <Object, Supplier <V>> OldValuesMap = map.putifabsent (valueMap = new ConcurnErthAshMap <())를 반환합니다. // OldValuesMap이 값이 있으면 (oldValuesMap! = null) if If가 실패했음을 의미합니다. {valueMap = OldValuesMap; }} // 프록시 클래스에서 구현 한 인터페이스 어레이를 기반으로 제 2 레벨 캐시 키를 만듭니다. key0, key1, key2, keyx 객체 subkey = objects.requirenonnull (subkeyfactory.apply (key, parameter))로 나뉩니다. // 보조 캐시의 값은 서브 키를 통해 얻습니다. 공급 업체 <v> 공급 업체 = valueMap.get (subkey); 공장 공장 = null; //이 루프는 폴링 메커니즘을 제공합니다. 조건이 거짓 인 경우 (true) {// 하위 키를 통해 검색된 값이 비어 있지 않으면 (공급자! = null) {// 여기 공급이 공급품이거나 Cachevalue // 여기에 판결이 이루어지지 않지만 공급 업체 구현 vals value = supplier.get (); get (); if (value! = null) {return value; }} if (factory == null) {// 서브 키 공장의 해당 값으로 새 공장 인스턴스를 만듭니다. } if (supplier == null) {// 여기서 SubKey는 해당 값이 없음을 의미합니다. 공급 업체의 SubKey 값으로 공장을 넣습니다. if (supplier == null) {// 여기서 공장이 캐시 공급 업체 = 공장에 성공적으로 배치되었음을 의미합니다. } // 그렇지 않으면, 다른 스레드는 그 기간 동안 값을 수정할 수 있다면, 우리는 더 이상 값을 서브 키에 계속 지정하지 않고, 그것을 꺼내서 직접 사용하고 {//이 기간 동안 다른 스레드는 값을 수정했을 수 있으므로 (valuesMap.replace, 공급 업체, 공장) {// 팩토리를 새로운 값 공급 업체로 대체 할 수 있습니다. } else {// 교체 실패, 원래 값 공급 업체 = valueMap.get (subkey)를 계속 사용합니다. }}}}LeainCache의 GET 메소드는 잠금 장치와 동기화되지 않으므로 스레드 안전을 어떻게 달성합니까? 수정 된 모든 멤버 변수는 ConcurrentMap을 사용하기 때문에이 클래스는 스레드 안전입니다. 따라서 자체 스레드 안전성을 동의 한 MAP로 위임하고 Get 메소드는 가능한 한 많은 동기화 코드 블록을 줄여 약한 캐시의 성능을 효과적으로 향상시킬 수 있습니다. 클래스 로더는 레벨 1 캐시의 키라는 것을 알 수 있으므로 클래스 로더에 의해로드 된 클래스가 다르기 때문에 클래스 로더에 따라 먼저 필터링 할 수 있습니다. 그런 다음 인터페이스 어레이를 사용하여 보조 캐시의 키를 생성합니다. 여기에는 몇 가지 최적화가 있습니다. 대부분의 클래스는 하나 또는 두 개의 인터페이스를 구현하기 때문에 보조 캐시 키는 key0, key1, key2 및 keyx로 나뉩니다. key0 to key2는 0 ~ 2 개의 인터페이스가 구현되었음을 의미하고 Keyx는 3 개 이상의 인터페이스가 구현되었음을 의미합니다. 실제로, 그들 대부분은 Key1과 Key2 만 사용합니다. 이 키의 생성 공장은 프록시 클래스에 있으며 주요 공장은 약한 캐시 생성자를 통해 전달됩니다. 여기서 두 번째 레벨 캐시의 값은 공장 인스턴스이며 프록시 클래스의 최종 값은 공장 공장을 통해 얻습니다.
Private Final Class Factory는 공급 업체 <v> {// 레벨 1 캐시 키, 클래스 로더에 따라 개인 최종 K 키를 생성합니다. // 프록시 클래스에서 구현 한 인터페이스 배열 비공개 최종 P 매개 변수; // 레벨 2 캐시 키, 인터페이스 어레이에 따라 개인 최종 객체 서브 키를 생성합니다. // 레벨 2 캐시 비공개 최종 동력 동력 <개체, 공급 업체 <v >> valueMap; 공장 (k 키, P 매개 변수, 객체 하위 키, ConcurrentMap <개체, 공급 업체 <V >> valueMap) {this.key = 키; this.parameter = 매개 변수; this.subkey = subkey; this.ValuesMap = valueMap; } @override public synchronized v get () {// 여기서는 공급 업체가 공급 업체 자체인지 확인하기 위해 공급 업체가 공급 업체 <v> 공급 업체 = valueMap.get (subkey)인지 확인합니다. if (공급자! = this) {// 여기서 공급 업체가 공장 인스턴스 자체인지 여부를 확인하고, 그렇지 않은 경우 널 리턴 및 발신자가 계속 여론 조사를하도록 허용하고 // 기간 동안 공급 업체는 Cachevalue로 교체되거나 대리 클래스를 초래하지 않아 2 차 캐시에서 제거 될 수 있습니다. } v value = null; {// 프록시 클래스를 생성하려면 valueFactory를 위임하십시오. 여기서 프록시 클래스 값은 들어오는 proxyclassfactory = 객체를 통해 생성됩니다 (valueFactory.apply (key, parameter)). } 마침내 {// 프록시 클래스 생성이 실패하면이 보조 캐시를 삭제하면 (value == null) {valueMap.remove (subkey, this); }} // 값의 값만이 비어 있지 않아 여기에 값에 도달 할 수 있습니다! = null; // 프록시 클래스 Cachevalue <v> cachevalue = new Cachevalue <> (value); // 포장 된 캐시 평가를 보조 캐시에 넣습니다. 이 작업은 성공적이어야합니다. 그렇지 않으면 (ValuesMap.replace (subkey, this, cachevalue)) {// cachevalue를 2 차 캐시에 성공적으로 넣은 후 reversemap.put (cachevalue, boolean.true); } else {새 assertionError를 던지십시오 ( "여기에 도달해서는 안됩니다"); } // 마지막으로 약한 참조로 랩핑되지 않은 프록시 클래스 리턴 값을 반환합니다. }}내부 공장 클래스 공장을 다시 살펴 보겠습니다. Get 메소드가 동기화 된 키워드를 사용하여 동기화되어 있음을 알 수 있습니다. Get 메소드를 수행 한 후 먼저 Subkey에 해당하는 공급 업체가 공장 자체인지 확인하십시오. 그렇지 않으면 NULL을 반환하고 약한 캐시 GET 메소드가 다시 다시 시도됩니다. 그것이 실제로 공장 자체 인 경우, proxyclassfactory는 약한 캐시를 구성 할 때 전달되는 프록시 클래스를 생성하도록 위임됩니다. 따라서 여기에서 프록시의 대중성 내부 공장이 결국 프록시 클래스를 생성하도록 호출되는 이유를 설명합니다. 프록시 클래스를 생성 한 후 약한 참조를 사용하여 래핑하여 리버시 맵에 넣고 마지막으로 원래 프록시 클래스를 반환합니다.
지금까지, 우리는 첫 번째 수준 캐시 및 제 2 레벨 캐시 구현 원리를 포함한 약한 캐시 캐시의 구현과 두 번째 레벨 캐시 키를 생성하는 원칙과 proxyClassFactory 호출을 통해 결국 프록시 클래스를 생성하는 방법에 대해 자세히 밝혀졌습니다. 다음 기사에서는 Proxygenerator 클래스로 이동하여 특정 프록시 클래스의 바이트 코드 생성 프로세스를보기를합니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.