Anonymous
Попытка динамически загружать и загружать зависимости во время выполнения с использованием Apache Aether, но Spring Boot
Сообщение
Anonymous » 13 янв 2025, 15:33
Я работаю над оптимизацией приложения Spring Boot, загружая зависимости во время выполнения, а не упаковывая их в окончательный JAR-файл. Хотя я успешно реализовал механизм загрузки, Spring Boot не может распознать эти динамически загружаемые зависимости, хотя они доступны через Java ClassLoader.
Цель:
Уменьшите окончательный размер JAR-файла:
Исключив зависимости из скомпилированного JAR-файла
Загрузив необходимые зависимости по адресу время выполнения
Загрузка их динамическое использование URLClassLoader
Моя информация
Я искал в Интернете возможные решения, но не нашел их. Ранее я обрабатывал нечто подобное, используя ядро Java, при разработке плагинов Minecraft с помощью Libby, но я не уверен, осуществимо ли это с помощью Spring Boot. Хотя я использовал инструменты искусственного интеллекта для решения некоторых проблем с зависимостями, сейчас я застрял на этом этапе.
Моя текущая реализация
DependancyLoader.java
Код: Выделить всё
package com.hapangama.sunlicense.boot;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.collection.CollectResult;
import org.eclipse.aether.collection.DependencyCollectionException;
import org.eclipse.aether.collection.DependencySelector;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.util.filter.DependencyFilterUtils;
import org.eclipse.aether.util.graph.selector.ScopeDependencySelector;
import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
import org.springframework.stereotype.Service;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@Service
public class DependencyLoader {
private static final Logger LOGGER = Logger.getLogger(DependencyLoader.class.getName());
private static final String DEPENDENCIES_DIR = "BOOT-INF/lib";
public static void initializeDependencies() throws Exception {
// Create libs directory if it doesn't exist
File libsDir = new File(DEPENDENCIES_DIR);
if (!libsDir.exists()) {
libsDir.mkdirs();
}
// Initialize Maven components
RepositorySystem system = Booter.newRepositorySystem();
DefaultRepositorySystemSession session = Booter.newRepositorySystemSession(system);
session.setLocalRepositoryManager(
system.newLocalRepositoryManager(
session,
new LocalRepository(libsDir.getAbsolutePath())
)
);
// Define repositories
List repositories = Arrays.asList(
new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/")
.setPolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN))
.build(),
new RemoteRepository.Builder("spring-releases", "default", "https://repo.spring.io/release")
.setPolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN))
.build(),
new RemoteRepository.Builder("jcenter", "default", "https://jcenter.bintray.com")
.setPolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN))
.build(),
new RemoteRepository.Builder("vaadin-addons", "default", "https://maven.vaadin.com/vaadin-addons")
.setPolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN))
.build()
);
// Define dependencies
List dependencies = Arrays.asList(
// Spring Boot dependencies
new Dependency(new DefaultArtifact("org.springframework.boot:spring-boot-starter-data-jpa:2.5.4"), "runtime"),
new Dependency(new DefaultArtifact("org.springframework.boot:spring-boot-starter-security:2.5.4"), "runtime"),
// Vaadin and related dependencies
new Dependency(new DefaultArtifact("com.vaadin:vaadin-spring-boot-starter:24.0.0"), "runtime"),
new Dependency(new DefaultArtifact("in.virit:viritin:2.10.1"), "runtime"),
new Dependency(new DefaultArtifact("com.github.appreciated:apexcharts:24.0.1"), "runtime"),
new Dependency(new DefaultArtifact("org.parttio:starpass-theme:1.0.4"), "runtime"),
new Dependency(new DefaultArtifact("org.vaadin.crudui:crudui:7.1.2"), "runtime"),
// Database
new Dependency(new DefaultArtifact("com.h2database:h2:2.1.214"), "runtime"),
// Utility libraries
new Dependency(new DefaultArtifact("org.modelmapper:modelmapper:3.2.0"), "runtime"),
// Discord integration
new Dependency(new DefaultArtifact("net.dv8tion:JDA:5.2.1"), "runtime")
);
// Create collection request
CollectRequest collectRequest = new CollectRequest();
collectRequest.setRepositories(repositories);
dependencies.forEach(collectRequest::addDependency);
// Resolve dependencies
DependencyResult result = resolveDependencies(system, session, collectRequest);
// Get resolved artifact files
List artifactFiles = getArtifactFiles(result);
// Create and set up the custom ClassLoader
URL[] urls = artifactFiles.stream()
.map(file -> {
try {
return file.toURI().toURL();
} catch (MalformedURLException e) {
LOGGER.warning("Failed to convert file to URL: " + file);
return null;
}
})
.filter(Objects::nonNull)
.toArray(URL[]::new);
URLClassLoader classLoader = new URLClassLoader(urls, DependencyLoader.class.getClassLoader());
Thread.currentThread().setContextClassLoader(classLoader);
// Verify critical dependencies
verifyDependencies(classLoader);
}
private static DependencyResult resolveDependencies(RepositorySystem system,
RepositorySystemSession session,
CollectRequest collectRequest) throws Exception {
CollectResult collectResult = system.collectDependencies(session, collectRequest);
DependencyRequest dependencyRequest = new DependencyRequest(collectResult.getRoot(),
DependencyFilterUtils.classpathFilter("compile", "runtime"));
return system.resolveDependencies(session, dependencyRequest);
}
private static List getArtifactFiles(DependencyResult result) {
PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
result.getRoot().accept(nlg);
return nlg.getArtifacts(false).stream()
.map(Artifact::getFile)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
private static void verifyDependencies(ClassLoader classLoader) {
try {
// Verify JDA
Class.forName("net.dv8tion.jda.api.hooks.ListenerAdapter", true, classLoader);
LOGGER.info("JDA dependency loaded successfully");
// Verify Spring Boot
Class.forName("org.springframework.boot.SpringApplication", true, classLoader);
LOGGER.info("Spring Boot dependency loaded successfully");
// Add other critical dependency verifications as needed
} catch (ClassNotFoundException e) {
LOGGER.severe("Failed to verify critical dependency: " + e.getMessage());
throw new RuntimeException("Critical dependency verification failed", e);
}
}
}
Booter.java
Код: Выделить всё
package com.hapangama.sunlicense.boot;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.transport.file.FileTransporterFactory;
import org.eclipse.aether.transport.http.HttpTransporterFactory;
import org.eclipse.aether.util.listener.ChainedRepositoryListener;
import org.eclipse.aether.util.listener.ChainedTransferListener;
import java.io.File;
// Booter.java
public class Booter {
public static RepositorySystem newRepositorySystem() {
DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
locator.addService(TransporterFactory.class, FileTransporterFactory.class);
locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
return locator.getService(RepositorySystem.class);
}
public static DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) {
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
LocalRepository localRepo = new LocalRepository("target/local-repo");
session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
session.setTransferListener(new ChainedTransferListener());
session.setRepositoryListener(new ChainedRepositoryListener());
return session;
}
}
Основной класс
Код: Выделить всё
package com.hapangama.sunlicense;
import com.hapangama.sunlicense.boot.DependencyLoader;
import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.theme.Theme;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.Properties;
@Theme(value = "sun")
@SpringBootApplication(exclude = ErrorMvcAutoConfiguration.class)
public class SunLicenseApplication implements AppShellConfigurator {
public static void main(String[] args) {
try {
// Initialize dependencies before starting Spring
DependencyLoader.initializeDependencies();
// Get the context class loader that has our dependencies
ClassLoader customClassLoader = Thread.currentThread().getContextClassLoader();
// Create Spring application
SpringApplication app = new SpringApplication(SunLicenseApplication.class);
Properties properties = new Properties();
properties.put("spring.main.allow-bean-definition-overriding", "true");
properties.put("spring.main.allow-circular-references", "true");
app.setDefaultProperties(properties);
// Important: Set both resource loader and context class loader
app.setResourceLoader(new DefaultResourceLoader(customClassLoader));
Thread.currentThread().setContextClassLoader(customClassLoader);
ConfigurableApplicationContext context = app.run(args);
if (context != null && context.isActive()) {
System.out.println("Application started successfully");
System.out.println("Active profiles: " + Arrays.toString(context.getEnvironment().getActiveProfiles()));
}
} catch (Exception e) {
System.out.println("Failed to start application");
e.printStackTrace();
System.exit(1);
}
}
}
Журнал консоли запуска
Java удалось загрузить JDA (одна из библиотек успешно)
но он по какой-то причине выдает класс, который позже не найден.
Код: Выделить всё
Caused by: java.lang.ClassNotFoundException: net.dv8tion.jda.api.hooks.ListenerAdapter
https://paste.hapangama.com/egewawovif.properties
Pom.xml
Код: Выделить всё
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.3.5
com.hapangama
SunLicense
0.0.1-SNAPSHOT
SunLicense
SunLicense
17
24.5.4
Vaadin Directory
https://maven.vaadin.com/vaadin-addons
false
org.springframework.boot
spring-boot-starter-data-jpa
provided
org.springframework.boot
spring-boot-starter-security
provided
com.vaadin
vaadin-spring-boot-starter
provided
com.h2database
h2
provided
org.projectlombok
lombok
true
Подробнее здесь: [url]https://stackoverflow.com/questions/79351555/trying-to-download-and-load-dependencies-dynamically-at-runtime-using-apache-aet[/url]
1736771634
Anonymous
Я работаю над оптимизацией приложения Spring Boot, загружая зависимости во время выполнения, а не упаковывая их в окончательный JAR-файл. Хотя я успешно реализовал механизм загрузки, Spring Boot не может распознать эти динамически загружаемые зависимости, хотя они доступны через Java ClassLoader. [b]Цель:[/b] Уменьшите окончательный размер JAR-файла: [list] [*]Исключив зависимости из скомпилированного JAR-файла [*]Загрузив необходимые зависимости по адресу время выполнения [*]Загрузка их динамическое использование URLClassLoader [/list] [b]Моя информация[/b] Я искал в Интернете возможные решения, но не нашел их. Ранее я обрабатывал нечто подобное, используя ядро Java, при разработке плагинов Minecraft с помощью Libby, но я не уверен, осуществимо ли это с помощью Spring Boot. Хотя я использовал инструменты искусственного интеллекта для решения некоторых проблем с зависимостями, сейчас я застрял на этом этапе. [b]Моя текущая реализация[/b] DependancyLoader.java [code]package com.hapangama.sunlicense.boot; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.collection.CollectResult; import org.eclipse.aether.collection.DependencyCollectionException; import org.eclipse.aether.collection.DependencySelector; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyFilter; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.repository.RepositoryPolicy; import org.eclipse.aether.resolution.DependencyRequest; import org.eclipse.aether.resolution.DependencyResolutionException; import org.eclipse.aether.resolution.DependencyResult; import org.eclipse.aether.util.filter.DependencyFilterUtils; import org.eclipse.aether.util.graph.selector.ScopeDependencySelector; import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator; import org.springframework.stereotype.Service; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.logging.Logger; import java.util.stream.Collectors; @Service public class DependencyLoader { private static final Logger LOGGER = Logger.getLogger(DependencyLoader.class.getName()); private static final String DEPENDENCIES_DIR = "BOOT-INF/lib"; public static void initializeDependencies() throws Exception { // Create libs directory if it doesn't exist File libsDir = new File(DEPENDENCIES_DIR); if (!libsDir.exists()) { libsDir.mkdirs(); } // Initialize Maven components RepositorySystem system = Booter.newRepositorySystem(); DefaultRepositorySystemSession session = Booter.newRepositorySystemSession(system); session.setLocalRepositoryManager( system.newLocalRepositoryManager( session, new LocalRepository(libsDir.getAbsolutePath()) ) ); // Define repositories List repositories = Arrays.asList( new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/") .setPolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN)) .build(), new RemoteRepository.Builder("spring-releases", "default", "https://repo.spring.io/release") .setPolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN)) .build(), new RemoteRepository.Builder("jcenter", "default", "https://jcenter.bintray.com") .setPolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN)) .build(), new RemoteRepository.Builder("vaadin-addons", "default", "https://maven.vaadin.com/vaadin-addons") .setPolicy(new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_DAILY, RepositoryPolicy.CHECKSUM_POLICY_WARN)) .build() ); // Define dependencies List dependencies = Arrays.asList( // Spring Boot dependencies new Dependency(new DefaultArtifact("org.springframework.boot:spring-boot-starter-data-jpa:2.5.4"), "runtime"), new Dependency(new DefaultArtifact("org.springframework.boot:spring-boot-starter-security:2.5.4"), "runtime"), // Vaadin and related dependencies new Dependency(new DefaultArtifact("com.vaadin:vaadin-spring-boot-starter:24.0.0"), "runtime"), new Dependency(new DefaultArtifact("in.virit:viritin:2.10.1"), "runtime"), new Dependency(new DefaultArtifact("com.github.appreciated:apexcharts:24.0.1"), "runtime"), new Dependency(new DefaultArtifact("org.parttio:starpass-theme:1.0.4"), "runtime"), new Dependency(new DefaultArtifact("org.vaadin.crudui:crudui:7.1.2"), "runtime"), // Database new Dependency(new DefaultArtifact("com.h2database:h2:2.1.214"), "runtime"), // Utility libraries new Dependency(new DefaultArtifact("org.modelmapper:modelmapper:3.2.0"), "runtime"), // Discord integration new Dependency(new DefaultArtifact("net.dv8tion:JDA:5.2.1"), "runtime") ); // Create collection request CollectRequest collectRequest = new CollectRequest(); collectRequest.setRepositories(repositories); dependencies.forEach(collectRequest::addDependency); // Resolve dependencies DependencyResult result = resolveDependencies(system, session, collectRequest); // Get resolved artifact files List artifactFiles = getArtifactFiles(result); // Create and set up the custom ClassLoader URL[] urls = artifactFiles.stream() .map(file -> { try { return file.toURI().toURL(); } catch (MalformedURLException e) { LOGGER.warning("Failed to convert file to URL: " + file); return null; } }) .filter(Objects::nonNull) .toArray(URL[]::new); URLClassLoader classLoader = new URLClassLoader(urls, DependencyLoader.class.getClassLoader()); Thread.currentThread().setContextClassLoader(classLoader); // Verify critical dependencies verifyDependencies(classLoader); } private static DependencyResult resolveDependencies(RepositorySystem system, RepositorySystemSession session, CollectRequest collectRequest) throws Exception { CollectResult collectResult = system.collectDependencies(session, collectRequest); DependencyRequest dependencyRequest = new DependencyRequest(collectResult.getRoot(), DependencyFilterUtils.classpathFilter("compile", "runtime")); return system.resolveDependencies(session, dependencyRequest); } private static List getArtifactFiles(DependencyResult result) { PreorderNodeListGenerator nlg = new PreorderNodeListGenerator(); result.getRoot().accept(nlg); return nlg.getArtifacts(false).stream() .map(Artifact::getFile) .filter(Objects::nonNull) .collect(Collectors.toList()); } private static void verifyDependencies(ClassLoader classLoader) { try { // Verify JDA Class.forName("net.dv8tion.jda.api.hooks.ListenerAdapter", true, classLoader); LOGGER.info("JDA dependency loaded successfully"); // Verify Spring Boot Class.forName("org.springframework.boot.SpringApplication", true, classLoader); LOGGER.info("Spring Boot dependency loaded successfully"); // Add other critical dependency verifications as needed } catch (ClassNotFoundException e) { LOGGER.severe("Failed to verify critical dependency: " + e.getMessage()); throw new RuntimeException("Critical dependency verification failed", e); } } } [/code] Booter.java [code]package com.hapangama.sunlicense.boot; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; import org.eclipse.aether.impl.DefaultServiceLocator; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.RepositoryPolicy; import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; import org.eclipse.aether.spi.connector.transport.TransporterFactory; import org.eclipse.aether.transport.file.FileTransporterFactory; import org.eclipse.aether.transport.http.HttpTransporterFactory; import org.eclipse.aether.util.listener.ChainedRepositoryListener; import org.eclipse.aether.util.listener.ChainedTransferListener; import java.io.File; // Booter.java public class Booter { public static RepositorySystem newRepositorySystem() { DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); locator.addService(TransporterFactory.class, FileTransporterFactory.class); locator.addService(TransporterFactory.class, HttpTransporterFactory.class); return locator.getService(RepositorySystem.class); } public static DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); LocalRepository localRepo = new LocalRepository("target/local-repo"); session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); session.setTransferListener(new ChainedTransferListener()); session.setRepositoryListener(new ChainedRepositoryListener()); return session; } } [/code] Основной класс [code]package com.hapangama.sunlicense; import com.hapangama.sunlicense.boot.DependencyLoader; import com.vaadin.flow.component.page.AppShellConfigurator; import com.vaadin.flow.theme.Theme; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.DefaultResourceLoader; import java.net.URLClassLoader; import java.util.Arrays; import java.util.Collections; import java.util.Properties; @Theme(value = "sun") @SpringBootApplication(exclude = ErrorMvcAutoConfiguration.class) public class SunLicenseApplication implements AppShellConfigurator { public static void main(String[] args) { try { // Initialize dependencies before starting Spring DependencyLoader.initializeDependencies(); // Get the context class loader that has our dependencies ClassLoader customClassLoader = Thread.currentThread().getContextClassLoader(); // Create Spring application SpringApplication app = new SpringApplication(SunLicenseApplication.class); Properties properties = new Properties(); properties.put("spring.main.allow-bean-definition-overriding", "true"); properties.put("spring.main.allow-circular-references", "true"); app.setDefaultProperties(properties); // Important: Set both resource loader and context class loader app.setResourceLoader(new DefaultResourceLoader(customClassLoader)); Thread.currentThread().setContextClassLoader(customClassLoader); ConfigurableApplicationContext context = app.run(args); if (context != null && context.isActive()) { System.out.println("Application started successfully"); System.out.println("Active profiles: " + Arrays.toString(context.getEnvironment().getActiveProfiles())); } } catch (Exception e) { System.out.println("Failed to start application"); e.printStackTrace(); System.exit(1); } } } [/code] Журнал консоли запуска Java удалось загрузить JDA (одна из библиотек успешно) [code]INFO: JDA dependency loaded successfully[/code] но он по какой-то причине выдает класс, который позже не найден. [code]Caused by: java.lang.ClassNotFoundException: net.dv8tion.jda.api.hooks.ListenerAdapter[/code] https://paste.hapangama.com/egewawovif.properties Pom.xml [code] xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.boot spring-boot-starter-parent 3.3.5 com.hapangama SunLicense 0.0.1-SNAPSHOT SunLicense SunLicense 17 24.5.4 Vaadin Directory https://maven.vaadin.com/vaadin-addons false org.springframework.boot spring-boot-starter-data-jpa provided org.springframework.boot spring-boot-starter-security provided com.vaadin vaadin-spring-boot-starter provided com.h2database h2 provided org.projectlombok lombok true Подробнее здесь: [url]https://stackoverflow.com/questions/79351555/trying-to-download-and-load-dependencies-dynamically-at-runtime-using-apache-aet[/url]