Existem dois tipos de classes em Java, um é definido pelo usuário e o outro é o carregador de classe de bootstrap construído na JVM.
Existem três tipos de carregadeiras de classe incorporadas em JVM, ou seja, bootstrap de classe de classe, carregador de classe de extensão (ou seja, extclassloader) e carregador de classe do sistema (ou seja, AppClassLoader).
Não vou falar sobre a delegação de pais quando a JVM estiver carregada, há muitos artigos sobre Javaeye que são introduzidos ...
Você pode dar uma olhada nos construtores deles separadamente, onde o carregador de classe está escrito em c.
java.lang.classloader
Classe Protected (ClassLoader pai) {Security Security = System.getSecuryManager (); true; inicializado = true;
Este construtor possui dois parâmetros e nenhum construtor. O construtor com parâmetros passa no carregador pai desse carregador de classe, enquanto o construtor sem parâmetros tratará o carregador de classe retornado pelo getSystemClassLoader () como seu próprio carregador pai
Classe estática pública GetSystemClassLoader () {// O carregador de classe retornado é atribuído a InitsystemclassLoader (); ccl = getCalerClassLoader (); if (! sclset) {if (scl! = nulo) lança nova ilegalstateException ("invocação recursiva"); OOPS = NULL; // O valor é atribuído Scl = L.GetclassLoader (); .... .....................................}} sclset = true; O carregador da classe pai aqui é SCL, obtido por L.GetClassLoader (), getClassLoader () e, em seguida, observe o código -fonte do iniciador:
lançador estático privado iniciador = novo iniciador ();
public static iniciador getLauncher () {return iniciador; ); AppClassLoader, ou seja, o GetSystemClassLoader retorna AppClassLoader Loader = AppClassLoader.GetAppClassLoader (extcl); Thread, para evitar a confusão causada por cargas de classe em multithreads (eu mesmo entendo isso, haha) // também define o carregador de classe de contexto para o encadeamento primário. .................................................. ................................................ .. ..............} / * * Retorna o carregador de classe usado para iniciar o aplicativo principal. A partir disso, vemos que o carregador pai do AppClassLoader é o ExtclassLoader e qual é o carregador pai do ExtclassLoader? Vejamos o construtor ExtclassLoader:
public ExtclassLoader (arquivo [] Dirs) lança ioexception {super (getExturls (diretor), nulo, fábrica);Seu carregador pai está vazio, enquanto sua classe de nível superior é java.lang.classloader.
Classe sincronizada protegida <?> Loadclass (nome da string, resolução booleana) lança classeNotFoundException {// primeiro, verifique se a classe já foi carregada classe C = findLoadLeaDclass (nome); ! = NULL) {// Ligue para o carregador pai primeiro para carregar. ) {// Se ainda não encontrado, Invocar FindClass em ordem // para encontrar a classe.Aqui, o FindBootStrapClass0 é chamar o carregador de classe de bootstrap, o carregador de classe mais principal, para carregar a classe.
Por fim, podemos ver que o carregador de classe retornou pelo getSystemClassLoader () é AppClassLoader.
Análise de mecanismo de carga de classe Java
JDK Padrão ClassLoader
O JDK fornece os seguintes carregadores de classe por padrão
Carregador de bootstp
O carregador de bootstp é escrito no idioma C ++. jre/classes.
Extclassloader
O carregador de bootstp carrega o carregador extclass e define o carregador pai do carregador extclass para o carregador de bootstp. Isso todas as classes nos diretórios sob o caminho e as bibliotecas de classes no caminho especificado pela variável do sistema java.ext.dirs.
AppClassLoader
Depois que o carregador de bootstr carrega o ExtclassLoader, o AppClassLoader será carregado e o carregador pai do AppClassLoader é especificado como o ExtclassLoader. O AppClassLoader também é gravado no Java. É um documento JAR, que também é o carregador de classe padrão para programas Java.
Para resumir, a relação entre eles pode ser descrita na figura a seguir:
Modelo de delegação de pais
O carregamento de classe no Java adota um mecanismo de delegado dos pais.
Atualmente, o Classloader verifica primeiro se essa classe foi carregada da classe que já carregou.
Cada carregador de classe possui seu próprio cache de carregamento.
Quando o cache do carregador de classe não é encontrado, o carregador da classe pai é delegado para carregá -lo. Maneira de Bootstrp ClassLoader.
Quando todos os carregadores da classe pai não são carregados, eles são carregados pelo carregador de classe atual e os colocam em seu próprio cache para que possam ser devolvidos diretamente na próxima vez que houver uma solicitação de carregamento.
Falando nisso, você pode se perguntar, por que Java adota um mecanismo de delegação? Para entender esse problema, introduzimos outro conceito de "espaço para nome" sobre o carregador de classe, o que significa que, para determinar uma determinada classe, você precisa de um nome totalmente qualificado da classe e carregar esse carregador de classe para determinar em conjunto. Ou seja, mesmo que os nomes totalmente qualificados das duas classes sejam iguais, porque diferentes carregadores de classe carregam essa classe, é uma classe diferente na JVM. Depois de entender o espaço para nome, vamos dar uma olhada no modelo delegado. Após adotar o modelo de delegado, os recursos interativos de diferentes carregadores de classe são aumentados. Importa seu programa, existem muitos carregadores de classe, para que essas classes possam ser compartilhadas, o que evita confusão causada por diferentes carregadores de classe após o carregamento de diferentes classes com o mesmo nome.
Como personalizar o Classloader
Além do carregador de classe padrão mencionado acima, o Java também permite que os aplicativos personalizem o Classloader. Precisamos prestar atenção a vários métodos importantes:
1. Método do carregamento
Método da classe de carga declarar
Classe pública <?> LOADCLASS (Nome da String) lança ClassNotFoundException
O acima é a declaração do protótipo do método da classe de carga. Vamos dar uma olhada no código desse método para ver como ele implementa a delegação dos pais.
Método da classe de carga Implementar
classe pública <?> loadclass (nome da string) lança ClassNotFoundException {return loadclass (nome, false);}Pelo acima, podemos ver que o método da classe de carga chama o método loadcclass (nome, false), então vamos dar uma olhada na implementação de outro método de classe de carga.
Classe carregamento (nome da string, resolução booleana)
Classe sincronizada protegida <?> loadclass (nome da string, resolução booleana) lança ClassNotFoundException {// Primeiro, verifique se a classe já foi carregada classe C = findLoadLeDclass (nome); // Verifique se a classe foi carregada se (c = c = = null) {tente {if (parent! = null) {c = parent.loadclass (nome, false); } else {c = findBootStrapClass0 (nome); // Se não houver um carregador de classe pai, delegue o carregador de bootstrap para carregar}} catch (classNotfoundException e) {// se ainda não for encontrado, invoce e findclass em ordem // para para Encontre a classe. }} if (resolve) {resolveclass (c);No código acima, adicionei comentários para ver claramente como o mecanismo de delegação dos pais da classe de carga funciona. Uma coisa que precisamos observar aqui é que a classe pública <?> LOADCLASS (nome da string) lança ClassNotFoundException não está marcado como final, o que significa que podemos substituir esse método, o que significa que o mecanismo de delegação de pais pode ser quebrado. Além disso, notamos que existe um método FindClass acima.
2.FindClass
Verificamos o código -fonte do java.lang.classloader e descobrimos que a implementação do FindClass é a seguinte:
classe protegida <?> findClass (nome da string) lança classeNotFoundException {throw new ClassNotFoundException (nome);}Podemos ver que a implementação padrão desse método é lançar exceções diretamente, mas, de fato, esse método é deixado para o nosso aplicativo para substituir. A implementação específica depende da sua lógica de implementação. Vamos descrever o DefinirClass mais tarde. OK, através da análise acima, podemos tirar as seguintes conclusões:
Quando escrevemos nosso próprio carregador de classe, se queremos seguir o mecanismo de delegação dos pais, precisamos apenas substituir o FindClass.
3. DefinirClass
Vamos primeiro olhar para o código -fonte do DefinClass:
DefinirClass
Classe final protegida <?> DefinClass (Nome da String, Byte [] B, Int Off, Int Len) lança ClassFormaterror {Return definitivamenteClass (Nome, B, Off, Len, Null);}A partir do código acima, podemos ver que esse método é definido como final, o que significa que esse método não pode ser substituído. O arquivo deve estar em conformidade com a definição de classes especificadas pela especificação da máquina virtual Java. Esse método finalmente chamará o método nativo para implementar o carregamento da classe real.
OK, através da descrição acima, vamos pensar sobre a seguinte pergunta:
Se escrevemos uma classe Java.lang.string, podemos substituir a classe que chama o próprio JDK?
A resposta é não. Não podemos alcançá -lo. Por que? Vejo muitas explicações on -line de que o mecanismo de delegação dos pais resolve esse problema, mas na verdade não é muito preciso. Como o mecanismo de delegação dos pais pode ser quebrado, você pode escrever um carregador de classe para carregar a aula de java.lang.string que você escreveu, mas você descobrirá que não carregará com sucesso, especificamente porque é para a aula que começa com Java.*, JVM A implementação garantiu que deve ser carregada pelo Bootstrp.
Cenários que não seguem o "mecanismo de delegação dos pais"
O mencionado mencionado acima que o mecanismo de delegação pai é principalmente para realizar o problema de interação das classes carregadas entre diferentes carregadores de classe. Loader da classe pai em Java. Vamos falar sobre a ocorrência dessa situação.
Existe um padrão SPI (interface do provedor de serviços) em Java, que usa bibliotecas SPI, como JDBC, JNDI, etc. Todos sabemos que o JDBC precisa de drivers fornecidos por terceiros, e o pacote JAR é colocado em nosso aplicativo. ClassPath e API da JDBC faz parte da provisão do JDK e foi carregada pelo Bootstrp. O Java apresenta o conceito de carga de contexto de encadeamento. Driver, tudo bem, carregando o carregador de classe de contexto do thread.
Além disso, para implementar o carregador de classe mais flexível OSGI e alguns servidores de aplicativos Java, ele também quebra o mecanismo de delegação pai.