Spring Boot со встроенным Tomcat завершается неудачно, когда JVM выполняется из JNI в приложении C ++

HP-UX: B.11.31 U ia64

Джава: 7 или 8

Весна-загрузка: 1.5.3.RELEASE

Кот: 8.5.14


  • Обновить: Похоже, проблема с Java JNI / JVM под HP-UX, поскольку мы не получаем эту ошибку под RHEL

    org.apache.tomcat.util.net.NioEndpoint$Acceptor run
    SEVERE: Socket accept failed
    java.nio.channels.NotYetBoundException
    

У меня есть приложение весенней загрузки, которое использует встроенный сервер Tomcat. JAR был переупакован как myapp-exec.jar используя spring-boot: repackage, чтобы его можно было выполнить из командной строки с помощью java -jar и успешно запустить в качестве автономного модуля только для целей тестирования. Тот же код, доступный в оригинальном JAR myapp.jar без всех сведений о BOOT-INF и подпружиненной загрузке предназначен для выполнения в производстве с помощью JVM, встроенной в приложение C ++. Из-за процесса переупаковки это невозможно с помощью переупакованного JAR.

Таким образом, для правильной работы встроенной JVM C ++ все библиотеки, доступные в перепакованном JAR, также должны быть доступны по пути к классам для встроенной JVM C ++. Это достигается путем извлечения BOOT-INF / lib из перепакованного JAR с использованием jar -xvf myapp-exec.jar и перемещение каталога BOOT-INF / lib в целевое расположение пути к классам. Файлы JAR включаются в определение CLASSPATH в том же порядке, в котором они отображаются в переупакованном JAR. Это работает просто отлично, и этот принцип применяется к ряду других проектов, использующих точно такую ​​же инфраструктуру приложения C ++ без проблем.

Проблема здесь, кажется, со встроенным сервером Tomcat. У меня проблема в том, что сервер Tomcat, который работает нормально, когда выполняется перепакованный JAR, не инициализируется правильно при запуске встроенной JVM C ++.

Любая помощь с благодарностью получена!

Spring-boot приложение запускается так:

    spring_application = new SpringApplication(IncidentConfiguration.class);
IncidentSubscribe subscriber = null;

try
{
spring_context = spring_application.run(args);
subscriber = (IncidentSubscribe) spring_context.getBean("incidentSubscribe");

synchronized (subscriber)
{
if (subscriber.start())
{
subscriber.wait();
}
else
{
log.warn("failed to start Web-Service platform!");
}
}
}

catch (InterruptedException ex)
{
log.info("thread interrupted");
}

Неудачный запуск (C ++ встроенная JVM)

Запустите встроенный Tomcat

Feb 08, 2018 6:06:05 PM org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer initialize
INFO: Tomcat initialized with port(s): 8080 (http)
Feb 08, 2018 6:06:05 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Feb 08, 2018 6:06:05 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/8.5.14

Инициализирует AbstractProtocol (не выполнено при успешном запуске)

Feb 08, 2018 6:06:12 PM org.springframework.jmx.export.MBeanExporter afterSingletonsInstantiated
INFO: Registering beans for JMX exposure on startup
Feb 08, 2018 6:06:12 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8080"]
Feb 08, 2018 6:06:13 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8080"]
Feb 08, 2018 6:06:13 PM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read

SEVERE: ошибка повторяет 1000 раз …

Feb 08, 2018 6:06:13 PM org.apache.tomcat.util.net.NioEndpoint$Acceptor run
SEVERE: Socket accept failed
java.nio.channels.NotYetBoundException
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:237)
at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:453)
at java.lang.Thread.run(Thread.java:745)

Здесь происходит нечто иное …

Feb 08, 2018 6:06:13 PM org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer start
INFO: Tomcat started on port(s): -1 (http)
Feb 08, 2018 6:06:14 PM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started application in 23.874 seconds (JVM running for 33.524)

Приложение C ++ обнаруживает сбой при запуске и завершает загрузку

08/02 18:06:15.127[26491][0:1:Thread-2] XXXAdapter.java:144 ***Warning: start() - stop the embeded TOMCAT server

Feb 08, 2018 6:06:15 PM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@545866ff: startup date [Thu Feb 08 18:05:55 GMT 2018]; root of context hierarchy
Feb 08, 2018 6:06:15 PM org.springframework.jmx.export.MBeanExporter destroy
INFO: Unregistering JMX-exposed beans on shutdown
Feb 08, 2018 6:06:15 PM org.apache.coyote.AbstractProtocol pause
INFO: Pausing ProtocolHandler ["http-nio-8080"]
Feb 08, 2018 6:06:15 PM org.apache.tomcat.util.net.AbstractEndpoint unlockAccept
WARNING: Failed to unlock acceptor for [http-nio-8080] because the local address was not available
Feb 08, 2018 6:06:15 PM org.apache.catalina.core.StandardService stopInternal
INFO: Stopping service Tomcat

Feb 08, 2018 6:06:15 PM org.apache.coyote.AbstractProtocol stop
INFO: Stopping ProtocolHandler ["http-nio-8080"]
Feb 08, 2018 6:06:15 PM org.apache.coyote.AbstractProtocol destroy
INFO: Destroying ProtocolHandler ["http-nio-8080"]

Успешный запуск (переупакованный JAR)

Запустите встроенный Tomcat

Feb 08, 2018 6:39:26 PM org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer initialize
INFO: Tomcat initialized with port(s): 8080 (http)
Feb 08, 2018 6:39:26 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Feb 08, 2018 6:39:26 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/8.5.14

Здесь происходит нечто иное …

Feb 08, 2018 6:39:33 PM org.springframework.jmx.export.MBeanExporter afterSingletonsInstantiated
INFO: Registering beans for JMX exposure on startup
Feb 08, 2018 6:39:33 PM org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer start
INFO: Tomcat started on port(s): 8080 (http)
Feb 08, 2018 6:39:33 PM org.springframework.boot.StartupInfoLogger logStarted
INFO: Started XXXApplication in 19.691 seconds (JVM running for 26.538)

Затем он закрывается …

 Feb 08, 2018 6:39:33 PM org.springframework.context.support.AbstractApplicationContext doClose

INFO: Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@423419: startup date [Thu Feb 08 18:39:17 GMT 2018]; root of context hierarchy
Feb 08, 2018 6:39:33 PM org.springframework.jmx.export.MBeanExporter destroy
INFO: Unregistering JMX-exposed beans on shutdown
Feb 08, 2018 6:39:33 PM org.apache.catalina.core.StandardService stopInternal
INFO: Stopping service Tomcat

Пример кода C ++ по запросу

ОК, фреймворк C ++ содержит гораздо больше функций, чем просто start() метод, так как это довольно сложно, я извлек соответствующие биты и убрал большинство кодов проверки ошибок и освобождения ресурсов для ясности.

Общая структура JVM

struct
{
JavaVM*      handle;             ///<  Handle to Java Virtual Machine (JVM).
jclass       adapterClass;       ///<  JNI jclass for user class.
jobject      adapterObject;      ///<  JNI jobject for instance of user class.
jmethodID    adapterStart;       ///<  JNI method ID  of 'start' function for user class.
jclass       XXXAdapterClass;    ///<  JNI jclass for class XXXAdapter.
jmethodID    AdapterClassLoader; ///<  JNI method ID for static method setClassLoader.

} JVM;

Конфигурация и инициализация JVM

JavaVMInitArgs vm_args;
vm_args.nOptions = count;
vm_args.options  = options;
vm_args.version  = JNI_VERSION_1_4;
vm_args.ignoreUnrecognized = JNI_FALSE;

//  Create the Java Virtual Machine
JNIEnv* jni = NULL;
int success = (JNI_CreateJavaVM((JavaVM**)&JVM.handle, (void**)&jni, &vm_args) != JNI_ERR);

if (!success)
{
SM_Throw(AdapterException, "error creating Java Virtual Machine (JVM)");
}

//  locate parent class and class loader for use later
//
JVM.XXXAdapterClass = jni->FindClass( "com/xxx/XXXAdapter" );
JVM.AdapterClassLoader = jni->GetStaticMethodID( JVM.XXXAdapterClass, "setClassLoader", "()V")) )jclass     j_adapterClass  = 0;
jobject    j_adapterObject = 0;
jmethodID  j_adapterInit   = 0;

//  locate the user specified AdapterClass
//
j_adapterClass = jni()->FindClass(adapter_class_path)) )

//  check  it is inherited from XXXAdapter class
//
jni->IsAssignableFrom(j_adapterClass, JVM.XXXAdapterClass) )

//  locate the default class constructor
//
j_adapterInit = jni->GetMethodID( j_adapterClass, "<init>", "()V");

//  create a new adapter object for this service
//
j_adapterObject = jni->NewObject( j_adapterClass, j_adapterInit );

//  save service adapter instance as a Java global object
//
JVM.adapterObject = jni->NewGlobalRef(j_adapterObject);

//  save user adapter class as a Java global reference
//
JVM.adapterClass = jni->NewGlobalRef(j_adapterClass);JVM.adapterStart = jni->GetMethodID( j_adapterClass, "start", "()V");

jni->DeleteLocalRef(j_adapterClass);
jni->DeleteLocalRef(j_adapterObject);
jni->ExceptionClear();

и, наконец, вызовите адаптер start() функция

JNIEnv*  jni;

//  attach to current Java thread to get handle to JNI environment
//
if (JVM.handle->AttachCurrentThread((void**)&jni, NULL) < 0)
{
SM_Throw(AdapterException, "JAVAAdapter: error during AttachCurrentThread!");
}

//  always use the parent class ClassLoader
//
jni->CallStaticVoidMethod(JVM.XXXAdapterClass, JVM.AdapterClassLoader, NULL);
if (jni->ExceptionCheck())
{
jni->ExceptionDescribe();
SM_Throw(WarningException, "JAVAAdapter: error during setClassLoader!" );
}

//  *** DO THE CALL ***
//
jni->CallVoidMethod(JVM.adapterObject, JVM.adapterStart);//  and detach from current Java thread
//
JVM.handle->DetachCurrentThread();

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]