O que é um Java ClassLoader?

174

Em algumas frases simples, o que é um Java ClassLoader, quando é usado e por quê?

OK, eu li um artigo da wiki. ClassLoader carrega classes. ESTÁ BEM. Portanto, se eu incluir arquivos jar e importar, um ClassLoader fará o trabalho.

Por que eu deveria me preocupar com este ClassLoader? Eu nunca usei e nem sabia que existia.

A questão é: por que a classe ClassLoader existe? E também, como você o usa na prática? (Casos existem, eu sei.)

EugeneP
fonte
Você obterá melhores resultados se você afinar a sua questão, por exemplo, apontando uma parte específica que você não entende, como se relaciona com algum outro idioma que você está familiarizado com, etc.
JRL
75
Esta é uma questão completamente razoável, quando visto a partir da perspectiva de alguém procura de algumas frases simples para explicar o conceito
oxbow_lakes
Este vídeo pode ser interessante: Você realmente recebe carregadores de classes?
Asmaier # 30/13

Respostas:

231

Retirado deste belo tutorial da Sun:

Motivação

Os aplicativos escritos em linguagens de programação compiladas estaticamente, como C e C ++, são compilados em instruções nativas específicas da máquina e salvos como um arquivo executável. O processo de combinar o código em um código nativo executável é chamado de vinculação - a mesclagem do código compilado separadamente com o código da biblioteca compartilhada para criar um aplicativo executável. Isso é diferente nas linguagens de programação compiladas dinamicamente, como Java. Em Java, os arquivos .class gerados pelo compilador Java permanecem como estão até serem carregados na Java Virtual Machine (JVM) - em outras palavras, o processo de vinculação é executado pela JVM em tempo de execução. As classes são carregadas na JVM 'conforme necessário'. E quando uma classe carregada depende de outra classe, essa classe também é carregada.

Quando um aplicativo Java é iniciado, a primeira classe a ser executada (ou o ponto de entrada no aplicativo) é aquela com o método void estático público chamado main (). Essa classe geralmente tem referências a outras classes, e todas as tentativas de carregar as classes referenciadas são realizadas pelo carregador de classes.

Para ter uma idéia desse carregamento de classe recursivo, bem como da ideia de carregamento de classe em geral, considere a seguinte classe simples:

public class HelloApp {
   public static void main(String argv[]) {
      System.out.println("Aloha! Hello and Bye");
   }
}

Se você executar esta classe especificando a opção de linha de comando -verbose: class, para que ela imprima quais classes estão sendo carregadas, você obterá uma saída com a seguinte aparência. Observe que essa é apenas uma saída parcial, pois a lista é muito longa para ser mostrada aqui.

prmpt>java -verbose:class HelloApp



[Opened C:\Program Files\Java\jre1.5.0\lib\rt.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jsse.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\jce.jar]
[Opened C:\Program Files\Java\jre1.5.0\lib\charsets.jar]
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
[Loaded java.lang.System from shared objects file]
[Loaded java.lang.Throwable from shared objects file]
.
.
.
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded java.security.Principal from shared objects file]
[Loaded java.security.cert.Certificate from shared objects file]
[Loaded HelloApp from file:/C:/classes/]
Aloha! Hello and Bye
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]

Como você pode ver, as classes de tempo de execução Java exigidas pela classe de aplicativo (HelloApp) são carregadas primeiro.

Carregadores de classe na plataforma Java 2

A linguagem de programação Java continua evoluindo para facilitar a vida dos desenvolvedores de aplicativos todos os dias. Isso é feito fornecendo APIs que simplificam sua vida, permitindo que você se concentre na lógica de negócios, e não nos detalhes da implementação de mecanismos fundamentais. Isso é evidente pela recente mudança do J2SE 1.5 para o J2SE 5.0, a fim de refletir a maturidade da plataforma Java.

A partir do JDK 1.2, um carregador de classes de autoinicialização integrado à JVM é responsável por carregar as classes do tempo de execução Java. Esse carregador de classes carrega apenas as classes encontradas no caminho de classe de inicialização e, como essas são classes confiáveis, o processo de validação não é executado como nas classes não confiáveis. Além do carregador de classes de autoinicialização, a JVM possui um carregador de classes de extensão responsável por carregar classes de APIs de extensão padrão e um carregador de classes de sistema que carrega classes de um caminho de classe geral, bem como de suas classes de aplicativos.

Como há mais de um carregador de classes, eles são representados em uma árvore cuja raiz é o carregador de classes de autoinicialização. Cada carregador de classes tem uma referência ao seu carregador de classes pai. Quando um carregador de classes é solicitado a carregar uma classe, ele consulta seu carregador de classes pai antes de tentar carregar o item em si. O pai, por sua vez, consulta seu pai e assim por diante. Portanto, é somente depois que todos os carregadores de classes ancestrais não conseguem encontrar a classe que o carregador de classes atual se envolve. Em outras palavras, um modelo de delegação é usado.

A classe java.lang.ClassLoader

The java.lang.ClassLoaderé uma classe abstrata que pode ser subclassificada por aplicativos que precisam estender a maneira pela qual a JVM carrega dinamicamente classes. Os construtores em java.lang.ClassLoader(e suas subclasses) permitem especificar um pai ao instanciar um novo carregador de classes. Se você não especificar explicitamente um pai, o carregador de classes do sistema da máquina virtual será atribuído como pai padrão. Em outras palavras, a classe ClassLoader usa um modelo de delegação para procurar classes e recursos. Portanto, cada instância do ClassLoader possui um carregador de classes pai associado, de modo que, quando solicitado a encontrar uma classe ou recursos, a tarefa é delegada ao seu carregador de classes pai antes de tentar encontrar a própria classe ou recurso. O loadClass()método do ClassLoader executa as seguintes tarefas, em ordem, quando chamado para carregar uma classe:

Se uma classe já foi carregada, ela a retorna. Caso contrário, ele delega a pesquisa para a nova classe no carregador de classes pai. Se o carregador de classes pai não encontrar a classe, loadClass()chame o método findClass()para localizar e carregar a classe. O finalClass()método procura a classe no carregador de classes atual se a classe não foi encontrada pelo carregador de classes pai.


Há mais no artigo original, que também mostra como implementar seus próprios carregadores de classes de rede, o que responde à sua pergunta sobre o porquê (e como). Veja também os documentos da API .

JRL
fonte
47

A maioria dos desenvolvedores Java nunca precisará usar explicitamente carregadores de classes (exceto para carregar recursos, para que ainda funcionem quando estiverem agrupados em JARs), e muito menos escrever seus próprios.

Os ClassLoaders são usados ​​em grandes sistemas e aplicativos de servidor para fazer coisas como:

  • Modularize um sistema e carregue, descarregue e atualize módulos em tempo de execução
  • Use versões diferentes de uma biblioteca de API (por exemplo, um analisador XML) em paralelo
  • Isole diferentes aplicativos em execução na mesma JVM (garantindo que eles não interfiram entre si, por exemplo, através de variáveis ​​estáticas)
Michael Borgwardt
fonte
29

A pergunta é "Por que alguém deveria incomodar essa classe ClassLoader"?

Bem, principalmente para que você possa consertar as coisas se elas derem errado :-).

É verdade, desde que você apenas escreva um aplicativo, compile-o em um JAR e talvez inclua alguns JARs extras da biblioteca, você não precisa saber sobre os carregadores de classes, ele funcionará.

Ainda assim, é útil conhecer um pouco sobre carregadores de classes e carregamento de classes para entender melhor o que acontece nos bastidores. Como um exemplo, "inicializadores estáticos" serão executados quando uma classe for carregada. Para entender quando eles serão executados, você precisa saber como o carregador de classes decide quando carregá-los.

também .. como você o usa na prática?

Para casos simples, você não precisa deles. No entanto, se você precisar carregar código dinamicamente em tempo de execução, com controle explícito de onde ele vem (por exemplo, carregamento em uma rede, carregamento de plug-ins não disponíveis no momento da compilação etc.), poderá ser necessário fazer mais. Então você pode, por exemplo, escrever seu próprio carregador de classes. Veja as outras respostas para obter links.

sleske
fonte
14

ClassLoaderin Java é uma classe usada para carregar arquivos de classe em Java. O código Java é compilado no arquivo de classe pelo javaccompilador e a JVM executa o programa Java, executando códigos de bytes escritos no arquivo de classe.

O ClassLoader é responsável por carregar arquivos de classe do sistema de arquivos, da rede ou de qualquer outra fonte. Existem três carregadores de classes padrão usados ​​no carregador de classes Java, Bootstrap , Extension e System ou Application .

ClassLoader


Como o ClassLoader funciona

## Interação do ClassLoader com a JVM insira a descrição da imagem aqui

More @: how-classloader-works-in-java.html

roottraveller
fonte
6

Os Carregadores de Classes são um componente funcional da JVM, que carrega dados de classe do arquivo '.class' ou da rede para a Área de Método no Heap.

Parece parte integrante da JVM, mas como usuário final do java, por que devo me preocupar? Aqui está o porquê:

Cada carregador de classes possui seu próprio espaço para nome e as classes chamadas por um carregador de classes específico entram no seu espaço para nome.

As classes invocadas por dois carregadores de classes diferentes não terão visibilidade uma da outra, resultando em maior segurança.

O mecanismo de delegação filho pai do carregador de classes garante que as classes java api nunca possam ser invadidas por código não autorizado.

Para detalhes veja aqui

bitan
fonte
1

Carregadores de classe são hierárquicos. As classes são introduzidas na JVM à medida que são referenciadas pelo nome em uma classe que já está em execução na JVM.

Como a primeira classe foi carregada?
A primeira classe é carregada com a ajuda do static main()método declarado em sua classe. Todas as classes carregadas subseqüentemente são carregadas pelas classes, que já estão carregadas e em execução.

Um carregador de classes cria um espaço para nome. Todas as JVM incluem pelo menos um carregador de classes incorporado à JVM denominado carregador de classes primordial (ou de autoinicialização) . Isso é uma coisa, e veremos os carregadores de classes não primordiais. A JVM possui ganchos para permitir que carregadores de classes definidos pelo usuário sejam usados ​​no lugar do carregador de classes primordiais. Aqui estão os carregadores de classes criados pela JVM.

Bootstrap (primordial) Este carregador de classes não é recarregável. Carrega classes internas do JDK, pacotes java. * (Normalmente carrega rt.jar e i18n.jar). Extensões Este carregador de classes não é recarregável. Carrega arquivos jar do diretório de extensões do JDK (geralmente lib / ext do JRE). Sistema Este carregador de classes não é recarregável. Carrega classes do caminho da classe do sistema.

http://www.sbalasani.com/2015/01/java-class-loaders.html

Srinivas Balasani
fonte
1

Quando você pergunta por que a classe ClassLoader existe, o motivo é bem simples: é a classe responsável por localizar e carregar arquivos de classe em tempo de execução .

Vamos elaborar isso.

Na JVM, toda classe é carregada por alguma instância de java.lang.ClassLoader. Sempre que uma nova JVM é iniciada pelo java <classname>comando usual de inicialização do programa Java , a primeira etapa é carregar todas as classes de chave na memória necessárias para o funcionamento adequado java.lang.Objecte outras classes de tempo de execução ( rt.jar).

Agora, existem três partes no ClassLoader:

  • O BootstrapClassLoaderresponsável por disponibilizar essas classes, ou seja, carregar essas classes na memória.

  • A próxima tarefa é carregar quaisquer bibliotecas / JARs externos na memória para o funcionamento adequado do aplicativo. O ExtClassLoaderé responsável por esta tarefa. Este carregador de classes é responsável por carregar todos os arquivos .jar mencionados no caminho java.ext.dirs.

  • O terceiro e o principal carregador de classes importante é o AppClassLoader. O carregador de classes do aplicativo é responsável pelo carregamento dos arquivos de classe mencionados na propriedade do sistema java.class.path.

Também é importante observar que as implementações padrão do ClassLoader podem ser substituídas, permitindo que você personalize a JVM de maneiras úteis e interessantes, permitindo redefinir completamente como os arquivos de classe são trazidos para o sistema.

insira a descrição da imagem aqui

Confira para saber mais sobre o Java Class Loader .

Johnny
fonte