Spring Boot WAR не распознает loader.path - PullRequest
0 голосов
/ 08 апреля 2020

Это как-то связано с с , но у меня это не сработало.

Вопрос сформулирован в одном предложении

Как добавить библиотеки для весенней загрузки, используя loader.path или что-то подобное при запуске веб-приложения, упакованного в файл WAR?

Что я хочу / Что я пробовал

Я хочу использовать свойство loader.path Spring Boot. Проблема в том, что весенняя загрузка не распознает его. Я думал, что это может быть потому, что я экспортировал проект в виде WAR файла.

Это мой код, предназначенный для загрузки другого приложения и библиотеки:

public static void load(String jarPath,String className,String methodName) throws MalformedURLException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    /*my old solution
    URL[] urls={new File(jarPath).toURI().toURL()};
    ClassLoader loader=AccessController.doPrivileged((PrivilegedAction<URLClassLoader>)()->new ParentPreferringURLClassLoader(urls,WebBot.class.getClassLoader()));
    */
    ClassLoader loader=Thread.currentThread().getContextClassLoader();
    Class<?> clazz = loader.loadClass(className);
    Method method = clazz.getMethod(methodName);
    Object ret = method.invoke(null);
    if(ret instanceof MyCommunicationClass) {
        MyCommunicationClass com=ret;
    }else {
        throw new IllegalArgumentException("the communication object supplier returned a "+ret.getClass().getCanonicalName()+": "+ret);
    }
}

Соответствующие части pom.xml в моем веб-приложении:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.4.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <packaging>war</packaging>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>Group ID of the shared library</groupId>
            <artifactId>Artefact ID of the shared library</artifactId>
            <version>Version of the shared library</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Примените части моего pom.xml в другом приложении:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

</project>
    <dependencies>
        <dependency>
            <groupId>Group ID of the shared library</groupId>
            <artifactId>Artefact ID of the shared library</artifactId>
            <version>Version of the shared library</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin><!-- assembly (JAR) -->
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>io.github.jdiscordbots.nightdream.core.NightDream</mainClass>
                        </manifest>
                    </archive>
                    <finalName>NightDream</finalName>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <appendAssemblyId>false</appendAssemblyId>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

После упаковки обоих приложений с помощью mvn clean package я запускаю веб-приложение, которое должно запускать другое приложение, используя java -Dloader.path="file:../otherApplication/target/other.jar" -Dloader.debug=true -jar target\MyWebApplication.war

Проблема в том, что Thread.currentThread().getContextClassLoader().loadClass(className) выдает ClassNotFoundException при попытке загрузить класс связи.

Я могу убедиться, что свойства устанавливаются с помощью System.getProperty(), но я не получаю никаких дополнительных данных отладчика для загрузчика и не могу загрузить класс.

Кажется, что я что-то пропустил при установке loader.pathloader.debug) свойство.

Кто-нибудь знает, как добавить библиотеки для весенней загрузки, используя loader.path или что-то подобное при запуске веб-приложения, упакованного как файл WAR?

Сфера / мой старый так lution (я не думаю, что это действительно нужно для ответа на этот вопрос)

Я использую Spring Boot для создания веб-интерфейса для другого приложения (он экспортируется в виде файла WAR по мере необходимости использовать JSP). Веб-интерфейс имеет доступ только к библиотеке, которую может изменить другое приложение.

Другое приложение должно быть предоставлено в JAR, который я могу выбрать.

Другое приложение также необходимо работать без веб-интерфейса.

Ранее я загружал другое приложение из своего веб-приложения, используя пользовательское ClassLoader, которое расширяет URLClassLoader, но использует родительский ClassLoader, если класс существует в обоих классах. loaders:

public class ParentPreferringURLClassLoader extends URLClassLoader {
    public ParentPreferringURLClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        try{
            return getParent().loadClass(name);
        }catch(ClassNotFoundException e) {
            return super.loadClass(name);
        }
    }
}

Мне нужно было использовать это ClassLoader, потому что я не мог приводить объекты из библиотеки из приложения

Мне не нравится это решение, потому что оно приносит следующее Основные проблемы:

  • Используется версия библиотеки, предоставленная из моего веб-интерфейса. Я хочу иметь возможность изменять версию библиотеки, которую использует другое приложение, без изменения версии в библиотеке. Веб-интерфейс должен также использовать версию библиотеки (если нет конфликтов, но эти конфликты не важны для вопроса)
  • Я использую Java API компилятора в моем другом приложении, и мне нужен доступ код другого приложения в нем. Кажется, что возникают проблемы при загрузке скомпилированного класса, поскольку он не включает другое приложение.
  • В идеале я хочу использовать регистратор SLF4J, предоставленный другим приложением.
...