Im vorherigen Artikel haben wir analysiert, wie die Proxy -Klasse in der Proxy -Klasse generiert wird. Wir haben gesehen, dass der Cache -Mechanismus im Proxy verwendet wird. Wenn die Proxy -Klasse im Cache basierend auf dem bereitgestellten Klassenlader und Schnittstellenarray gefunden werden kann, wird die Proxy -Klasse direkt zurückgegeben. Andernfalls wird die ProxyClassFactory -Fabrik aufgerufen, um die Proxy -Klasse zu generieren. Der hier verwendete Cache ist ein sekundärer Cache, und seine Cache-Taste der ersten Stufe wird basierend auf dem Klassenloader generiert, und die Cache-Taste der zweiten Ebene wird basierend auf dem Schnittstellenarray generiert. Wir werden den Code direkt veröffentlichen, um den spezifischen internen Mechanismus im Detail zu erläutern.
// Referenzwarteschlange private endgültige Referenzqueue <k> refQueue = new Referencequeue <> (); // Die zugrunde liegende Implementierung von Cache ist der Schlüssel erster Cache und der Wert zweiter Ebene. Um NULL zu unterstützen, wird der Schlüsseltyp von MAP auf die endgültige ConcurrentMap <Objekt, ConcurrentMap <Objekt, Lieferant <v >>> map = new ConcurrentHasMap <> (); // ReverseMap -Aufzeichnungen festgelegt, ob alle Proxy -Klassengeneratoren verfügbar sind. This is to implement the cache expiration mechanism private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>();//The factory that generates the secondary cache key, the KeyFactoryprivate final BiFunction<K, P, ?> subKeyFactory;//The factory that generates the secondary cache value, here is the ProxyClassFactoryprivate final Bifunction <k, p, v> ValueFactory; // Konstruktor, die Fabrik, die den sekundären Cache -Schlüssel und die Fabrik erzeugt, die den sekundären Cache -Wert öffentlicher WeaPcache (bifunction <k, p,?> Subkeyfactory, bifunction <k, p, v> valueFactory) {this.subyfactory = Objectory = Objectory = Objectory = Objectory. this.ValueFactory = Objects.requirenonnull (valueFactory);}Schauen wir uns zunächst die Mitgliedsvariablen und den Konstruktor von WeaPcache an. Die interne Implementierung von WeaChache -Cache wird durch ConcurrentMap abgeschlossen. Die von der Mitgliedsvariablen -Karte ist die zugrunde liegende Implementierung des sekundären Cache. Die Reversemap besteht darin, den Cache -Ablaufmechanismus zu implementieren. Der SubKeyFactory ist die Erzeugungsfabrik des sekundären Cache -Schlüssels. Es wird durch den Konstruktor übergeben. Der hier übergebene Wert ist der Schlüsselfaktor der Proxy -Klasse, und der Wertfaktor ist die Erzeugungsfabrik des sekundären Cache -Werts. Es wird durch den Konstruktor übergeben. Die Proxyklasse -ProxyClassFactory wird hier übergeben. Schauen wir uns als nächstes die GET -Methode von WeaPcache an.
public v get (k key, p parameter) {// Die hier implementierte Schnittstelle kann nicht leere Objekte sein. Requirenonnull (Parameter); // abgelaufene cache exclimingestaleEntries () löschen; // Classloader in Cachekey als Schlüssel für den ersten Cache-Objekt Cachekey = cachekey.ValueOf (Schlüssel, RefQueue) einwickeln; // Erhalten Sie den sekundären Cache ConcurrentMap <Objekt, Lieferant <v >> valuesmap = map.get (cachekey); // Wenn der entsprechende Wert nicht basierend auf Classloader erhalten wird, wenn (valuesmap == null) {// ihn in CAS einfügen, wenn er nicht existiert, geben Sie ihn an, ansonsten geben Sie den ursprünglichen Wert ConcurrentMap <Objekt, Lieferant <v >> oldValuesmap = map.putiFabSent (cachekey, valuesmap = New ConcurentHashmap <> (). // Wenn OldValuesMap einen Wert hat, bedeutet dies, dass die Platzierung fehlgeschlagen ist, wenn (oldValuesMap! = Null) {valuesMap = oldValuesMap; }} // Erstellen Sie den Cache-Schlüssel der zweiten Ebene basierend auf dem von der Proxy-Klasse implementierten Schnittstellen-Array, das in Key0, Key1, Key2, Keyx-Objekt subKey = Objects.requirenonnull (subKeyFactory.Apply (Schlüssel, Parameter)) unterteilt ist. // Der Wert des sekundären Cache wird durch Unterschlüssel erhalten. Lieferant <V> Lieferant = valuesmap.get (subKey); Werksfabrik = NULL; // Diese Schleife bietet einen Wahlmechanismus. Wenn die Bedingung falsch ist, versuchen Sie es weiter, bis die Bedingung wahr ist, während (true) {// Wenn der durch SubKey abgerufene Wert nicht leer ist, wenn (Lieferant! if (value! = null) {Rückgabewert; }} if (factory == null) {// Erstellen Sie eine neue Fabrikinstanz als entsprechender Wert von SubKey Factory = New Factory (Schlüssel, Parameter, SubKey, ValuesMap); } if (Lieferant == null) {// hier bedeutet es, dass der SubKey keinen entsprechenden Wert hat. Setzen Sie die Fabrik als Wert des SubKEY in Supplierer = valuesMap.putIFAbSent (SubKey, Fabrik); if (Lieferant == NULL) {// hier bedeutet es, dass die Fabrik erfolgreich in den Cache -Lieferanten = fabrisch platziert wird; } // Ansonsten können andere Threads den Wert während des Zeitraums ändern, dann zuweisen wir nicht mehr Werte dem Subschlüssel, sondern nehmen sie direkt heraus und verwenden sie direkt} else {// Während dieses Zeitraums können andere Threads den Wert geändert haben, ersetzen also den Originalwert, wenn (valuesmap.replace (Subty, Supplier, Factory). } else {// fehlgeschlagen ersetzen, verwenden Sie weiterhin den ursprünglichen Wert -Lieferanten = valuesmap.get (subKey); }}}}Die GET -Methode von WreadCache synchronisiert nicht mit Schlössern. Wie erreicht sie also die Gewindesicherheit? Da alle seine modifizierten Mitgliedsvariablen eine ConcurrentMap verwenden, ist diese Klasse Thread-Safe. Daher delegiert es seine eigene Thread -Sicherheit in ConcurrentMap, und die GET -Methode reduziert die Synchronisationscodeblöcke so weit wie möglich, was die Leistung von Schwacher effektiv verbessern kann. Wir sehen, dass Classloader ein Schlüssel des Cache Level 1 ist, damit wir ihn zuerst nach dem Classloader filtern können, da die von verschiedenen Klassenloader geladenen Klassen unterschiedlich sind. Anschließend wird ein Schnittstellenarray verwendet, um die Taste des sekundären Cache zu generieren. Hier hat es einige Optimierungen. Da die meisten Klassen ein oder zwei Schnittstellen implementieren, ist die sekundäre Cache -Taste in Key0, Key1, Key2 und Keyx unterteilt. Key0 to Key2 bedeutet, dass 0 bis 2 Schnittstellen implementiert werden und Keyx bedeutet, dass 3 oder mehr Schnittstellen implementiert werden. Tatsächlich verwenden die meisten von ihnen nur Key1 und Key2. Die Erzeugungsfabrik dieser Schlüssel befindet sich in der Proxy -Klasse, und die Schlüsselfabrik wird durch den WeaCache -Konstruktor übergeben. Der Wert des Cache der zweiten Ebene ist hier eine Fabrikinstanz, und der Endwert der Proxy-Klasse wird durch die Fabrikfabrik erhalten.
Private Final Class Factory implementiert Lieferanten <V> {// Cache -Taste Level 1, generieren Sie den privaten endgültigen K -Schlüssel nach Classloader; // Schnittstellenarray Private Final P -Parameter implementiert von der Proxy -Klasse; // Level 2 -Cache -Taste, generieren Sie einen privaten endgültigen Objekt -Unterschlüssel gemäß dem Schnittstellenarray. // Stufe 2 Cache Private Final ConcurrentMap <Objekt, Lieferant <v >> valuesMap; Werksfabrik (K -Schlüssel, P -Parameter, Objektsubrieb, ConcurrentMap <Objekt, Lieferant <v >> valuesmap) {this.key = key; this.Parameter = Parameter; this.subkey = subkey; this.valuesmap = valuesMap; } @Override public synchronized v get () {// Hier gehe ich wieder zum sekundären Cache, um den Lieferanten zu überprüfen, ob es sich um die Fabrik selbst lieferant <v> Lieferant = valuesmap.get (SubKey); if (Lieferant! } V value = null; Versuchen Sie es mit {// den ValueFactory delegieren, um die Proxy -Klasse zu generieren. Hier wird der Proxy -Klassenwert über die eingehende ProxyclassFactory = Objects.requirenonnull (ValueFactory.Apply (Schlüssel, Parameter)) generiert. } endlich {// Wenn die Proxy -Klasse -Generierung fehlschlägt, löschen Sie diesen sekundären Cache if (value == null) {valuesmap.remove (subKey, this); }} // Nur der Wert des Wertes ist nicht leer. Kann er hier den Wert erreichen! = Null; // Die Proxy -Klasse Cachevalue <V> cachevalue = new Cachevalue <> (Wert); // Legen Sie den verpackten Cachevalue in den sekundären Cache. Diese Operation muss erfolgreich sein, andernfalls wird ein Fehler gemeldet, wenn (VALUTSMAP.REPLACE (SUBKEY, THE, CACHEVALUE)) {// Nach erfolgreichem Cachevalue in den sekundären Cache, Mark It Reveremap.put (Cachevalue, boolean.Tree), erfolgreich eingesetzt wird. } else {werfen neuer Assertionerror ("sollte hier nicht erreichen"); } // schließlich den Rückgabewert der Proxy -Klasse zurückgeben, der nicht mit schwacher Referenz verpackt ist. }}Schauen wir uns die interne Fabrikklassenfabrik erneut an und wir können sehen, dass die GET -Methode mit dem synchronisierten Schlüsselwort synchronisiert wird. Überprüfen Sie nach der Durchführung der GET -Methode zunächst, ob der Lieferant, der dem Subty entspricht, die Fabrik selbst ist. Wenn nicht, wird es null zurückgegeben, und die WeaCache -Methode wird es weiterhin erneut versuchen. Wenn es sich tatsächlich um die Fabrik selbst handelt, wird ProxyClassFactory delegiert, um die Proxy -Klasse zu generieren, die beim Konstruktion von WeaKcache übergeben wird. Hier erklärt also, warum die ProxyclassFactory Internal Factory in Proxy aufgerufen wird, um die Proxy -Klasse am Ende zu generieren. Nachdem die Proxy -Klasse generiert wurde, verwendet sie eine schwache Referenz, um sie zu wickeln und in ReverseMap zu setzen, und gibt schließlich die ursprüngliche Proxy -Klasse zurück.
Bisher haben wir ausführlich die Implementierung von WeapaCache-Cache einschließlich der Cache der ersten Ebene und der Cache-Implementierungsprinzipien der zweiten Ebene sowie des Prinzips der Generierung der Cache-Taste der zweiten Ebene und der Aufforderung an ProxyclassFactory enthüllt, um die Proxy-Klasse am Ende zu generieren. Im nächsten Artikel werden wir in die Proxygenerator -Klasse gehen, um den Bytecode -Erzeugungsprozess der spezifischen Proxy -Klasse anzuzeigen.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.