En el artículo anterior, analizamos cómo se genera la clase proxy dentro de la clase proxy. Vimos que el mecanismo de caché se usa dentro del proxy. Si la clase proxy se puede encontrar en el caché en función de la matriz de cargador de clase e interfaz proporcionada, la clase proxy se devolverá directamente. De lo contrario, la fábrica proxyClassFactory será llamada para generar la clase proxy. El caché utilizado aquí es un caché secundario, y su tecla de caché de primer nivel se genera en función del cargador de clase, y la tecla de caché de segundo nivel se genera en función de la matriz de interfaz. Publicaremos directamente el código para explicar el mecanismo interno específico en detalle.
// cola de referencia de referencia referencia final de referencia final <k> refqueue = new RefectiveQueue <> (); // La implementación subyacente de caché, la clave es la memoria caché de primer nivel y el valor es el caché de segundo nivel. Para admitir NULL, el tipo clave de mapa se establece en ObjectPrivate Final ConcurrentMap <Object, concurrentMap <Object, Proveedor <V>>> MAP = nuevo ConcurrentDashMap <> (); // Reversión registra si todos los generadores de clases proxy están disponibles. Esto es para implementar el mecanismo de expiración de caché, el mapas concurrentes finales privados <proveedor <v>, boolean> reverseMap = new concurrenthashmap <> (); // La fábrica que genera la clave de caché secundaria, el valor de KeyFactory Bifunction final <K, P,?> SubkeyFactory; // La fábrica que genera el Valor de Cache Secondary, aquí es el Valor Cache de Cache, aquí es el Valor Cache de Cache, aquí es el Valor Cache de ProxyClays. Bifunción <k, p, v> valueFactory; // constructor, la fábrica que genera la tecla de caché secundaria y la fábrica que genera el valor de caché secundario public didietCache (bifunction <k, p, "subkeyfactory, bifunción <k, p, v> valuefactory) {this.subkeyfactory = objetuals.requirenonnull (subterrupción); this.ValueFactory = Objects.RequirenonNull (ValueFactory);}Primero, echemos un vistazo a las variables de los miembros y el constructor de DeakCache. La implementación interna de DeakCache Cache se completa a través de concurrentes. El mapa variable de miembro es la implementación subyacente del caché secundario. El reverso es implementar el mecanismo de vencimiento de la memoria caché. La fábrica de fábricas subterráneas es la fábrica de generación de la tecla de caché secundaria. Se pasa a través del constructor. El valor aprobado aquí es la KeyFactory de la clase proxy, y el valueFactory es la fábrica de generación del valor de caché secundario. Se pasa a través del constructor. La clase Proxy ProxyClassFactory se pasa aquí. A continuación, echemos un vistazo al método GET de WeakCache.
public v get (k key, parámetro p) {// La interfaz requerida que se implementará aquí no puede ser objetos vacíos. Requirenonnull (parámetro); // borrar el caché expirado exungestaleEnries (); // Envuelve class Loader en CacheKey como clave para el objeto de caché de primer nivel cachekey = cachekey.valueOf (clave, refQueue); // Obtenga el caché secundario concurrentMap <objeto, proveedor <v>> valoresmap = map.get (cachekey); // Si el valor correspondiente no se obtiene en función de ClassLoader if (ValuesMap == NULL) {// Ponlo en CAS, si no existe, colóquelo, de lo contrario devuelve el valor original concurrentMap <Object, proveedor <V>> OldValuesMap = MAP.PutifabSent (Cachekey, ValuesMap = New CoRurrentHashhashmap <> ()); // Si OldValuesMap tiene un valor, significa que la colocación falló si (OldValuesMap! = NULL) {ValuesMap = OldValuesMap; }} // Cree la tecla de caché de segundo nivel basada en la matriz de interfaz implementada por la clase proxy, dividida en Key0, Key1, Key2, KeyX Object Subkey = Objects.RequirenonNull (SubkeyFactory.Apply (Key, Parameter)); // El valor del caché secundario se obtiene a través de la subclave. Proveedor <v> proveedor = valoresmap.get (subpuesta); Fábrica de fábrica = nulo; // Este bucle proporciona un mecanismo de votación. Si la condición es falsa, continúe intentándolo nuevamente hasta que la condición sea verdadera mientras (verdadero) {// si el valor recuperado a través de la subclave no está vacío si (proveedor! = Null) {// aquí el suministro puede ser una fábrica o un cachevalue // no se hace un juicio aquí, pero verifique en el método get del proveedor de la clase v valor = proveedor.get ();; if (value! = null) {value de retorno; }} if (factory == null) {// Cree una nueva instancia de fábrica como el valor correspondiente de Subkey Factory = new Factory (Key, Parameter, Subkey, ValuesMap); } if (proveedor == null) {// Entonces aquí significa que la subpuesta no tiene un valor correspondiente, ponga fábrica como el valor de la subclave en el proveedor = ValuesMap.putifabsent (Subkey, Factory); if (proveedor == null) {// Entonces aquí significa que la fábrica se coloca con éxito en el proveedor de caché = fábrica; } // de lo contrario, otros subprocesos pueden modificar el valor durante el período, entonces ya no continuamos asignando valores a la subclave, sino que sáquelos y usándolos directamente} de lo contrario {// durante este período, otros subprocesos pueden haber modificado el valor, por lo que reemplazar el valor if (valores de valores.replace (subkey, proveedor, fábrica)) {// reemplazar con éxito la fábrica con un nuevo valor de valor = fábrica; } else {// reemplazar fallado, continúe usando el valor de valor original = valoresmap.get (subpuesta); }}}}El método GET de DeakCache no se sincroniza con los bloqueos, entonces, ¿cómo logra la seguridad de los subprocesos? Debido a que todas sus variables de miembros modificados usan concurrentMap, esta clase es segura de hilo. Por lo tanto, delega su propia seguridad de hilo a concurrenteMAP, y el método GET reduce los bloqueos del código de sincronización tanto como sea posible, lo que puede mejorar de manera efectiva el rendimiento de DeakCache. Vemos que el cargador de clases es una clave de caché de nivel 1, para que podamos filtrarlo primero de acuerdo con el cargador de clases, porque las clases cargadas por diferentes cargadores de clase son diferentes. Luego utiliza una matriz de interfaz para generar la clave del caché secundario. Aquí tiene algunas optimizaciones. Debido a que la mayoría de las clases implementan una o dos interfaces, la tecla de caché secundaria se divide en Key0, Key1, Key2 y KeyX. Key0 a Key2 significa que se implementan 0 a 2 interfaces, y KeyX significa que se implementan 3 o más interfaces. De hecho, la mayoría de ellos solo usarán Key1 y Key2. La fábrica de generación de estas claves está en la clase proxy, y la fábrica de clave se pasa a través del constructor DeakCache. El valor del caché de segundo nivel aquí es una instancia de fábrica, y el valor final de la clase proxy se obtiene a través de la fábrica de fábrica.
El proveedor de fábrica de clase final privada implementa <v> {// Llave de caché de nivel 1, genere la tecla K final privada de acuerdo con la carga de clases; // matriz de interfaz de parámetro P Private final implementado por la clase proxy; // Clave de caché de nivel 2, genere una subclave de objeto final privado de acuerdo con la matriz de interfaz; // nivel 2 Cache Privado Final ConcurrentMap <Object, Proveedor <v>> ValuesMap; Fábrica (k key, parámetro p, subterránea de objeto, concurrentemap <objeto, proveedor <v>> valores map) {this.key = key; this.parameter = parámetro; this.subkey = Subkey; this.ValuesMap = ValuesMap; } @Override public Synchronized v get () {// Aquí voy al caché secundario nuevamente para obtener el proveedor para verificar si es el propio proveedor de fábrica <V> proveedor = valoresmap.get (subkey); if (proveedor! = this) {// Aquí verifico si el proveedor es la instancia de fábrica en sí, si no, devuelve nulo y deja que la persona que llama continúe encuestando y vuelva a intentar // durante el período, el proveedor puede reemplazarse con Cachevalue, o se elimina de la caché secundaria debido a la falla para generar la clase Proxy; } V valor = nulo; Pruebe {// delegar el valor de valores para generar la clase proxy, aquí el valor de la clase proxy se generará a través del proxyclassFactory entrante = objects.requirenonnull (valueFactory.apply (key, parameter)); } Finalmente {// Si la generación de clases proxy falla, elimine este caché secundario if (value == null) {ValuesMap.Remove (subclaves, esto); }} // Solo el valor del valor no está vacío ¿Puede alcanzar aquí el valor de afirmar! = NULL; // La clase proxy Cachevalue <V> Cachevalue = new Cachevalue <> (valor); // Coloque el cacheValue empaquetado en el caché secundario. Esta operación debe ser exitosa, de lo contrario, se informará un error si (ValuesMap.replace (Subkey, this, Cachevalue)) {// después de poner con éxito Cachevalue en el caché secundario, marquelo reversemap.put (cachevalue, boolean.true); } else {tirar nueva afirmación ("no debe alcanzar aquí"); } // finalmente devuelve el valor de retorno de la clase proxy que no está envuelta con referencia débil; }}Veamos nuevamente la fábrica de clases de fábrica interna, y podemos ver que su método GET se sincroniza utilizando la palabra clave sincronizada. Después de realizar el método GET, primero verifique si el proveedor correspondiente a la subpuesta es la fábrica misma. Si no, devolverá NULL, y el método DableCache Get continuará intentando volver a intentarlo. Si de hecho es la fábrica misma, entonces proxyClassFactory se delegará para generar la clase proxy, que se pasa cuando se construye débilcache. Entonces, aquí explica por qué la fábrica interna proxyClassFactory en proxy se llama a generar la clase proxy al final. Después de generar la clase proxy, utiliza una referencia débil para envolverla y ponerla en reversiones, y finalmente devuelve la clase proxy original.
Hasta ahora, hemos revelado en detalle la implementación de la memoria caché de Cache Weakcache, incluida su caché de primer nivel y los principios de implementación de caché de segundo nivel, así como el principio de generar la tecla de caché de segundo nivel, y cómo llama ProxyClassFactory para generar la clase Proxy en el final. En el próximo artículo, iremos a la clase ProxyGenerator para ver el proceso de generación de Bytecode de la clase proxy específica.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.