Java.lang.instrument Agent Uso
O pacote java.lang.instrument foi introduzido no JDK5. Os programadores podem modificar dinamicamente o código de classe modificando o bytecode do método. Isso geralmente é pré -processado antes que o método principal da classe seja chamado e é implementado pelo Java para especificar a classe proxy da classe. Antes que o bytecode da classe seja carregado na JVM, o método de transformação do ClassFileTransformer será chamado para realizar a função de modificar o método de classe original e implementar a AOP. A vantagem disso é que ele não produzirá uma nova classe, como proxy dinâmico ou tecnologia CGLIB, que implementa a AOP, e não há necessidade de a classe original ter uma interface.
(1) O agente é um interceptador antes do seu método principal, ou seja, o código que executa o agente antes que o método principal seja executado. O código do agente é executado na mesma JVM que o seu método principal, é carregado pelo mesmo carregador de classe do sistema e é gerenciado pela mesma política e contexto de segurança. O agente do nome é um pouco enganador e não é o mesmo que o agente que geralmente entendemos. O agente Java é relativamente simples de usar. Como escrever um agente Java? Você só precisa implementar o método premArin: public static void premAn (string agenteargs, Instrumentation Inst) Se a definição acima de premArin não puder ser encontrada no JDK 6, você também tentará chamar a seguinte definição: Public Static Void PremAn (string agenteargs)
(2) A classe do agente deve ser digitada em um pacote JAR e, em seguida, o meta-inf/mainifest.mf interno deve conter o atributo de classe pré-pernas. Aqui está um exemplo de manifesto.mf:
Manifest-Version: 1.0 Premaint-Class: MYAGENT1 Criado por: 1.6.0_06
Em seguida, adicione manifesto.mf ao seu pacote JAR. A seguir, os atributos manifestos se manifestam para o arquivo JAR do agente: Classe premArin Se um proxy for especificado quando a JVM é iniciada, esse atributo especifica a classe Proxy, ou seja, a classe que contém o método prematurgo. Esta propriedade é necessária se um proxy for especificado quando a JVM for iniciada. Se a propriedade não existir, a JVM abortará. Nota: Esta propriedade é um nome de classe, não um nome ou caminho de arquivo. Classe do agente Se a implementação suportar o mecanismo para iniciar o agente em um certo momento após o início da VM, esta propriedade especifica a classe do agente. Isto é, a classe que contém o método AgentMain. Esta propriedade é necessária e o proxy não será iniciado se não existir. Nota: Este é o nome da classe, não o nome ou caminho do arquivo. A classe de inicialização define a lista de caminhos para pesquisas de carregador de classe de inicialização. Os caminhos representam diretórios ou bibliotecas (geralmente referenciados como bibliotecas JAR ou ZIP em muitas plataformas). Depois que um mecanismo específico da plataforma para encontrar uma classe falha, o carregador de classe de inicialização procura esses caminhos. Pesquise os caminhos no pedido listado. Os caminhos da lista são separados por um ou mais espaços. Os caminhos usam a sintaxe do componente do caminho do URI hierárquico. Se o caminho começar com um caractere de barra ("/"), é um caminho absoluto, caso contrário, é um caminho relativo. O caminho relativo é analisado com base no caminho absoluto do arquivo JAR de proxy. Ignore os caminhos com formato incorreto e caminhos inexistentes. Se o agente for iniciado em um determinado momento após o início da VM, o caminho que não representa o arquivo JAR será ignorado. Esta propriedade é opcional. As classes de recuperação de Can-Redefiniram booleanas (verdadeiras ou falsas, irrelevantes para a parte superior e inferior). Se as classes necessárias para esse proxy podem ser redefinidas. Outros valores que não são verdadeiros são considerados falsos. Esta propriedade é opcional e o valor padrão é falso. As classes de Can-setransformam booleanos (verdadeiros ou falsas, irrelevantes para a parte superior e inferior). Se as classes necessárias para esse proxy podem ser reconvertidas. Outros valores que não são verdadeiros são considerados falsos. Esta propriedade é opcional e o valor padrão é falso. Valor booleano de prefixo de métodos de combustão de poder (verdadeiro ou falso, irrelevante para a parte superior e inferior). Se o prefixo do método nativo exigido por esse proxy pode ser definido. Outros valores que não são verdadeiros são considerados falsos. Esta propriedade é opcional e o valor padrão é falso.
(3) Todos esses pacotes JAR de agentes serão adicionados automaticamente ao caminho de classe do programa. Portanto, não há necessidade de adicioná -los ao caminho de classe manualmente. A menos que você queira especificar a ordem dos pathes de classe.
(4) Não há limite para o número de parâmetros de -javaagent em um programa Java, para que você possa adicionar tantos agentes Java. Todos os agentes Java serão executados na ordem que você definir. Por exemplo:
java -Javaagent: myAgent1.jar -javaagent: myagent2.jar -jar myprogram.jar
Suponha que a principal função no MyProgram.jar esteja no Myprogram. MyAgent1.jar, myAgent2.jar, as classes que implementam precedentes nesses dois pacotes JAR são MyAgent1, e a ordem de execução do programa MyAgent2 será:
MyAgent1.premain -> myAgent2.premain -> myProgram.main
(5) Além disso, o precedente colocado após a função principal não será executado, por exemplo:
java -javaagent: myAgent1.jar -jar myProgram.jar -javaagent: myAgent2.jar
MyAgent2 é colocado atrás do MyProgram.jar, portanto, a pré -alcance do MyAGent2 não será executada; portanto, o resultado da execução será:
MyAgent1.premain -> myProgram.main
(6) Cada agente Java pode receber um parâmetro do tipo string, ou seja, agenteRgs no pré-rei. Este agenteRgs é definido na opção Java. Por exemplo:
java -Javaagent: myAgent2.jar = thisisagentargs -jar myprogram.jar
O valor dos agentes recebidos pela premain em MyAgent2 será "Thisisagentargs" (excluindo cotações duplas).
(7) Instrumentação no parâmetro: Adicione o ClassFileTransFormer definido pelo parâmetro para alterar o arquivo de classe. O transformador personalizado aqui implementa o método de transformação, que fornece modificação ao bytecode da classe a ser realmente executado e pode até chegar ao ponto de executar outro método de classe. Por exemplo: Escreva classe do agente:
pacote org.toy; importar java.lang.instrument.instrumentation; importar java.lang.instrument.classFileTransFormer; public classe perfmonagent {private estática Instrumentação Inst = null; /** * Esse método é chamado antes que o método principal do aplicativo seja chamado, * quando esse agente é especificado para a VM Java. **/ public static void premain (string agentargs, instrumentação _inst) {System.out.println ("perfmonagent.preMain () foi chamado."); // Inicialize as variáveis estáticas que usamos para rastrear informações. inst = _inst; // Configure o transformador de arquivo de classe. ClassFileTransFormer trans = new PerfMonxformer (); System.out.println ("Adicionando uma instância do PerfMonxformer à JVM."); Inst.addtransformer (trans); }}Escreva ClassFileTransformer Class:
pacote org.toy; importar java.lang.instrument.classFileTransformer; importar java.lang.instrument.illegalclassformatexception; importar java.security.protectionDomain; importação javassist.cannotCompileException; importação javassist.classPool; javassist.notfoundException; importar javassist.expr.expreditor; importar javassist.expr.methodCall; public class PerfMonXformer implementa ClassFileTransformer {public byte [] transfortDonsDorler (ClassLoader carregador, string className, classe <?> ClassBeLerFerSEnFined, ProtectomOngOMAnAin, por classe, classe [ClassBeLeFerTerDerSformEngOnDomain (ClassEnTeRaader, por classe, classe [ClassBeLeFerSFormEnTonsDomain (ClassEnEstenEnAntomAnin (ClassEnEsterMeNain (ClassEl) byte [] transformado = null; System.out.println ("Transforming" + ClassName); ClassPool Pool = ClassPool.getDefault (); Ctclass cl = null; tente {cl = pool.makeclass (new java.io.bytearrayinputStream (ClassFileBuffer)); if (cl.isinterface () == false) {ctBeHavior [] métodos = cl.getDeclaredbehaviors (); for (int i = 0; i <métodos.length; i ++) {if (métodos [i] .isempty () == false) {domethod (métodos [i]); }} transformado = cl.tobytecode (); }} Catch (Exceção e) {System.err.println ("Não foi possível instrumentar" + className + ", exceção:" + e.getMessage ()); } finalmente {if (cl! = null) {cl.detach (); }} retornar transformado; } private void domethod (método ctbehavior) lança NotfoundException, não pode comcompileException {// method.insertBefore ("long stime = system.nanotime ();"); // Method.insertafter ("System.out.println (/" Leave "+Method.getName ()+" e Time:/"+(System.nanotime ()-Stime));"); Method.Instrument (new ExPreditor () {public void Edit (MethodCall M) Os arremessos não podem ser compilados {M.Replace ("{LONG STIME = System.nanotime (); $ _ = $ prosseguem ($$); System.out.println (/" " +m.getClassName () +" "M.M.M.M.M.M.M.M.M.Mot.Println (/" " +m.getClassName () +" "" M.M. ":/"+(System.nanotime ()-stime));} ");}}); }}); }}As duas classes acima são o núcleo do agente. Quando a JVM iniciar, o perfmonagent.Premain será chamado antes que o aplicativo seja carregado. Em seguida, um ClassFileTransforme personalizado, como o PerfMonXformer, é instanciado no Perfmonagent.premain e, em seguida, um ClassFileTransformer personalizado é instanciado no PerfMonXformer e, em seguida, a instância do PerfMonxformer é adicionada à instituição de instrumentação (transmitida do JVM). Isso torna o perfmonxformer.transform será chamado quando a classe no aplicativo for carregada. Você pode alterar a classe carregada neste método. É realmente mágico. Para alterar o bytecode da classe, usei o Javassist de Jboss. Embora você não precise usá -lo assim, o Javassist de Jboss é realmente poderoso, permitindo que você altere facilmente o bytecode da classe.
No método acima, mudei o bytecode da classe e adicionei long stime = System.nanotime (); para a entrada do método de cada classe e adicionou System.out.println ("MethodClassName.MethodName:"+(System.nanotime ()-Stime));
Obrigado pela leitura, espero que isso possa ajudá -lo. Obrigado pelo seu apoio a este site!