Dans l'article précédent, nous avons analysé comment la classe de proxy est générée à l'intérieur de la classe de procuration. Nous avons vu que le mécanisme de cache est utilisé à l'intérieur du proxy. Si la classe proxy peut être trouvée dans le cache en fonction du chargeur de classe fourni et du tableau d'interface, la classe proxy sera renvoyée directement. Sinon, l'usine Proxyclassfactory sera appelée pour générer la classe proxy. Le cache utilisé ici est un cache secondaire, et sa touche de cache de premier niveau est générée en fonction du chargeur de classe, et la touche de cache de deuxième niveau est générée en fonction du tableau d'interface. Nous publierons directement le code pour expliquer en détail le mécanisme interne spécifique.
// Référence de référence File d'attente privée Final Referenceeue <K> RefQueue = new ReferenceQueue <> (); // l'implémentation sous-jacente du cache, la clé est un cache de premier niveau et la valeur est un cache de deuxième niveau. Afin de prendre en charge NULL, le type de clé de la carte est défini sur ObjectPrivate Final concurrentMap <objet, concurrentMap <objet, fournisseur <v>>> map = nouveau concurrenthashmap <> (); // reversEMAP enregistre si tous les générateurs de classe proxy sont disponibles. Il s'agit de mettre en œuvre le mécanisme d'expiration du cache final final concurrentmap <v>, boolean> reversEMAP = new concurrenthashmap <> (); // l'usine qui génère la clé de cache secondaire, l'usine de la bifonction finale <k, p, p, p, ici est le proxclasse; BIFUNCTION FINAL <K, P, V> ValueFactory; // Constructeur, l'usine qui génère la clé de cache secondaire et l'usine qui génère la valeur du cache secondaire Public Waiwcache (Bifonction <K, P,?> SubkeyFactory, Bifonction <k, p, v> valuefactory) {this.subkeyfactory = objets.requirennull (subkey); this.valuefactory = objets.RequiRenonnull (ValueFactory);}Tout d'abord, jetons un coup d'œil aux variables membre et au constructeur de faibles. La mise en œuvre interne du cache faible est terminée via concurrentMap. La carte des variables membre est la mise en œuvre sous-jacente du cache secondaire. Le ReverseMap est de mettre en œuvre le mécanisme d'expiration du cache. Le Sous-KeyFactory est l'usine de génération de la clé de cache secondaire. Il est passé par le constructeur. La valeur réalisée ici est le KeyFactory de la classe de proxy, et la valeur de valeur est l'usine de génération de la valeur de cache secondaire. Il est passé par le constructeur. La classe proxy proxyclassfactory est passé ici. Ensuite, jetons un coup d'œil à la méthode GET de FaibleCache.
public v get (k key, paramètre p) {// L'interface qui doit être implémentée ici ne peut pas être des objets vides.RequiRenonnull (paramètre); // Clear Cache Expirestalentries (); // Enveloppez Classloader dans CacheKey comme clé pour l'objet Cache de premier niveau CacheKey = CacheKey.ValueOf (clé, RefQueue); // Obtenez le cache secondaire concurrentmap <objet, fournisseur <v>> valeursmap = map.get (cacheKey); // Si la valeur correspondante n'est pas obtenue sur la base de classloader if (valeursmap == null) {// le mettez-le en cas, s'il n'existe pas, mettez-le, sinon renvoyez la valeur d'origine concurrentmap <objet, fournisseur <v>> oldValuesMap = map.putifabsen (cacheKey, valeursmap = new ConcurrentHashMap <> ()); // Si OldValuesMap a une valeur, cela signifie que le placement a échoué si (OldValuesMap! = NULL) {ValuesMap = OldValuesMap; }} // Créez la touche de cache de deuxième niveau basée sur le tableau d'interface implémenté par la classe proxy, divisée en Key0, Key1, Key2, KeyX Object Subkey = Object.RequireNonnull (SubKeyFactory.Apply (clé, paramètre)); // La valeur du cache secondaire est obtenue via la sous-clé. Fournisseur <v> fournisseur = valeursmap.get (subkey); Usine d'usine = null; // Cette boucle fournit un mécanisme de sondage. Si la condition est fausse, continuez à réessayer jusqu'à ce que la condition soit vraie tandis que (true) {// si la valeur récupérée via Subkey n'est pas vide si (fournisseur! = Null) {// Ici l'approvisionnement peut être une usine ou une cachevalue // Aucun jugement n'est fait ici, mais vérifiez dans la méthode GET de la méthode de mise en œuvre du fournisseur Classe V Valeur = fournisseur.get (); if (value! = null) {return value; }} if (factory == null) {// Créer une nouvelle instance d'usine comme valeur correspondante de Subkey Factory = new Factory (clé, paramètre, sous-clé, valeursmap); } if (fournisseur == null) {// donc ici signifie que la sous-clé n'a pas de valeur correspondante, mettez l'usine comme valeur de la sous-clé dans fournisseur = valeursmap.putifabsent (sous-clé, usine); if (fournisseur == null) {// donc ici, cela signifie que l'usine est placée avec succès dans le fournisseur de cache = usine; } // Sinon, d'autres threads peuvent modifier la valeur pendant la période, alors nous ne continuons plus d'attribuer des valeurs à la sous-clé, mais les retirer et les utiliser directement} else {// Pendant cette période, d'autres threads peuvent avoir modifié la valeur, donc remplacer la valeur d'origine if (valeursmap.replace (subkey, fournisseur, factory)) {// Remplacez avec succès le facteur par une nouvelle valeur fournisseur = factory; } else {// Remplacer l'échec, continuer à utiliser le fournisseur de valeur d'origine = valeursmap.get (subkey); }}}}La méthode GET de FaibleCache ne se synchronise pas avec les verrous, alors comment réalise-t-il la sécurité des fils? Étant donné que toutes ses variables de membres modifiées utilisent ConcurrentMap, cette classe est filée. Par conséquent, il délégue sa propre sécurité de thread à concurrentMap, et la méthode GET réduit autant que possible le code de synchronisation, ce qui peut améliorer efficacement les performances de faible. Nous voyons que Classloader est une clé du cache de niveau 1, afin que nous puissions le filtrer d'abord en fonction de Classloader, car les classes chargées de différents chargeurs de classe sont différentes. Ensuite, il utilise un tableau d'interface pour générer la clé du cache secondaire. Ici, il a quelques optimisations. Étant donné que la plupart des classes implémentent une ou deux interfaces, la clé de cache secondaire est divisée en Key0, Key1, Key2 et Keyx. Key0 to Key2 signifie que les interfaces 0 à 2 sont implémentées, et Keyx signifie que 3 interfaces ou plus sont implémentées. En fait, la plupart d'entre eux n'utiliseront que Key1 et Key2. L'usine de génération de ces clés se trouve dans la classe de procuration, et l'usine de clés est transmise par le constructeur faible. La valeur du cache de deuxième niveau ici est une instance d'usine, et la valeur finale de la classe proxy est obtenue via l'usine d'usine.
L'usine de classe finale privée implémente le fournisseur <v> {// Cache de cache de niveau 1, générer une touche finale privée KELLED Selon Classloader; // Array d'interface Paramètre P privé final implémenté par la classe proxy; // Clé de cache de niveau 2, générez une sous-clé d'objet final privé en fonction du tableau d'interface; // Niveau 2 Cache privé final concurrentmap <objet, fournisseur <v>> valeursmap; Factory (key k, paramètre p, sous-clé d'objet, concurrentmap <objet, fournisseur <v>> valeursmap) {this.key = key; this.paramètre = paramètre; this.subKey = Subkey; this.valuesmap = valeursmap; } @Override public synchronisé v get () {// Ici, je vais à nouveau au cache secondaire pour que le fournisseur vérifie s'il s'agit de Factory lui-même fournisseur <v> fournisseur = valeursmap.get (subkey); si (fournisseur! = this) {// Ici, je vérifie si le fournisseur est l'instance d'usine elle-même, sinon, renvoyez NULL et laissez l'appelant continuer à interroger et à réessayer // pendant la période, le fournisseur peut être remplacé par une cachevalue, ou il est supprimé du cache secondaire en raison de l'échec de générer la classe Proxy; } V valeur = null; essayez {// déléguer le ValueFactory pour générer la classe proxy, ici la valeur de classe proxy sera générée via le proxyclassFactory = objets.RequiRenonnull (ValueFactory.Apply (Key, Paramètre)); } Enfin {// Si la génération de classe proxy échoue, supprimez ce cache secondaire if (value == null) {valeursmap.remove (subkey, this); }} // seule la valeur de la valeur n'est pas vide peut-elle atteindre ici la valeur d'affirmer! = Null; // La classe proxy cachevalue <v> cachevalue = new cachevalue <> (valeur); // Mettez la cachevalue emballée dans le cache secondaire. Cette opération doit être réussie, sinon une erreur sera signalée si (valeursmap.replace (sous-clé, ceci, cachevalue)) {// après avoir réussi à mettre cachevalue dans le cache secondaire, marquez-le reversemap.put (cachevalue, boolean.true); } else {lancer une nouvelle assertionError ("ne devrait pas atteindre ici"); } // Renvoie enfin la valeur de retour de classe proxy qui n'est pas enveloppée de référence faible; }}Regardons à nouveau l'usine de classe d'usine interne, et nous pouvons voir que sa méthode GET est synchronisée à l'aide du mot-clé synchronisé. Après avoir effectué la méthode GET, vérifiez d'abord si le fournisseur correspondant à la sous-clé est l'usine elle-même. Sinon, il reviendra NULL et la méthode FaibleCache Get continuera de réessayer. S'il s'agit bien de l'usine elle-même, ProxyclassFactory sera délégué pour générer la classe de procuration, qui est transmise lors de la construction de faiblesCache. Voici donc ici pourquoi l'usine interne proxyclassfactory dans le proxy est appelée pour générer la classe de proxy à la fin. Après avoir généré la classe proxy, il utilise une référence faible pour l'envelopper et la mettre dans ReverseMap, et renvoie enfin la classe de proxy d'origine.
Jusqu'à présent, nous avons révélé en détail la mise en œuvre du cache FaibleCache, y compris son cache de premier niveau et ses principes de mise en œuvre de cache de deuxième niveau, ainsi que le principe de génération de la clé de cache de deuxième niveau, et comment il appelle ProxyclassFactory pour générer la classe de procuration à la fin. Dans le prochain article, nous allons entrer dans la classe ProxyGenerator pour voir le processus de génération de bytecode de la classe de proxy spécifique.
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.