Necesito encontrar la persona que llama de un método. ¿Es posible usar stacktrace o reflexión?
java
stack-trace
Sathish
fuente
fuente
DontNameYourMethodFooException
si el método de llamada se llama foo.Respuestas:
De acuerdo con los Javadocs:
Una
StackTraceElement
tienegetClassName()
,getFileName()
,getLineNumber()
ygetMethodName()
.Tendrá que experimentar para determinar qué índice desea (probablemente
stackTraceElements[1]
o[2]
).fuente
Se puede encontrar una solución alternativa en un comentario a esta solicitud de mejora . Utiliza el
getClassContext()
método personalizadoSecurityManager
y parece ser más rápido que el método de seguimiento de la pila.El siguiente programa prueba la velocidad de los diferentes métodos sugeridos (el bit más interesante está en la clase interna
SecurityManagerMethod
):Un ejemplo de la salida de mi MacBook Intel Core 2 Duo de 2.4 GHz con Java 1.6.0_17:
El método interno de reflexión es mucho más rápido que los demás. Obtener un seguimiento de pila de un recién creado
Throwable
es más rápido que obtenerlo de la actualThread
. Y entre las formas no internas de encontrar la clase de llamada, la costumbreSecurityManager
parece ser la más rápida.Actualizar
Como Lyomi señala en este comentario, el
sun.reflect.Reflection.getCallerClass()
método se ha deshabilitado de forma predeterminada en la actualización 40 de Java 7 y se eliminó por completo en Java 8. Lea más sobre esto en este tema en la base de datos de errores de Java .Actualización 2
Como descubrió zammbi , Oracle se vio obligado a retirarse del cambio que eliminó el
sun.reflect.Reflection.getCallerClass()
. Todavía está disponible en Java 8 (pero está en desuso).Actualización 3
3 años después: Actualización sobre el tiempo con JVM actual.
fuente
Parece que estás tratando de evitar pasar una referencia al
this
método. Pasarthis
es mucho mejor que encontrar a la persona que llama a través del seguimiento de la pila actual. Refactorizar a un diseño más OO es aún mejor. No deberías necesitar conocer a la persona que llama. Pase un objeto de devolución de llamada si es necesario.fuente
LoggerFactory.getLogger(MyClass.class)
donde no tuve que pasar el literal de la clase. Rara vez es lo correcto.INotifyPropertyChanged
interfaz .NET . Si bien este ejemplo específico no está en Java, el mismo problema puede manifestarse cuando se intenta modelar campos / captadores como cadenas para Reflection.Java 9 - JEP 259: API para caminar sobre la pila
JEP 259 proporciona una API estándar eficiente para el recorrido de la pila que permite un filtrado fácil y un acceso lento a la información en los seguimientos de la pila. Antes de Stack-Walking API, las formas comunes de acceder a los marcos de pila eran:
El uso de estas API suele ser ineficiente:
Para encontrar la clase de la persona que llama inmediatamente, primero obtenga un
StackWalker
:Luego, llame al
getCallerClass()
:o
walk
elStackFrame
sy obtener el primer precedenteStackFrame
:fuente
Oneliner :
Tenga en cuenta que es posible que deba reemplazar el 2 con 1.
fuente
Este método hace lo mismo, pero un poco más simple y posiblemente un poco más eficaz y, en caso de que esté utilizando la reflexión, omite esos cuadros automáticamente. El único problema es que puede no estar presente en JVM que no sean Sun, aunque está incluido en las clases de tiempo de ejecución de JRockit 1.4 -> 1.6. (El punto es que no es una clase pública ).
En cuanto a cuál
realFramesToSkip
debería ser el valor, las versiones de VM de Sun 1.5 y 1.6java.lang.System
, hay un método de paquete protegido llamado getCallerClass () que llamasun.reflect.Reflection.getCallerClass(3)
, pero en mi clase de utilidad auxiliar utilicé 4 ya que existe el marco agregado de la clase auxiliar invocación.fuente
Por ejemplo, si intenta obtener la línea del método de llamada para fines de depuración, debe pasar la clase de utilidad en la que codifica esos métodos estáticos:
(antiguo código java1.4, solo para ilustrar un posible uso de StackTraceElement)
fuente
He hecho esto antes. Puede crear una nueva excepción y tomar el seguimiento de la pila sin lanzarla, luego examinar el seguimiento de la pila. Sin embargo, como dice la otra respuesta, es extremadamente costoso, no lo hagas en un círculo cerrado.
Lo he hecho antes para una utilidad de registro en una aplicación donde el rendimiento no importaba mucho (el rendimiento rara vez importa mucho, en realidad, siempre que muestre el resultado de una acción, como hacer clic rápidamente en un botón).
Antes de que pudiera obtener el seguimiento de la pila, las excepciones solo tenían .printStackTrace (), así que tuve que redirigir System.out a una secuencia de mi propia creación, luego (nueva Excepción ()). PrintStackTrace (); Redirigir System.out hacia atrás y analizar la secuencia. Cosas divertidas.
fuente
fuente
Aquí hay una parte del código que hice en base a las sugerencias que se muestran en este tema. Espero eso ayude.
(No dude en hacer sugerencias para mejorar este código, por favor dígame)
El contador:
Y el objeto:
fuente
O
fuente
use este método:
El que llama del ejemplo de método Code está aquí: -
fuente