programacion - son los encargados de que los programas compilados en java corran en cualquier sistema operativo
¿Cómo puedo llamar a un método en un objeto desde fuera de la JVM? (11)
JNI (Java Native Interface) permite el acceso al código java desde C o C ++.
Tengo una clase Java realmente simple que decora de manera efectiva un mapa con validación de entrada, con los métodos obvio void set () y String get ().
Me gustaría poder llamar efectivamente a esos métodos y manejar valores de retorno y excepciones desde fuera de la JVM, pero aún en la misma máquina. Actualización: la persona que llama que tengo en mente no es otra JVM; gracias @Dave Ray
Mis consideraciones de implementación son típicas
- actuación
- facilidad de implementación y mantenimiento (¿simplicidad?)
- confiabilidad
- flexibilidad (es decir, ¿puedo llamar desde una máquina remota, etc.)?
¿Hay una "forma correcta"? Si no, ¿cuáles son mis opciones y cuáles son los pro / contra para cada una?
(¡Las cosas que las personas realmente han hecho y pueden proporcionar retroalimentación de la vida real serían geniales!)
¿Llamarás desde otro sistema basado en JVM, o es el lenguaje del cliente arbitrario? Si llama desde otra JVM, uno de los enfoques más simples es exponer su objeto como un MBean a través de JMX. Aquí se muestra el Hello World MBean canónico. Los pros son:
- Realmente fácil de implementar
- Realmente fácil de llamar desde otras JVM
- Soporte para máquinas remotas
- jconsole le permite probar manualmente su MBean sin escribir un cliente
Contras:
- El cliente tiene que estar en una JVM (creo)
- No es ideal para estructuras de datos e interacciones más complicadas. Por ejemplo, no creo que un MBean pueda devolver una referencia a otro MBean. Se serializará y devolverá una copia.
Como sus llamadores no son aplicaciones Java y ya está previendo llamadas en red, RMI-IIOP (CORBA) podría ser una opción. Aunque definitivamente no es fácil de implementar, tiene la ventaja de ser un estándar ampliamente reconocido.
Lo que quiere es la interfaz nativa de Java (JNI), a pesar de las dificultades que pueda presentar. No hay otra tecnología equivalente que sea tan fácil de implementar.
Como se mencionó en los comentarios de la respuesta anterior, el JNI está optimizado para llamar al código nativo de Java, pero también se puede usar para el reverso con un poco de trabajo. En su código nativo, necesitará implementar el punto de entrada JNI, algo así como SetMapPointer (), luego invoque esa función desde el código Java una vez que se haya creado el Mapa. La implementación de SetMapPointer () debería guardar el puntero del objeto Java en algún lugar accesible, luego el código nativo puede invocar los métodos Java en él según sea necesario.
Deberá asegurarse de que esto ocurra en el orden correcto (es decir, el código nativo no intente acceder al Mapa antes de que se haya creado y pasado al código nativo), pero ese no debería ser un problema especialmente difícil.
Para facilidad de uso, usaría Spring Remoting . Si ya está utilizando Spring en su proyecto, eso es obvio. Si no estás ... bueno deberías echarle un vistazo de todos modos.
Spring proporciona una abstracción que le permite cambiar fácilmente los protocolos de comunicación remota. Admite los protocolos más ampliamente implementados (SOAP, Hessian, Burlap, RMI, ...). Si llama desde un código que no es de Java, Hessian tiene soporte en varios otros idiomas, se sabe que es más eficiente que SOAP y más fácil que CORBA.
Tengo una secuencia de comandos Inno Setup (instalación de un programa Java) que llama a algunos métodos Java para realizar algunas operaciones o verificar algunas condiciones.
Yo (en realidad mi predecesor) simplemente instanciamos java.exe en cada llamada. Lo cual es, obviamente, costoso, aunque no crítico en mi caso (y el caché de Windows se activa, supongo).
Una alternativa es utilizar algunos mensajes / comunicación entre idiomas, su programa Java actúa como un servidor. Corba viene a la mente, ya que es independiente del idioma. Pero un poco pesado, tal vez. Puedes usar enchufes RPC es otra palabra de moda también, pero no tengo mucha experiencia en el campo.
Como su llamador no está basado en JVM, se trata de una comunicación entre procesos con JVM. Las opciones que tengo en mente son:
- Comuníquese sobre un socket: haga que su JVM escuche las conexiones entrantes y los comandos de envío de llamadas
- Comuníquese usando archivos compartidos (grabaciones de llamadas en archivos, sondeos y actualizaciones de JVM)
- Usando JNI, inicie JVM dentro de un proceso de llamadores y luego use RMI / MBeans para comunicarse con la primera ("servidor") JVM. La persona que llama tendrá acceso a los resultados usando JNI
La opción 3 IMO es la forma más "Java" de hacer esto, y es la más compleja / propensa a errores. La opción 2 es fea pero simple La opción 1 es moderadamente fácil (parte de Java) y de lo contrario está bien.
De acuerdo. Aquí hay otra oportunidad ahora que sé que el cliente no es Java. Como quiere acceso fuera de proceso y posiblemente acceso remoto a la máquina, no creo que JNI sea lo que quiere, ya que es estrictamente en proceso (y una molestia total). Aquí hay algunas otras opciones:
Sockets crudos : solo configure un socket de escucha en Java y acepte conexiones. Cuando obtenga una conexión, lea la solicitud y envíe una respuesta. Casi todos los idiomas pueden usar conectores así que esta es una solución bastante universal. Sin embargo, deberá definir su propio esquema de clasificación, análisis, etc.
XML-RPC : esto no es tan moderno hoy en día, pero es simple y efectivo. Existen bibliotecas de Java y bibliotecas en la mayoría de los otros idiomas.
CORBA : como se mencionó anteriormente, CORBA es una opción, pero es bastante complicado y los expertos son cada vez más difíciles de conseguir.
Servidor web : configure un servidor web incorporado en su aplicación y gestione los requisitos. He oído cosas buenas sobre Jetty o puede usar la que se proporciona con Java . He utilizado este último con éxito para los archivos KML del servidor a Google Earth a partir de una simulación escrita en Java. La mayoría de los otros idiomas tienen bibliotecas para hacer solicitudes HTTP. Cómo usted codifica los datos (XML, texto, etc.) depende de usted.
Servicios web : Creo que esto sería más complicado, pero podría usar JAX-WS para exponer sus objetos como servicios web. NetBeans tiene herramientas muy buenas para construir servicios web, pero esto puede ser excesivo.
Otra alternativa para considerar si el otro proceso estará en la misma máquina y el sistema operativo es POSIX-obediente (no Windows) es Canalizaciones con nombre.
El proceso externo escribe las operaciones, como cadenas o alguna otra codificación de bytes acordada, en el conducto nombrado mientras la aplicación Java está leyendo desde el conducto, analizando las operaciones entrantes y ejecutándolas contra su objeto.
Esta es la misma estrategia que utilizaría para las conexiones de socket, simplemente en lugar de un SocketInputStream que estaría leyendo desde un FileInputStream que está conectado a un canalización con nombre.
Una alternativa a CORBA es ICE , a menos que la licencia sea un problema (es GPL, pero también puede comprar una licencia comercial).
Tiene casi todos los beneficios de CORBA, pero ZeroC, el proveedor, proporciona enlaces para muchos idiomas diferentes. Los proveedores de CORBA tienden a proporcionar solo uno o dos enlaces de idioma, y luego comienzas a encontrar problemas de compatibilidad.
La documentación también es excelente. No hubiera dicho que fue particularmente fácil de aprender, pero probablemente más fácil que CORBA.
De lo contrario, otra opción que no creo que se haya mencionado es el nuevo middleware / marco RPC desarrollado por Cisco, ahora donado a Apache, llamado Etch . Todavía es bastante nuevo, y la documentación es escasa.
Beanshell es un intérprete de java similar a un intérprete de comandos que puede exponerse a través de un socket de red. Básicamente lo haces desde Java:
i = new bsh.Interpreter();
i.set( "myapp", this ); // Provide a reference to your app
i.eval("server(7000)");
y luego haces esto desde cualquier otro lugar:
telnet localhost 7001
myapp.someMethod();
Esta pequeña utilidad realiza invocaciones Java remotas mucho más fácilmente que JNI o RMI.
Para obtener más información, comience en: http://www.beanshell.org/manual/remotemode.html