Ошибка запуска Single jar после обновления с Spring Boot 1.3.7 до 1.4.0

После обновления с Spring Boot 1.3.7 до 1.4.0 мы больше не можем запускать наше приложение как единую сборку jar с плагином Spring Boot Maven. Наше приложение представляет собой небольшой REST-интерфейс, использующий Jersey и Jetty. Мы используем Maven, и наш файл pom довольно стандартный для Spring Boot.

Мы по-прежнему можем запускать приложение с помощью mvn spring-boot:run и из Eclipse, но при запуске в виде одного jar-файла Jersey ResourceFinder жалуется, что не может найти .jar!/BOOT-INF/classes.

Когда я распаковываю банку, папка BOOT-INF/classes присутствует и содержит ожидаемые классы и ресурсы.

Любая помощь приветствуется.

2016-08-10 14:58:31.162 ERROR 16071 --- [           main] o.s.boot.SpringApplication               
: Application startup failed

org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'jerseyConfig' defined in URL
[jar:file:/acmesource/acme/acme-core/acme-core-api/target/acme-core-api-0.1
SNAPSHOT.jar!/BOOT-INF/classes!/com/acme/core/api/JerseyConfig.class]: Bean 
instantiation via constructor failed; nested exception is 
org.springframework.beans.BeanInstantiationException: Failed to instantiate 
[com.acme.core.api.JerseyConfig]: Constructor threw exception; nested 
exception is
org.glassfish.jersey.server.internal.scanning.ResourceFinderException:
java.io.FileNotFoundException: /acmesource/acme/acme-core/acme-core
api/target/acme-core-api-0.1-SNAPSHOT.jar!/BOOT-INF/classes (No such file or directory)

person oleb    schedule 10.08.2016    source источник


Ответы (3)


Из Spring Примечания к выпуску Boot 1.4:

Изменение макета исполняемых файлов jar означает, что ограничение в сканировании путей к классам в Джерси теперь влияет на исполняемые jar, а также исполняемые файлы war. Чтобы обойти эту проблему, классы, которые вы хотите сканировать с помощью Джерси, должны быть упакованы в банку и включены в качестве зависимости в BOOT-INF/lib. После этого средство запуска Spring Boot должно быть настроен на распаковку этих банок при запуске, чтобы Джерси мог сканировать их содержимое.

person Andy Wilkinson    schedule 10.08.2016
comment
Спасибо! Пропустил тот. Работает при индивидуальной регистрации ресурсов. - person oleb; 10.08.2016
comment
@oleb Вы спасли мой день!! Спасибо - person Héctor; 28.12.2016

Просто другое решение:

Хотя Jersey не может сканировать ваши классы внутри новой версии толстого загрузочного jar-файла, вы можете добиться того же эффекта, используя средства сканирования пути к классам Spring. Таким образом, вы можете сканировать пакет аналогично ResourceConfig.packages():

ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Provider.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Path.class));
config.registerClasses(scanner.findCandidateComponents("your.package.to.scan").stream()
            .map(beanDefinition -> ClassUtils.resolveClassName(beanDefinition.getBeanClassName(), config.getClassLoader()))
            .collect(Collectors.toSet()));

Примечание: пожалуйста, посмотрите на источник org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener. Это стандартное решение, и вы можете видеть, что оно делает то же самое: оно сканирует классы, аннотированные с помощью @Path или @Provider (но не может ничего найти из-за сломанного механизма сканирования).

Кстати, метод на основе бобов, опубликованный lanwen, может быть более понятным :) Просто добавьте к нему @Provider.

person mihu86    schedule 17.03.2017

С Spring Boot (+ Jersey 2) это может выглядеть как отдельный класс конфигурации (для достижения индивидуальной регистрации ресурсов):

@Configuration
public class RestBeansConfiguration {
    private static final Logger LOG = LoggerFactory.getLogger(RestBeansConfiguration.class);

    @Inject
    private ApplicationContext appCtx;

    @Bean
    public ResourceConfigCustomizer jersey() {
        return config -> {
            LOG.info("Jersey resource classes found:");
            appCtx.getBeansWithAnnotation(Path.class).forEach((name, resource) -> {
                LOG.info(" -> {}", resource.getClass().getName());
                config.register(resource);
            });
        };
    }
}
person lanwen    schedule 13.09.2016