Entre los nuevos dispositivos introducidos en la versión 5.0 de
la plataforma Java 2 se encuentran una API que permite a las
aplicaciones Java y a las herramientas compatibles supervisar y
administrar una Java Virtual Machine (JVM) y el sistema
operativo nativo en el que se ejecuta. En este artículo, usted
aprenderá sobre las posibilidades de esta nueva plataforma de
gestión API, incluida en el paquete
java.lang.management . Este artículo
le lleva rápidamente a un nuevo conjunto de dispositivos de gran
alcance que serán más importante en futuros releases de la
plataforma Java.
La supervisión y gestión de una VM 5.0
Java 5.0 proporciona nuevas posibilidades para administrar y ejecutar una máquina virtual. Los desarrolladores y los administradores del sistema pueden supervisar - y, para algunas propiedades, ajustar con precisión - el rendimiento de una VM 5.0. El mecanismo para realizar estas actividades será conocido para cualquiera que tenga experiencia previa en el uso de Java Management Extensions (JMX). A través de la tecnología JMX, un conjunto de recursos de la plataforma a controlar pueden ser considerados como simples objetos bien definidos, cuyas propiedades se correlacionan con las características de bajo nivel de los recursos dados.
En la API de administración de la plataforma, estos objetos bien definidos se llaman MXBeans. Si usted piensa que un MXBean suena como un tipo del posiblemente más conocido MBean, entonces está en lo correcto. Estos MXBeans (o plataforma MBeans) son, en efecto, beans de gestión que encapsulan partes específicas del funcionamiento interno de la plataforma 5.0. La Figura 1 ilustra cómo los MXBeans encajan en la imagen más grande:
Figura 1. los MXBeans proporcionan interfaces de gestión para la plataforma Java
Usted puede descubrir y personalizar diferentes clases de funcionalidad en la ejecución de una VM 5.0 compatible, por ejemplo, puede obtener los detalles sobre el comportamiento del sistema de compilación just-in-time que puede estar en uso u obtener cifras del progreso del servicio de recogida de basura.
Cualquier aplicación Java puede hacer uso de los beans de la plataforma, simplemente obteniendo la referencia bean necesaria, (utilizando las técnicas que analizaremos en este artículo) y a continuación invocando la llamada del método apropiado. En el caso más simple, el cliente de bean puede descubrir información sobre la plataforma que el propio cliente está ejecutando. Pero un cliente también puede controlar el comportamiento de una completamente separada JVM. Esto es posible porque un MXBean es una clase de MBean y se puede gestionar de forma remota utilizando los servicios estándar JMX disponibles en Java 5.0.
Un ejemplo de un cliente bean es la herramienta JConsole que se suministra con Java SE 5.0 SDK. Esta es una interfaz gráfica que se conecta a una JVM para mostrar información sobre la misma. Las pestañas en la GUI se relacionan a aspectos particulares de la JVM, existen pestañas de memoria, hebras y clases. La herramienta JConsole también proporciona una pestaña de resumen general, una pestaña VM que proporciona información sobre el entorno en el que se inició la VM, y una pestaña MBeans con la que el usuario puede inspeccionar el estado de la plataforma MBeans con más detalle.
se puede iniciar JConsole simplemente escribiendo
jconsole. en un prompt de comando,
asumiendo que el directorio bin del SDK está en su vía de
acceso. Introduzca el nombre de host donde la JVM que
desea supervisar se está ejecutando junto con el número de
puerto en el cual se escuchan las solicitudes de
gestión -- junto con los detalles de autenticación necesarios --
y entonces haga clic en Connect. Al hacer clic
enConnect con los valores predeterminados
dellocalhost y port
0 , se supervisa la JVM que está
siendo utilizada para ejecutar la propia JConsole (ya que
JConsole es un proceso Java). Esto se conoce como modalidad
de auto-control. La Figura 2 ilustra el inicio de
JConsole:
Figura 2. Inicio de JConsole
Una vez se ha establecido una conexión a una JVM, JConsole se inicia mediante la pestaña Resumen, como se muestra en la Figura 3:
Figura 3. Pestaña Resumen de JConsole
Desde aquí, usted puede seleccionar cualquiera otra pestaña. Por ejemplo, la pestaña Memoria, que se ilustra en la Figura 4, muestra un historial del uso de cada agrupación de memoria en la JVM:
Figura 4. Pestaña Memoria de JConsole
Observe el botón Perform GC en la esquina superior derecha del panel. Este es un ejemplo de una de las muchas operaciones que se pueden invocar en la JVM utilizando la plataforma MBeans.
Apoyando todo lo que ha leído hasta ahora está el concepto de un bean gestionado, o MBean. Se puede pensar en los MBeans como la representación programática de la interfaz de gestión de un recurso. En términos más sencillos, se puede pensar en ellos como derivadores de Java alrededor de una entidad a controlar. En términos más prácticos aún, los MBeans son las clases de Java, cuyos métodos públicos son escrito de acuerdo a un conjunto de reglas bien definidas, estas reglas hacen cumplir la encapsulación completa de las características de una aplicación o un recurso a administrar. En última instancia, el gestor del recurso (donde quiera que esté y donde quiera que habite en la red) localiza y utiliza el MBean correspondiente para fines de control.
A través de su API, un MBean proporciona información sobre lo siguiente, todos lo que se ilustra en la figura 5:
- El estado actual del recurso, a través de sus propiedades de
- Operations que pueden invocarse a través de las notificaciones de evento
- posibles a los agentes de gestión que pueden ser enviadas a las partes interesada.
Figura 5. Los clientes MBean hacen uso de las propiedades, operaciones, y eventos.
Una vez que se crea, tiene que registrar un MBean con un servidor MBean. Además de jugar el rol de un registro de MBean, el servidor MBean también proporciona una manera de que los sistemas de gestión encuentren y utilicen los MBeans registrados. La funcionalidad adicional para la gestión de MBeans registrados es llevada a cabo por los servicios de agente JMX . Tales servicios incluyen la supervisión de los valores de los atributos de un MBean y la notificación a las partes interesadas sobre los cambios que se realizan, la notificación a los receptores periódicamente con información específica sobre un MBean, y la vigilancia de las relaciones entre MBeans. Los servicios de agente JMX son a menudo los propios MBeans.
La combinación de un servidor de MBean con los servicios de agente JMX obligatorios se conoce como un agente JMX, el cual se muestra en la Figura 6:
Figura 6. El agente JMX.
Un agente JMX puede hacer que se gestionen sus recursos - es decir, el conjunto de MBeans actualmente registrados en su servidor MBean --- disponible para otros agentes remotos.
Antes que el release Java 5.0, la API
javax.management era una extensión
opcional de la plataforma Java que los usuarios podían obtener
en una descarga por separado y poner en marcha como medio de
gestión y supervisión de los recursos a través de código Java.
Los Recursos en este contexto, pueden significar
aplicaciones, servidores J2EE que ejecutan aplicaciones críticas
de empresa, objetos Plain Old Java (POJO), e incluso entidades
de hardware, como dispositivos de red, descodificadores, equipos
de telecomunicaciones, o similares.Si se puede hacer referencia
a partir del código Java, entonces puede convertirse
potencialmente en un recurso administrado.
A pesar de que en realidad aquí sólo hemos arañado la superficie de JMX, hemos cubierto lo suficiente para permitirnos echar un vistazo a los MXBeans. Un completo análisis del diseño y las posibilidades de JMX está fuera del alcance de este artículo. Para una excelente visión general de la parte que juega JMX en las aplicaciones de gestión de red, se pueden leer las series de Sing Li sobre el tema (ver Recursos).
¿Qué son los MXBeans y cómo puedo utilizarlos?
Así que ahora que sabe lo que son los MBeans, echemos un vistazo
a sus homónimos cercanos como se define en el paquete
java.lang.management , MXBeans. La
buena noticia es que los MXBeans no se apartan de los conceptos
que introducimos cuando los analizamos. La mayoría de tipos en
este paquete son interfaces que siguen un convenio de
denominación similar los que se utilizan para los MBeans
estándar: el nombre del recurso de la plataforma que se
instrumenta seguida por el sufijo
MXBean. (Para los MBeans estándar el
sufijo MBean se esperará, por
supuesto.)
La Tabla 1 describe los recursos de la plataforma que están
disponibles para la instrumentación a través de las interfaces
MXBean proporcionadas en el paquete
java.lang.management :
Tabla 1. Recursos de la plataforma que se pueden administrar a través de MXBeans
| Recurso de la plataforma | Correspondiente a MXBean | Número disponible |
|---|---|---|
| Compilación | CompilationMXBean | 0 o 1 |
| Sistema de recogida de basuras | GarbageCollectorMXBean | Al menos 1 |
| Memoria | MemoryMXBean | Exactamente 1 |
| Gestores de memoria | MemoryManagerMXBean | Al menos 1 |
| Enhebrado | ThreadMXBean | Exactamente 1 |
| Sistema operativo | OperatingSystemMXBean | Exactamente 1 |
| Sistemas de tiempo de ejecución | RuntimeMXBean | Exactamente 1 |
| Sistema de carga de clase | ClassLoadingMXBean | Exactamente 1 |
| Recursos de memoria | MemoryPoolMXBean | Al menos 1 |
Para cada MXBean, la interfaz que los clientes deben programar está firmemente establecida en la especificación de Java 5.0. En la actualidad no hay manera de que los usuarios pueden personalizar una interfaz como la que se expone en los atributos más manejables de la plataforma.
El número de posibles instancias de cada tipo de MXBean, se
indica en la tercera columna de la Tabla 1, depende en gran
medida el sistema de plataforma en particular que se administra.
Por ejemplo, como la especificación JVM permite a los
implementadores elegir los algoritmos de recogida de basura
utilizados, es totalmente razonable para cualquier número de
recopiladores de basura - y por lo tanto, cualquier número de
instancias de GarbageCollectionMXBean
-- que se activen simultáneamente. Contrasta con el
OperatingSystemMXBean, del cual sólo
puede haber una instancia disponible, como la máquina virtual
instrumentada, obviamente sólo se puede ejecutar en un sistema
operativo en un momento dado.
El código de cliente puede asumir con seguridad que los excepcionales MXBeans son verdaderamente únicos en la VM. Cada vez que se solicita una referencia a estos excepcionales tipos, siempre se responde con la misma instancia, independientemente de donde se hace la solicitud y cuando se produce en el ciclo de vida de la VM. Esto es cierto incluso cuando varios clientes están controlando una VM en particular.
Para un código de cliente Java, una instancia MXBean se comporta
como cualquier POJO. La información se puede adquirir a través
de una llamada directa al objeto sin la necesidad de ningún otro
participante. Por supuesto, esto sólo es el caso siempre y
cuando el cliente Java haya obtenido una referencia a un bean
local (que se ejecuta en la misma VM como en la aplicación de
gestión) directamente o bien haya solicitado un proxy a un
componente de encapsulación de un bean de una VM remota. En
ambos casos, la referencia se obtiene de la única plataforma
ManagementFactory..
Además de puede acceder a un bean de la plataforma a través de
javax.management.MBeanServerConnection,
pero en tal caso, hay un nivel extra de indirección en la
conversación. Como puede ver en Supervisión de una
VM remota a través del servidor de la plataforma, en ese
caso de ejemplo los clientes siempre realizan una solicitud a
MBeanServerConnection para localizar
y realizar llamadas en su nombre a los beans remotos
especificados. Esto está en consonancia con el análisis de JMX
proporcionado con anterioridad, en el que se observa que para
emitir llamadas en cualquier MBean remoto, los clientes remotos
debe comunicarse con el servidor MBean en el que está registrado
el MBean.
Para evitar cualquier confusión, usted debe recordar que si bien es perfectamente correcto pensar en un MXBean como una especie de MBean que ayuda a supervisar y controlar una JVM, sin duda, no es correcto pensar en un MXBean como un tipo de JavaBean. La tecnología JavaBeans es el modelo de componentes para la plataforma Java que fue diseñado para ofrecer la capacidad de construir aplicaciones a partir de componentes reutilizables Java utilizando herramientas gráficas. Mientras que algunos de los dispositivos de JavaBeans, como los importantes convenios de denominación para ayudar a descubrir las propiedades a través de las herramientas, están presentes en el espacio de MBean y MXBean, hay una gran diferencia entre las dos tecnologías. No las confunda.
Al comienzo de este artículo, mencionamos que el paquete
java.lang.management aloja la API de
gestión de la plataforma.Bien, aquí tenemos que corregir esa
sentencia ligeramente porque no todos los MXBeans están en
realidad contenidos en ese paquete. Debido a que el
LoggingMXBean está tan
intrínsecamente ligado a la funcionalidad de registro
cronológico de la plataforma Java, tenía más sentido alojarlo en
el paquete java.util.logging . Como
era de esperar de su nombre, este tipo de MXBean proporciona una
interfaz de gestión para ejecutar un recurso de registro
cronológico de la VM. A partir de una referencia a este bean,
los clientes pueden obtener los nombres de todos los
registradores que han sido grabados en la plataforma y sus
relaciones con los demás. También está disponible la posibilidad
de obtener y establecer el nivel de un registrador de la
plataforma denominada.
Como el OperatingSystemMXBean y el
ThreadMXBean (por mencionar otros dos
ejemplos), el LoggingMXBean existe
como único en la VM que se está ejecutando. Cualquier obtención
o establecimiento en las propiedades expuestas, a través de
cualquier medio de comunicación, son siempre enviadas a la misma
instancia del objeto.
Existen tres formas para que el código del cliente acceda a los MXBeans: a través de los métodos de fábrica, a través del servidor de la plataforma, o como proxies.
La forma más sencilla de recuperar los MXBeans es utilizar los
métodos estáticos proporcionados en la clase
java.lang.management.ManagementFactory
. Sin embargo, los MXBeans obtenidos de esta manera sólo se
puede utilizar para supervisar su VM local. La
claseManagementFactory define un
método de recuperación de MXBean. Algunos de estos métodos
devuelven una sola instancia del MXBean, y otros devuelven una
lista más estricta de las instancias
de MXBean.
Cuando sólo hay un MXBean de un tipo específico, el código para
recuperarlo es simple. El Listado 1 muestra el código para
recuperar el ThreadMXBean.:
Listado 1. Recuperar una referencia del ThreadMXBean único de la plataforma
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); |
Para aquellos tipos de MXBean donde puedan existir varias
instancias del MXBean, hay métodos de fábrica que devuelven el
MXBeans en una Lista, como se muestra
en el Listado 2:
Listado 2. Recuperación de una lista más estricta de todos MemoryPoolMXBeans conocidos en la plataforma
List<MemoryPoolMXBean> memPoolBeans = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean mpb : memPoolBeans) {
System.out.println("Memory Pool: " + mpb.getName());
}
|
El LoggingMXBean es un componente del
paquete java.util.logging y como
resultado, se accede a él mediante la
claseLogManager, en lugar de la clase
ManagementFactory , como aparece en
el Listado 3:
Listado 3. Obtención de la referencia LoggingMXBean desde el LogManager
LoggingMXBean logBean = LogManager.getLoggingMXBean(); |
Recuerde, estos métodos sólo le permiten acceder a los MXBeans que pertenecen a su VM local . Si desea ampliar el alcance de su código de cliente a distancia para instrumentar las JVM remotas ubicadas en la misma máquina o en los diferentes nodos en total, entonces tiene que utilizar uno de los dos métodos que se describen a continuación.
A través del servidor de la plataforma.
Estructurar el código para realizar llamadas en una conexión a un servidor MBean de VM remoto es, una opción disponible para usted. Para que esto tenga éxito, primero tendrá que lanzar la VM remota con clave de opciones de línea de comandos. Estas establecen el puerto en el que su agente JMX asociado escucha las solicitudes y el nivel de seguridad que estará en vigor. Por ejemplo, las siguientes opciones inician una VM, cuyo agente escucha en el puerto 1234 sin seguridad:
-Dcom.sun.management.jmxremote.port=1234 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false |
El permitir un acceso seguro a una VM se cubre posteriormente en este artículo en la sección de Seguridad .
Con el agente remoto escuchando, se puede usar el fragmento de código en el Listado 4 para obtener una referencia de la conexión del servidor MBean asociada:
Listado 4. Uso de JMXConnectorFactory para conectar a un servidor MBean de una VM diferente
pruebe {
// connect to a separate VM's MBeanServer, using the JMX RMI functionality
JMXServiceURL address =
new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:1234/jmxrmi");
JMXConnector connector = JMXConnectorFactory.connect(address);
MBeanServerConnection mbs = connector.getMBeanServerConnection();
} catch ...
|
Una vez que ha recuperado el
MBeanServerConnection, usted puede
utilizar los métodos JMX
getAttribute(),
setAttribute() y
invoke() para trabajar con los
MXBeans. Esto se cubre en Supervisión de una VM
remota a través del servidor de la plataforma..
El tercer enfoque para acceder a las API beans de la plataforma
comparte algunas similitudes con los dos métodos ya
introducidos. Al igual que antes, usted tiene que recuperar
MBeanServerConnection del agente JMX
de la VM de desea supervisar. A continuación, utilizando el
método ayudante estático en la clase
ManagementFactory , el código del
cliente puede solicitar una instancia de proxy a un MXBean
denominado registrado en el servidor MBean de la VM remota. El
Listado 5 ilustra un ejemplo:
Listado 5. Una referencia a un servidor MBean remoto puede obtener proxies para un MXBeans remoto.
pruebe {
ThreadMXBean threadBean = ManagementFactory.newPlatformMXBeanProxy
(mbs, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
} catch ...
|
Para todos los MXBeans únicos excepto el
LoggingMXBean, los nombres de cadena
de caracteres completa que se utilizan para el registro de
servidor están disponibles en los campos estáticos públicos de
la clase ManagementFactory . Así por
ejemplo, la representación de la cadena de caracteres del
javax.management.ObjectName
deThreadMXBean se almacena en el
campo THREAD_MXBEAN_NAME . De igual
manera, el nombre de registro de
LoggingMXBean se almacena en un campo
estático en la clase
java.util.logging.LogManager . El
Listado 6 demuestra una solicitud de una instancia proxy para
LoggingMXBean:
Listado 6. El nombre de la cadena de caracteres de LoggingMXBean es una constante de la clase java.util.logging.LogManager
pruebe {
LoggingMXBean logBean = ManagementFactory.newPlatformMXBeanProxy
(mbs, LogManager.LOGGING_MXBEAN_NAME, LoggingMXBean.class);
} catch ...
|
Con los tipos de MXBean donde más una instancia puede existir en
la VM, las cosas se vuelven un poco más participativas. En tales
casos, primero debe utilizar el
MBeanServerConnection para obtener
los nombres de todos los MXBeans registrados de un determinado
tipo. Por comodidad, el componente de dominio de
ObjectName para cada MXBean no único
se almacena en los campos estáticos públicos en
ManagementFactory.. Una vez que se
recuperan los nombres, se pueden utilizar uno por uno para la
construcción de una instancia proxy por separado. El Listado 7
muestra un ejemplo:
Listado 7. Creación de proxies para cada MemoryManagerMXBean que pertenecen a una VM remota
try {
// Get the names of all the Memory Manager MXBeans in the server
Set srvMemMgrNames = mbs.queryNames(new ObjectName(
ManagementFactory.MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE + ",*"), null);
// Get a MXBean Proxy for each name returned
for (Object memMgrName : srvMemMgrNames){
// Cast Object to an ObjectName
ObjectName memMgr = (ObjectName) memMgrName;
// Call newPlatformMXBeanProxy with the complete object name
// for the specific MXBean
MemoryManagerMXBean memMgrBean =
ManagementFactory.newPlatformMXBeanProxy(
mbs, memMgr.toString(), MemoryManagerMXBean.class);
// memMgrBean is a proxy to the remote MXBean. We can use it
// just as if it was a reference to a local MXBean.
System.out.println("Memory Manager Name = " +
memMgrBean.getName());
}
} catch ...
|
Las operaciones definidas a través de cada intefaz de MXBean se
indican en la documentación
java.lang.management . A través de
estas operaciones, el usuario puede gestionar y supervisar la
máquina virtual. Por ejemplo, en
MemoryMXBean, existen operaciones que
le permiten activar una salida detallada de la memoria del
sistema, solicitar la recogida de basura, y recuperar
información detallada sobre el uso de la memoria actual por las
agrupaciones de memoria con y sin almacenamiento dinámico. Por
lo tanto, si estaba preocupado por la cantidad de memoria que
estaba utilizando una aplicación Java o desea ajustar el tamaño
del almacenamiento dinámico, podría escribir fácilmente un
cliente de administración utilizando la API
java.lang.management para conectar
con la aplicación y controlar el uso de la memoria.
De igual manera, ThreadMXBean ofrece
una funcionalidad que podría ser útil si la aplicación Java se
cuelga. El método
findMonitorDeadlockedThreads()
devuelve los ID de cualquier hebra que se identifica como un
punto muerto. Entonces, se pueden utilizar estos ID para
recuperar información detallada sobre las hebras, incluyendo el
rastreo de pila, sus estados, si estaban ejecutando un código
nativo, y así sucesivamente.
Esta información de hebra se suministra en una instancia de
ThreadInfo , una de las tres clases
en el paquete java.lang management
utilizado por MXBeans para devolver instantáneas de los datos a
un usuario -- las otras son las clases
MemoryUsage y
MemoryNotificationInfo . Cada una de
estos es un tipo de datos complejos que contiene
información estructurada que describe las cualidades específicas
de la plataforma.
Ahora echemos un vistazo a dos casos de ejemplo que ilustran cómo las ideas que se comentan anteriormente se traducen en el código Java.
Ejemplo 1: Control de una VM a través de MXBeans o proxies.
Como hemos comentado, los métodos de un MXBean se pueden llamar
directamente desde un MXBean local o bien a través de un proxy.
El Listado 8 muestra cómo utilizar las operaciones método getter
y método setterThreadMXBean. La
variable threadBean en este ejemplo
puede ser un MXBean recuperado de la VM local o un proxy para el
MXBean desde una VM remota. Es transparente al interlocutor una
vez que se ha adquirido la referencia.
Listado 8. Obtener y establecer los valores de un ThreadMXBean
try {
// Get the current thread count for the JVM
int threadCount = threadBean.getThreadCount();
System.out.println(" Thread Count = " + threadCount);
// enable the thread CPU time
threadBean.setThreadCpuTimeEnabled(true);
} catch ...
|
El método setThreadCpuTimeEnabled(),
que se utiliza en el Listado 8 es opcionalmente soportado por
las VM5.0 compatible. La verificación requerida cuando se
utiliza tal funcionalidad opcional se muestra en el Listado
9:
Listado 9. Verificación de que esa propiedad opcional es compatible antes que intentar utilizarla
si (threadBean.isThreadCpuTimeSupported()) {
threadBean.setThreadCpuTimeEnabled(true);
}
|
El método getTotalCompilationTime()
del tipo CompilationMXBean, también
contiene una funcionalidad que no estará disponible
necesariamente en todas las implementaciones de VM
5.0-compatible. Como con
setThreadCpuTimeEnabled(), en el
listado 9, hay un método asociado disponible para comprobar si
existe soporte. El código que no se aprovecha de estos métodos
de verificación tiene que manejar cualquier
java.lang.UnsupportedOperationException
que pueda ser lanzada a través de métodos opcionales.
El Listado 10 demuestra cómo acceder a información sobre todas
las hebras que se ejecutan en la VM. Cada información de hebra
se almacena en un objeto ThreadInfo
separado dedicado, el cual se puede consultar
posteriormente.
Listado 10. Obtención de los nombres de todas las hebras que se ejecutan en una VM
try {
// Get the ids of all the existing threads
long[] threadIDs = threadBean.getAllThreadIds();
// Get the ThreadInfo object for each threadID
ThreadInfo[] threadDataset = threadBean.getThreadInfo(threadIDs);
for (ThreadInfo threadData : threadDataset) {
if (threadData != null) {
System.out.println(threadData.getThreadName());
}
}
} catch ...
|
Tenga en cuenta que la información contenida en los tipos
complejos como ThreadInfo,
MemoryUsage y
MemoryNotificationInfo es meramente
una instantánea del sistema en el momento en que se realizó la
llamada de adquisición. Estos objetos no se actualizan
dinámicamente después de que usted obtenga una referencia de
ellos, así que, si la aplicación necesita datos frescos
en uno de estos aspectos de la VM administrada, es necesario
realizar otra llamada para obtener un
ThreadInfo actualizado u objeto
MemoryUsage .
Los objetos MemoryNotificationInfo
son un poco diferentes en este respecto, ya que no son extraídos
por las aplicaciones de gestión, sino que más bien son empujados
a los eventos de notificación (que analizaremos en
más detalle próximamente).
Ejemplo 2: Supervisión de una VM remota a través de la plataforma del servidor.
El acceso al ThreadMXBean de una JVM
remota por medio de un
MBeanServerConnection no es tan
sencillo como el ejemplo que aparece en el Listado 1. En primer
lugar, usted necesitará una instancia
javax.management.ObjectName para el
ThreadMXBean.. Esto se puede crear
con la misma cadena de caracteres de nombres que un objeto proxy
MXBean, como se muestra en el Listado 11:
Listado 11. Construcción de un ObjectName para un ThreadMXBean
try {
ObjectName srvThrdName = new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME);
...
} catch ...
|
Se puede utilizar la instancia
ObjectName para identificar el
ThreadMXBean específico remoto en
posteriores llamadas a los métodos
getAttribute(),
setAttribute() y
invoke() del MBeanServerConnection,
como aparece en el Listado 12:
Listado 12. Poner el ObjectName en buen uso en las llamadas al servidor MBean remoto
try {
// Get the current thread count for the JVM
int threadCount =
((Integer)mbs.getAttribute( srvThrdName, "ThreadCount")).intValue();
System.out.println(" Thread Count = " + threadCount);
boolean supported =
((Boolean)mbs.getAttribute(srvThrdName, "ThreadCpuTimeSupported")).booleanValue();
if (supported) {
mbs.setAttribute(srvThrdName,
new Attribute("ThreadCpuTimeEnabled", Boolean.TRUE));
...
}
} catch ...
|
El Listado 13 demuestra cómo acceder a la información sobre todas
la hebras actuales en la VM a través de la conexión al servidor
de MBean. MXBeans accede utilizando este enfoque a los tipos de
datos complejos de devolución, recortando el tipo complejo
dentro de un tipo abierto de JMX, como un objeto
javax.management.openmbean.CompositeData
.
¿Por qué están los datos complejos recortados dentro de un tipo
intermedio? Tenga en cuenta que MXBeans podrían ser
potencialmente administrados por las aplicaciones remotas que no
estén realmente escritas en lenguaje Java o por aplicaciones
Java sin acceso a todos los tipos complejos utilizados para
describir diversas cualidades de los recursos gestionados. Si
bien es seguro asumir que ambos extremos de la conexión al
agente JMX de la plataforma, comprenderá los tipos sencillos,
como boolean,
long, y
string , y los correlacionará a los
tipos correspondientes en su lenguaje de implementación
respectivo, no es realista asumir que los tipos complejos, tales
como ThreadInfo o
MemoryUsage serán interpretados
correctamente por cada aplicación de gestión posible.Tipos
abiertos comoCompositeData pueden
representar datos complejos (es decir, no primitivos o
estructurado) en cuanto a los tipos más fundamentales.
Si usted realiza una llamada remota a un MXBean 5.0 que requiere
pasar una instancia de un tipo complejo, el objeto se convierte
en el equivalente de CompositeData .
Mientras esto activa el envío de información a la gama más
amplia de clientes posible, hay un inconveniente: La recepción
de aplicaciones Java que realmente pueden resolver los
tiposThreadInfo
yMemoryUsage seguirán no obstante
necesitando convertirse del tipo abierto al tipo complejo por
ellos mismos. Pero incluso eso no es demasiado oneroso a un
paso, como todos los tipos de datos complejos de soporte
definidos en java.lang.management
tienen sus propios métodos de conveniencia estática para hacer
esto.
En el Listado 13, el atributo
threadDataset contiene una matriz de
objetosCompositeData que se
correlacionan directamente a los objetos
ThreadInfo . Para cada hebra, el
método estático de ThreadInfo
from() se utiliza entonces para la
construcción de un objeto ThreadInfo
equivalente del CompositeData.. Se
puede utilizar este objeto para acceder a la información de cada
hebra.
Listado 13. El tipo CompositeData transfiere complejas estructuras de datos por la red
try {
// Get the ids of all the existing threads
long[] threadIDs = (long[])mbs.getAttribute(srvThrdName, "AllThreadIds");
// Get the ThreadInfo object for each threadID. To do this we need to
// invoke the getThreadInfo method on the remote thread bean. To do
// that we need to pass the name of the method to run together with the
// argument and the argument type. It's pretty ugly we know.
CompositeData[] threadDataset =
(CompositeData[]) (mbs.invoke(srvThrdName, "getThreadInfo",
new Object[]{threadIDs}, new String[] {"[J"}));
// Recover the ThreadInfo object from each received CompositeData using
// the static helper from() method and then use it to print out the
// thread name.
for (CompositeData threadCD : threadDataset) {
ThreadInfo threadData = ThreadInfo.from(threadCD);
if (threadData != null) {
System.out.println(threadData.getThreadName());
}
}
} catch ...
|
Si usted desarrolla un código de gestión de la plataforma que verifica el estado de las hebras VM, entonces puede que encuentre interesantes algunos comportamientos con los que nos topamos por casualidad mientras realizábamos este artículo.¿Afectará a su código? Eso depende de en qué medida la aplicación utiliza la versión 5.0 del nuevo mecanismo de la plataforma Java para proteger los bloques de código a un acceso simultaneo.
El nuevo paquete 5.0
java.util.concurrent.locks introduce
la claseReentrantLock que, como su
nombre sugiere, se puede utilizar para construir un bloqueo de
reentrada para proteger secciones críticas de código. Es muy
parecido al mecanismo de bloqueo implícito establecido que usted
obtiene con la palabra clave
sincronizada, pero tiene algunas
posibilidades adicionales que pueden ser útiles para un control
más refinado del bloqueo explícito. El Listado 14 muestra un
ejemplo de su utilización:
Listado 14. Un uso muy simple de ReentrantLock
private Lock myLock = new ReentrantLock();
...
void myMethod() {
// Acquire the lock
myLock.lock();
try {
... do work in critical section ...
} finally {
// Relinquish the lock
myLock.unlock();
}// end finally
...
}
|
Antes de entrar en la sección critica, se invoca el método
lock() del objeto
ReentrantLock para intentar y obtener
el bloqueo. Esto sólo da resultado si otra hebra ya no tiene el
bloqueo, en cuyo caso la hebra actual está bloqueada. Antes de
la versión 5.0 de la plataforma Java, usted podría haber escrito
la funcionalidad en el Listado 14 en código con algo así en el
Listado 15. (usted todavía puede, por supuesto, como
sincronizada no ha desaparecido.)
Listado 15. Un método sincronizado
synchronized void myMethod() {
... realizar un trabajo en un sección crítica ...
}
|
En estos usos sencillos, no se apreciará una diferencia en el
comportamiento del código. Si, sin embargo, usted hace uso de
los tipos ThreadMXBean y
ThreadInfo para verificar el recuento
bloqueado de una hebra que se conoce que se bloqueará la entrada
a una sección crítica en el curso de un programa en ejecución,
el resultado será diferente dependiendo del método de bloqueo
que se utiliza. usted mismo puede demostrar esto escribiendo
algún código simple que tenga dos hebras diferentes intentando
realizar una llamada a myMethod(), y
forzar a una hebra a llegar siempre allí en segundo lugar.Esa
hebra, obviamente será bloqueada y deberá tener una cuenta
bloqueada de exactamente uno. Utilizando la palabra clave
sincronizada con
myMethod() usted verá, como era de
esperar, una cuenta bloqueada mayor que cero del objeto
ThreadInfo asociado a la hebra. Sin
embargo, utilizando el nuevo enfoque
ReentrantLock , podrá verá una cuenta
bloqueada de cero. Es una apuesta segura que, como la
posibilidad de supervisión de la VM
ThreadMXBean alcanza el mismo nivel
con los paquetes nuevos simultáneos, esta diferencia en el
comportamiento observado se eliminará en futuros releases de la
plataforma Java.
ElMemoryMXBean es único entre los
MXBeans en que tiene la posibilidad de enviar notificaciones
dinámicas de los eventos interesantes sobre el uso de la memoria
de los objetos de los clientes. Los beneficios de la
comunicación inmediata en asuntos tales como el uso de memoria
que supera un umbral preestablecido deberían ser obvia, ya que
puede ser un síntoma de problemas a nivel de aplicación, o bien
indicar que la máquina virtual necesita otro ajuste.
El modelo de notificación que utiliza
MemoryMXBean proviene de la
especificación JMX MBean, que a su vez es muy parecida al modelo
de notificación de eventos que se utiliza en la programación
Java. Como un emisor de notificaciones, el
MemoryMXBean implementa la interfaz
JMX
javax.management.NotificationBroadcaster,
una interfaz relativamente pequeña que permite al bean tanto
registrar como dar de baja a las partes interesadas. Por otra
parte, cada una de las partes interesadas (objeto) debe
implementar la interfaz
javax.management.NotificationListener
. Esta interfaz consiste en una sola operación, la cual es
invocada por el evento de emisión de un MXBean cuando se produce
un evento.
Los receptores se pueden registrar (o dar de baja) con el
MemoryMXBean en cualquier momento
durante el ciclo de vida de la VM. Las notificaciones sólo se
emiten al conjunto actual de registrados.
Cuando se realiza una llamada a un método manejador del receptor,
recibe una instancia de la clase
javax.management.Notification . Este
es el tipo de señal de evento genérico en el modelo de
notificación de eventos de JMX. Su diseño es tal que se puede
establecer para mantener una cantidad considerable de
información sobre el evento que llevo a su creación. Para el
MemoryMXBean, existen en la
actualidad dos tipos de notificaciones:
- Un recurso de memoria (a veces llamado agrupación de
memoria) en la VM ha crecido hasta superar un valor
previamente establecido. Esta clase de evento es
identificado por la constante
MemoryNotificationInfoMEMORY_THRESHOLD_EXCEEDED.. - El tamaño del recurso de memoria de inmediato después de
la recogida de memoria es mayor que un valor de
umbral previamente establecido. Esto es identificado por la
constante
MemoryNotificationInfoMEMORY_COLLECTION_THRESHOLD_EXCEEDED..
A la recepción del objeto Notificación
en el método manejador, un receptor registrado puede determinar
el tipo de evento que se ha producido mediante la consulta del
tipo de Notificación, y comprobar la
cadena de caracteres en contra de los dos valores
MemoryNotificationInfo .
Para transferir información detallada sobre el evento a los
receptores, el MemoryMXBean establece
cada propiedad de los datos de usuario del objeto de
Notificación esencialmente, (un medio
para que la emisora incluya todo lo que quiera) con una
instancia concreta de
javax.management.openmbean.CompositeData
que representa un objeto
MemoryNotificationInfo . Tal y como
explicamos en Supervisión de una VM remota a través
del servidor de la plataforma, la encapsulación de los
datos del evento dentro de un tipo abierto de JMX permite que lo
entienda el conjunto más amplio de receptores.
Hasta el momento, vamos bien. Ahora es el momento para hacer frente a algo que no se puede pasar por alto: la seguridad. ¿Qué ocurre si usted no quiere que el código de aplicación de una persona pueda acceder y modificar la VM? ¿Qué opciones están disponibles? Existen algunas propiedades del sistema que se pueden configurar para controlar el nivel de acceso y la forma en que los datos de la VM se transmiten desde el agente JMX hasta el cliente de administración. Estos recaen en dos categorías: la autenticación de la contraseña y la Secure Sockets Layer (SSL).
por medio de las opciones de línea de comandos.
Para hacer accesible a una VM 5.0-compatible a la supervisión y gestión, es necesario instalar un número de puerto para el agente JMX de la plataforma por medio de la siguiente opción de línea de comandos:
-Dcom.sun.management.jmxremote.port=<number> |
En el caso poco probable de que no le importe quién pueda acceder a su VM a través de este puerto, también se puede desactivar la autenticación de la contraseña y el cifrado SSL (las cuales están habilitadas de manera predeterminada) añadiendo las dos opciones siguientes:
-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false |
El uso de estas tres opciones a la vez es conveniente cuando se
encuentra desarrollando el código de cliente
java.lang.management y desea ser
capaz de supervisar otra VM fácilmente. En un ambiente de
producción, es necesario instalar el control de contraseña o el
SSL (y posiblemente los dos).
Autenticación de la contraseña
En el directoriojre/lib/management del 5.0 SDK, encontrará un
archivo llamado jmxremote.password.template. Esto define nombres
de usuario y contraseñas para dos roles. El primero es un rol de
supervisión , permitiendo el acceso a funciones de
gestión de sólo lectura; el segundo rol es un rol de
control para funciones de escritura y lectura. Los
clientes pueden autenticar los nombres de usuario
monitorRole o
controlRole , dependiendo del nivel
de acceso necesario. Para garantizar que sólo estos usuarios
autenticados puedan tener acceso, necesita hacer lo
siguiente:
- Copiar el contenido de jmxremote.password.template en un
archivo llamado jmxremote.password y eliminar los
comentarios de las líneas al final del archivo que definen
los nombres de usuario y las contraseñas, cambiando las
contraseñas a su gusto.
- Modificar los permisos en jmxremote.password de modo que
sólo los pueda leer y modificar el propietario. (En los
sistemas UNIX y UNIX-like, establecer los permisos a 600. En
Microsoft Windows, siga las instrucciones en el artículo
"Cómo proteger un archivo de contraseña en los sistemas de
Microsoft Windows", del cual se puede encontrar un enlace en
Recursos.)
- Al iniciar la VM, especifique la ubicación del archivo de
contraseñas para utilizarlo con la siguiente opción de línea
de
comandos:
-Dcom.sun.management.jmxremote.password.file=<file-path>
Desde la perspectiva del cliente de gestión, es necesario proporcionar una combinación válida de nombre de usuario/contraseña para acceder a una VM que tenga activada la autenticación. Si el cliente es JConsole, esto es fácil: los campos de nombre de usuario y contraseña se proporcionan en la pestaña de conexión inicial. Para escribir el código que proporciona los detalles de autenticación para una VM remota, es necesario añadir las modificaciones que se muestran en el Listado 16 del código de conexión previamente dado en el Listado 4:
Listado 16. Conexión a una VM remota que requiere la autenticación del usuario
try {
// provide a valid username and password (e.g., via program arguments)
String user = "monitorRole";
String pw = "password";
// place the username and password in a string array of credentials that
// can be used when making the connection to the remote JMX agent
String[] credentials = new String[] { user, pw };
// the string array of credentials is placed in a map keyed against the
// well-defined credentials identifier string
Map<String, String[]> props = new HashMap<String, String[]>();
props.put("jmx.remote.credentials", credentials);
// supply the map of credentials to the connect call
JMXServiceURL address =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1234/jmxrmi");
JMXConnector connector = JMXConnectorFactory.connect(address, props);
// it is a trivial matter to get a reference for the MBean server
// connection to the remote agent
MBeanServerConnection mbs = connector.getMBeanServerConnection();
} catch ...
|
El proporcionar un nombre de usuario o contraseña no válido a una
VM que requiera autenticación, da lugar a un
java.lang.SecurityException.. De
igual forma, el autenticar como el
monitorRole y a continuación tratar
de invocar una de las operaciones de lectura y escritura -- como
intentar solicitar la recogida de basura -- también provoca el
lanzamiento de un SecurityException
.
Se puede utilizar el SSL para cifrar la información que se transfiere desde un agente JMX de la plataforma de clientes de gestión que lo supervisa. Los datos transmitidos son cifrados utilizando la criptografía (asimétrica) de clave pública, de manera que sólo el titular de la clave privada correspondiente puede descifrar los datos. Esto previene a las aplicaciones de análisis de paquetes de que intercepten la comunicación.El hacer uso de este dispositivo requiere que los dos extremos de la conexión tengan el SSL configurado, lo que implica la generación de un par de claves y un certificado digital. Los detalles están fuera del alcance de este artículo, lea el excelente tutorial de Greg Travis, "Uso de JSSE para la segura comunicación de socket," para obtener más información (ver Recursos).
Las buenas noticias es que una vez generadas el par de claves y el certificado, no es necesario modificar el código de clientes de gestión al hacer uso del SSL. Se puede activar el cifrado con sólo utilizar ciertas opciones de línea de comandos. En primer lugar, la aplicación Java que desea supervisar o administrar debe iniciarse con las siguientes opciones:
-Dcom.sun.management.jmxremote.ssl.need.client.auth=true -Djavax.net.ssl.keyStore=<keystore-location> -Djavax.net.ssl.trustStore=<truststore-location> -Djavax.net.ssl.keyStoreType=<keystore-type> -Djavax.net.ssl.keyStorePassword=<keystore-password> -Djavax.net.ssl.trustStoreType=<truststore-type> -Djavax.net.ssl.trustStorePassword=<truststore-password> |
Los clientes de gestión que deseen comunicarse con la plataforma,
tienen que ser lanzados con un subconjunto de las opciones
anteriores: Se puede omitir la primera y las dos últimas líneas.
Si el cliente es JConsole, puede transferir estas opciones
cuando se inicia la GUI con la sintaxis de línea de comandos
-J, la cual transfiere las opciones
de Java a través de la JVM.
Una vez más, el tutorial "Uso de JSSE para la segura comunicación de socket" puede ofrecer más detalles sobre estas opciones individuales.
Esperamos haberle estimulado a conocer más acerca de la API de
gestión de la plataforma Java 5.0. Así como la llegada de Java
Management Extensions proporciona a los desarrolladores y
administradores de empresa de Java una forma estandarizada para
supervisar y controlar sus implementaciones, por lo que la
introducción de la API
java.lang.management en Java 5.0, le
ofrece los medios para mirar por debajo de la capucha de la
misma plataforma en la que se ejecutan sus aplicaciones.
Los MXBeans son bastante sencillos de obtener y utilizar, si están manteniendo agrupaciones de hebras y pestañas en una aplicación ejecutándose localmente o comprobando de forma segura el uso de la memoria de un programa de misión crítica que requiera la atención en otras partes de la intranet. Los MXBeans desempeñan un papel fundamental en ayudarle a entender más sobre el mundo en que él se ejecuta su código, si está analizando y tratando de comprender las características de las implementaciones Java desconocidas de una manera no intrusiva, o compilando sus propias herramientas de supervisión del rendimiento y creación de perfiles.
Como "la habilidad de diagnosticar, supervisión y gestión" es uno de los temas clave para el próximo release 6.0 de la plataforma Java, esta API se establece para tener un rol cada vez más importante en el futuro de la tecnología Java.
Aprender
- API java.lang.management: Explore la API completa en
más detalle.
- "Uso de JSSE para seguras comunicaciones de socket"
(Greg Travis, developerWorks, abril de 2002): Aprenda más sobre
la segura configuración de socket.
- ""De las cajas negras a las empresas" (Sing Li,
developerWorks, septiembre-diciembre de 2002): Obtenga más
información sobre JMX en esta serie de tres partes.
- "Como asegurar un archivo de contraseña en los sistemas
Microsoft Windows" (Sun Microsystems): Aprenda a
asegurar los recursos sensibles de Java, como el archivo
jmxremote.password, en la plataforma Windows.
- WebSphere Application Server InfoCenter: Aprenda como
WebSphere Application Server versión 6 utiliza la tecnología
JMX.
- Taming Tiger: Las series de John Zukowski
en developerWorks es una lectura fundamental para realizar el
cambio a Java 5.
- La zona de la
tecnología Java : Cientos de artículos sobre cada
aspecto de la programación Java.
Comentar
- blogs de
developerWorks: Participe en la comunidad
developerWorks.
May Glover Gunn es un físico de formación, pero se unió a IBM a su antojo hace tres años. Desde entonces, ha trabajado en el Centro de Tecnología Java en los Laboratorios de IBM en Hursley en una variedad de roles. Recientemente, ha desarrollado pruebas para el release de la tecnología Java 5.0 y se encuentra trabajando actualmente en nuevas tecnologías relacionadas con la plataforma Java.
George Harley es un desarrollador sénior de los laboratorios de IBM en Hursley que trabaja en el Centro de Tecnología Java. Se ha dedicado por más de una década a la escritura profesional de software en una diversidad de lenguajes. En su tiempo libre trabaja.

Caroline Gough trabajó como desarrolladora en una pequeña empresa de software durante tres años antes de unirse al equipo de Pruebas de Sistemas del Centro de Tecnología Java en los Laboratorios de IBM en Hursley. Es una probadora sénior, con experiencia en las pruebas de estrés y planificación técnica de RAS (fiabilidad, disponibilidad y servicio). Trabajó en la reciente adaptación de la versión 5.0 de la plataforma Java de IBM y en la actualidad se encuentra preparando pruebas para los futuros releases de la plataforma Java.