Pergunta

Aqui está o problema que eu estou correndo em. Há um aplicativo de legado enorme que roda em java 1.3 e usos da API externa, digamos, v1.0 MyAPI. A implementação exata do MyAPI 1.0 está localizada em algum lugar no classpath usado pelo aplicativo. Há também um mecanismo que permite que o aplicativo para usar o código externo (algum tipo de mecanismo de encaixe). Agora eu tenho outra biblioteca java (MyLib.jar) que usa v2.0 MyAPI (que não é 100% compatível com v1.0) e eu tenho que usá-lo a partir do aplicativo original usando esse mecanismo de encaixe. Então eu tenho que de alguma forma deixar duas versões (incompatíveis!) De uma mesma obra API juntos. Especificamente, eu quero usar v2.0 MyAPI quando classes de API são invocados a partir MyLib.jar classes e uso MyAPI 1.0 em todos os outros casos.

MyAPI 1.0 está no classpath, por isso vai ser usado por padrão, isso é ok. Eu posso criar minha própria versão do carregador de classe para classes de carga de MyAPI 2.0 - não há problema. Mas como faço para encaixar tudo junto? Perguntas:

  1. objetos MyLib.jar instanciar muito (!) De instâncias de classes de MyAPI 2.0. Isso significa que eu vou ter que fazer todas essas instâncias através de reflexão (especificando o meu próprio carregador de classe)? Isso é um inferno de um trabalho!

  2. Se alguns dos objetos MyAPI 2.0 é instanciado e instancia internamente outro objeto de MyAPI, o carregador de classe será que vai usar? Será que usar o meu carregador de classe ou de um padrão?

  3. Apenas geralmente, faz o meu som abordagem razoável? Existe uma maneira melhor?

Foi útil?

Solução

Vamos começar de responder a sua pergunta 2: quando se refere de alguma classe para outra classe que será carregado pelo mesmo carregador de classe que carregou a classe original (a menos que o carregador de classe não teve êxito em encontrar a classe e, em seguida, ele vai delegar ao seu carregador de classe pai).

Dito isto, por que não vai todo o seu MyLib.jar ser carregado por um carregador de classe personalizada, e em seguida, ele pode consultar a versão mais recente da API de uma forma regular. Caso contrário, você tem um problema, porque você vai ter que trabalhar com o tipo de objeto e reflexão durante todo o tempo.

Outras dicas

Você precisa ter cuidado com carregadores de classe. Se você faz o que você estava sugerindo, você quase sempre acabam MyAPI 1.0, mesmo quando usando seu carregador de classe para MyAPI 2.0. A razão para isto é como as classes são carregadas utilizando o carregador de classe. As classes são sempre carregado a partir do carregador de classe principal em primeiro lugar.

"A classe ClassLoader usa um modelo de delegação de pesquisa para classes e recursos. Cada instância de ClassLoader tem um carregador de classe pai associado. Quando solicitado para encontrar uma classe ou de recursos, uma instância ClassLoader vai delegar a busca para a classe ou recurso ao seu carregador de classe pai antes de tentar encontrar a classe ou recurso em si. a máquina virtual é construído-in carregador de classe, chamada de "carregador de classe de bootstrap", não em si tem um pai, mas pode servir como o pai de uma instância ClassLoader. " ( http://java.sun.com/javase /6/docs/api/java/lang/ClassLoader.html )

Para fornecer isolamento entre as duas APIs corretamente, você precisaria de 2 carregadores de classe (ou 2, além de o principal aplicação).

Parent - System classloader
  |- Classloader1 - Used to load MyAPI 1.0
  |- Classloader2 - Used to load MyAPI 2.0

Agora, para suas perguntas. O que você provavelmente vai querer fazer é mover a maior parte da lógica que usa a API para os carregadores de classe. Além MyAPI 1.0 / 2.0, você deve carregar a parte do aplicativo que usa os. Em seguida, o aplicativo pai só tem que chamar um método que utiliza a API. Desta forma, você fazer uma única chamada reflexão para iniciar o aplicativo e tudo dentro desse aplicativo usa apenas referências padrão.

Você pode fazer isso com um ClassLoader fantasia sem reflexão.

Basicamente, o carregador de classe tem a dizer "se a classe de carga a partir deste frasco, carga de classpath B, caso contrário, usar o ClassLoader principal".

É um pouco mais complicado do que isso, mas se você começar a partir dessa idéia que você vai ter que funcionou.

Isso parece razoável. No [javadoc API para loadClass] [1] diz:

"Carrega a classe com o nome binário especificado A implementação padrão desse pesquisas método para classes na seguinte ordem.: Invoke findLoadedClass (String) para verificar se a classe já foi carregado.

invocar o método loadClass sobre o carregador de classe pai. Se o pai é nulo o carregador de classe embutido para a máquina virtual é usado, em seu lugar.

invocar o FindClass (String) método para encontrar a classe. "

Se CL1 é para MyAPI1, CL2 é para MyAPI2 e CL3 é para MyLib parece que você quer que eles sejam verificados na ordem: CL3, CL2, CL1. Que a partir da citação acima (como os pais são verificados primeiro) sugere que você quer CL1 ter CL2 pai, e CL2 ter CL3 pai. Como o construtor com um carregador de classes pai é protegido, você vai ter que classloader uso URL com os pais definir de forma adequada.

Algo como

URLCLassLoader cl3 = new URLClassLoader(new URL[]{ path to MyLib});
URLCLassLoader cl2 = new URLClassLoader(new URL[]{ path to API2}, cl3);
URLCLassLoader cl1 = new URLClassLoader(new URL[]{ path to API1}, cl2);

então usar cl1 em todos os lugares.

[1]: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassLoader.html#loadClass (java.lang.String , boolean)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top