Eu preciso encontrar o chamador de um método. É possível usar stacktrace ou reflexão?
java
stack-trace
Sathish
fonte
fonte
DontNameYourMethodFooException
se o método de chamada é nomeado foo.Respostas:
De acordo com os Javadocs:
Um
StackTraceElement
temgetClassName()
,getFileName()
,getLineNumber()
egetMethodName()
.Você precisará experimentar para determinar qual índice deseja (provavelmente
stackTraceElements[1]
ou[2]
).fonte
Uma solução alternativa pode ser encontrada em um comentário a esta solicitação de aprimoramento . Ele usa o
getClassContext()
método de um costumeSecurityManager
e parece ser mais rápido que o método de rastreamento de pilha.O programa a seguir testa a velocidade dos diferentes métodos sugeridos (o bit mais interessante está na classe interna
SecurityManagerMethod
):Um exemplo da saída do meu MacBook Intel Core 2 Duo de 2,4 GHz executando Java 1.6.0_17:
O método interno de reflexão é muito mais rápido que os outros. Obter um rastreamento de pilha de um recém-criado
Throwable
é mais rápido do que obtê-lo do atualThread
. E entre as formas não internas de encontrar a classe de quem chama, o costumeSecurityManager
parece ser o mais rápido.Atualizar
Como lyomi aponta neste comentário, o
sun.reflect.Reflection.getCallerClass()
método foi desativado por padrão na atualização 40 do Java 7 e removido completamente no Java 8. Leia mais sobre isso nesta edição no banco de dados de erros do Java .Atualização 2
Como o zammbi descobriu, a Oracle foi forçada a desistir da mudança que removeu o
sun.reflect.Reflection.getCallerClass()
. Ele ainda está disponível no Java 8 (mas está obsoleto).Atualização 3
3 anos depois: Atualização sobre o tempo com a JVM atual.
fonte
Parece que você está tentando evitar passar uma referência para
this
o método. Passarthis
é muito melhor do que encontrar o chamador através do rastreamento de pilha atual. Refatorar para um design mais OO é ainda melhor. Você não precisa conhecer o chamador. Passe um objeto de retorno de chamada, se necessário.fonte
LoggerFactory.getLogger(MyClass.class)
qual eu não precisei passar na classe literal. Ainda raramente é a coisa certa a fazer.INotifyPropertyChanged
interface .NET . Embora este exemplo específico não esteja em Java, o mesmo problema pode se manifestar ao tentar modelar campos / getters como seqüências de caracteres para o Reflection.Java 9 - JEP 259: API Stack-Walking
O JEP 259 fornece uma API padrão eficiente para movimentação de pilha que permite filtragem fácil e acesso lento às informações nos rastreamentos de pilha. Antes da API Stack-Walking, formas comuns de acessar quadros de pilha eram:
O uso dessas APIs geralmente é ineficiente:
Para encontrar a classe do chamador imediato, primeiro obtenha um
StackWalker
:Em seguida, ligue para
getCallerClass()
:ou
walk
osStackFrame
e obtenha o primeiro precedenteStackFrame
:fonte
Oneliner :
Observe que pode ser necessário substituir o 2 por 1.
fonte
Esse método faz a mesma coisa, mas um pouco mais simples e possivelmente um pouco mais eficiente e, no caso de você estar usando reflexão, ele pula esses quadros automaticamente. O único problema é que ele pode não estar presente em JVMs que não são da Sun, embora esteja incluído nas classes de tempo de execução do JRockit 1.4 -> 1.6. (O ponto é que não é uma classe pública ).
Quanto ao
realFramesToSkip
valor, nas versões Sun 1.5 e 1.6 VM dejava.lang.System
, existe um método protegido por pacote chamado getCallerClass () que chamasun.reflect.Reflection.getCallerClass(3)
, mas, na minha classe de utilitário auxiliar, usei 4, pois há o quadro adicional da classe auxiliar invocação.fonte
Por exemplo, se você tentar obter a linha do método de chamada para fins de depuração, precisará passar pela classe Utility na qual codifica esses métodos estáticos:
(código java1.4 antigo, apenas para ilustrar um uso potencial de StackTraceElement)
fonte
Eu já fiz isso antes. Você pode simplesmente criar uma nova exceção e pegar o rastreamento de pilha sem lançá-lo e, em seguida, examinar o rastreamento de pilha. Como a outra resposta diz, é extremamente caro - não faça isso em um loop apertado.
Eu já fiz isso antes para um utilitário de registro em um aplicativo em que o desempenho não importava muito (o desempenho raramente importa muito, na verdade - desde que você mostre o resultado de uma ação como clicar rapidamente em um botão).
Foi antes que você pudesse obter o rastreamento de pilha, as exceções tinham apenas .printStackTrace (), então eu tive que redirecionar System.out para um fluxo de minha própria criação, depois (new Exception ()). PrintStackTrace (); Redirecione System.out para trás e analise o fluxo. Coisas divertidas.
fonte
fonte
Aqui está uma parte do código que eu criei com base nas dicas mostradas neste tópico. Espero que ajude.
(Sinta-se à vontade para fazer sugestões para melhorar esse código, informe-me)
O contador:
E o objeto:
fonte
OU
fonte
use este método: -
Exemplo de chamada do método Code is here: -
fonte