No artigo anterior, analisamos como a classe de proxy é gerada dentro da classe proxy. Vimos que o mecanismo de cache é usado dentro do proxy. Se a classe proxy puder ser encontrada no cache com base na classe de classe fornecida e na matriz de interface, a classe proxy será retornada diretamente. Caso contrário, a fábrica proxyclassFactory será chamada para gerar a classe Proxy. O cache usado aqui é um cache secundário, e sua chave de cache de primeiro nível é gerada com base no carregador de classe, e a chave de cache de segundo nível é gerada com base na matriz de interface. Publicaremos diretamente o código para explicar o mecanismo interno específico em detalhes.
// fila de referência de referência Private final ReferenceQueue <k> refqueue = new ReferenceQueue <> (); // A implementação subjacente do cache, a chave é o cache de primeiro nível e o valor é o cache de segundo nível. Para suportar o NULL, o tipo de mapa principal é definido como ObjectPrivate Final ConcurrentMap <Object, ConcurrentMap <Object, Fornecedor <V>>> map = new ConcurrentHashmap <> (); // ReverseMap registra se todos os geradores de classe proxy estão disponíveis. Isso é para implementar o mecanismo de expiração do cache privado final ConcurrentMap <Fornecedor <V>, boolean> reverseMap = new ConcurrentHashmap <> (); // A fábrica que gera a chave de cache secundária, a fábrica que gera o gênero final da fábrica <k, p, p,? Bifunção <k, p, v> valuefactory; // construtor, a fábrica que gera a chave de cache secundária e a fábrica que gera o valor do cache secundário public fratCache (bifunction <k, p,?> SubkeyFactory, bifunction <k, p, vugeptória) {this.subkeyPactory = Objection.requunction <k, p, v> this.valueFactory = Objects.RequirenOnNull (ValueFactory);}Primeiro, vamos dar uma olhada nas variáveis do membro e no construtor do fracos. A implementação interna do cache do fracoscache é concluída através do ConcurrentMap. O mapa variável do membro é a implementação subjacente do cache secundário. O mapa de reversão é implementar o mecanismo de expiração do cache. A sub -fábrica é a fábrica de geração da chave de cache secundária. É passado através do construtor. O valor aprovado aqui é o KeyFactory da classe Proxy, e o ValueFactory é a fábrica de geração do valor do cache secundário. É passado através do construtor. A classe proxy proxyclassFactory é passada aqui. Em seguida, vamos dar uma olhada no método Get de fracos.
public v get (K -Key, parâmetro p) {// A interface necessária a ser implementada aqui não pode ser objetos vazios.RequiReNonNull (parâmetro); // cache expirado expirado ExpungestaleEntries (); // Wrap ClassLoader no CacheKey como uma chave para o objeto de cache de primeiro nível CacheKey = cacheKey.valueof (chave, refqueue); // Obtenha o cache secundário ConcurrentMap <Objeto, Fornecedor <V>> valoresMap = map.get (cacheKey); // Se o valor correspondente não for obtido com base no ClassLoader se (valoresMap == null) {// coloque -o no CAS, se não existir, coloque -o, caso contrário, retorne o valor original ConcurrentMap <Object, Fornecedor <V>> OldValuesMap = map.putifabsent (cachekey, valoresmap = new ConcorrentHMAP <> // Se o OldValuesMap tiver um valor, significa que o posicionamento falhou se (OldValuesMap! = NULL) {valoresMap = OldValuesMap; }} // Crie a tecla de cache de segundo nível com base na matriz de interface implementada pela classe Proxy, dividida em key0, key1, key2, keyx objeto subkey = objects.requiteNonNull (subkeyFactory.apply (key, parameter)); // O valor do cache secundário é obtido através da subchave. Fornecedor <V> fornecedor = valoresMap.get (Subkey); Fábrica de fábrica = nulo; // Este loop fornece um mecanismo de votação. Se a condição for falsa, continue tentando novamente até que a condição seja verdadeira enquanto (true) {// se o valor recuperado através da subchave não estiver vazio se (fornecedor! = Null) {// aqui o suprimento pode ser uma fábrica ou um cachevalue // nenhum julgamento é feito aqui, mas verifique no método da get of the fornecedores de implementação Value v vale = supplier.get.get.get.get.gen; if (value! = null) {return value; }} if (Factory == null) {// Crie uma nova instância de fábrica como o valor correspondente da subcheque Factory = New Factory (chave, parâmetro, subchave, valoresmap); } if (fornecedor == null) {// Então, aqui significa que a Subkey não possui valor correspondente, coloque a fábrica como o valor da subchave no fornecedor = valoresMap.putifabsent (Subkey, Factory); if (fornecedor == null) {// Então aqui significa que a fábrica é colocada com sucesso no fornecedor de cache = fábrica; } // Caso contrário, outros threads podem modificar o valor durante o período, então não continuamos mais a atribuir valores à subchave, mas os retiram e os usam diretamente} else {// Durante esse período, outros threads podem ter modificado o valor; portanto, substitua o valor original se (valoresMap.replace (Subkey, Supplier, Factory)) {// // com sucesso; } else {// Substitua falhou, continue usando o fornecedor de valor original = valoresmap.get (subkey); }}}}O método GET do fracoscache não sincroniza com os bloqueios, então como ele atinge a segurança do thread? Como todas as suas variáveis de membro modificadas usam o ConcurrentMap, esta classe é segura para threads. Portanto, ele delega sua própria segurança de encadeamento ao ConcurrentMap e o método GET reduz o máximo possível os blocos de código de sincronização, o que pode melhorar efetivamente o desempenho do fracoCache. Vemos que o Classloader é uma chave do cache do nível 1, para que possamos filtrá -lo primeiro de acordo com o Classloader, porque as classes carregadas por diferentes carregadores de classe são diferentes. Em seguida, ele usa uma matriz de interface para gerar a chave do cache secundário. Aqui tem algumas otimizações. Como a maioria das classes implementa uma ou duas interfaces, a tecla de cache secundária é dividida em Key0, Key1, Key2 e KeyX. Key0 para KEY2 significa que 0 a 2 interfaces são implementadas e o KEYX significa que 3 ou mais interfaces são implementadas. De fato, a maioria deles usará apenas Key1 e Key2. A fábrica de geração dessas teclas está na classe de procuração e a fábrica principal é transmitida pelo construtor de fracos. O valor do cache de segundo nível aqui está uma instância de fábrica, e o valor final da classe proxy é obtido através da fábrica de fábrica.
Classe final privada Factory implementa o fornecedor <V> {// Chave de cache de nível 1, gera a chave final privada K de acordo com o Classloader; // Parâmetro P Private Final da matriz de interface implementado pela classe Proxy; // Chave de cache de nível 2, gerar subcke do objeto final privado de acordo com a matriz da interface; // Nível 2 Cache privado final ConcurrentMap <Objeto, Fornecedor <v >> valoresMap; Factory (Key K, parâmetro P, subcheque de objeto, ConcurrentMap <Object, Fornecedor <V>> valoresMap) {this.key = key; this.parameter = parâmetro; this.subkey = subkey; this.ValuesMap = valoresMap; } @Override public sincronizado v get () {// Aqui vou para o cache secundário novamente para fazer com que o fornecedor verifique se é o próprio fornecedor de fábrica <V> fornecedor = valoresmap.get (subkey); Se (fornecedor! } V valor = nulo; tente {// delegue o valuefactory para gerar a classe Proxy, aqui o valor da classe proxy será gerado por meio do proxyclassFactory de entrada = objects.RequiRononLull (valueFactory.Apply (key, parâmetro)); } finalmente {// Se a geração da classe proxy falhar, exclua este cache secundário se (value == null) {valoresmap.remove (subkey, this); }} // Somente o valor do valor não está vazio pode chegar aqui, afirmar valor! = Null; // a classe proxy Cachevalue <V> Cachevalue = new Cachevalue <> (valor); // Coloque o Cachevalue embalado no cache secundário. Esta operação deve ser bem -sucedida, caso contrário, será relatado um erro se (valoresmap.preplace (subkey, isto, Cachevalue)) {// Depois de colocar com êxito o Cachevalue no cache secundário, marcar ele reversemap.put (Cachevalue, boolean.true); } else {lança novo assertionError ("não deve chegar aqui"); } // finalmente retorna o valor de retorno da classe proxy que não é envolvido com referência fraca; }}Vejamos novamente a fábrica da classe de fábrica interna e podemos ver que seu método GET é sincronizado usando a palavra -chave sincronizada. Depois de executar o método GET, primeiro verifique se o fornecedor correspondente à Subkey é a própria fábrica. Caso contrário, ele retornará nulo e o método do fracoCache Get continuará tentando novamente. Se for realmente a própria fábrica, o ProxyclassFactory será delegado para gerar a classe de proxy, que é aprovada ao construir o fracoCache. Então, aqui explica por que a fábrica interna proxyclassFactory em proxy é chamada para gerar a classe proxy no final. Depois de gerar a classe proxy, ele usa uma referência fraca para envolvê -la e colocá -la em mapa inversa e, finalmente, retorna a classe de proxy original.
Até o momento, revelamos em detalhes a implementação do cache do fracos, incluindo seus princípios de implementação de cache de primeiro nível e cache de segundo nível, bem como o princípio de gerar a chave de cache de segundo nível e como ela chama de proxyclassFactory para gerar a classe proxy no final. No próximo artigo, entraremos na classe ProxyGenerator para ver o processo de geração de bytecode da classe de proxy específica.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.