Неверный тип в пуле констант после горячей замены кода с использованием DCEVM

Всем привет! Для контекста я работаю над простым проектом Spring в IntelliJ, чтобы настроить его с помощью HotswapAgent, используя DCEVM [8u181 build 2] вместе с совместимым JDK [ 8u181 ] на сервере приложений Payara 5.0.

Пожалуйста, поддержите меня в следующих нескольких фрагментах кода и моем правдоподобном объяснении того, что происходит, и это не вопрос о синтаксисе Spring MVC или его работе.

Это пример кода, который я тестирую на горячей замене [не встроенной в JVM, но с использованием DCEVM] и HotswapAgent[1.3.0].

HelloWorldController.java

@Controller
public class HelloWorldController {



 @Autowired HelloService helloService;



@RequestMapping("/hello")
public String hello(
        @RequestParam(value = "name", required = false, defaultValue = "World") String name,
        Model model) {


    model.addAttribute("name", name);
    System.out.println( helloService.sayHello() );

    return "helloworld";
}

Я не хочу включать код для helloService, так как это может раздуть этот пост.

HelloService.sayHello() просто выдает типичный Hello World в консоли

Как вы можете видеть выше, автоматическое подключение было включено и выполняет правильную функцию (упомянутую выше).

После этого я комментирую аннотацию Autowired и вызов функции, и это дает мне ошибку:

org.springframework.web.util.NestedServletException: Handler dispatch     failed; nested exception is java.lang.annotation.AnnotationFormatError: java.lang.IllegalArgumentException: Wrong type at constant pool index

Сосредоточьтесь на:

java.lang.IllegalArgumentException: Wrong type at constant pool index

Я отладил приложение и обнаружил, что исключение IllegalArgumentException возникло, когда AnnotationParser анализировал аннотации класса контроллера Spring из пула констант, а члены (одной из аннотаций, которые являются «типом» аннотации) были неправильно, когда он был взят из пула констант класса.

Итак, насколько мне известно, горячее развертывание выполняется неправильно (даже несмотря на то, что HotswapAgent говорит, что он перезагрузил класс на сервере Payara), или что-то не так с коммуникацией JVM или JDK, и я говорю это, потому что, когда я делаю противоположное это закомментировать автопроводку, затем горячее развертывание, а затем запустить, поэтому я получаю исключение нулевого указателя.

Примечание: просто для дополнительной информации

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException

Если кому-то нужна дополнительная информация, код или журналы по этому поводу, я был бы более чем рад уточнить. Спасибо за ваше время всем.


person AbuBakar Khan    schedule 23.10.2018    source источник


Ответы (2)


Политика хранения Autowire — @Retention(RetentionPolicy.RUNTIME).

Согласно спецификации JVM, аннотация должна быть доступна в бинарном виде. (Ссылка: https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.6.4.2)

Я предполагаю, что java хранит ссылку в постоянном пуле всех классов с аннотацией RUNTIME. При горячей замене происходит горячая замена класса, но константный пул не обновляется, чтобы отразить замену класса.

Существует аналогичная открытая проблема с hotswapgent: https://github.com/HotswapProjects/HotswapAgent/issues/256

person Ashraff Ali Wahab    schedule 23.10.2018
comment
Ваше предположение верно, есть ли способ проверить постоянный пул класса или получить к нему доступ? Я имею в виду любой способ практически проверить ваше предположение. Благодарю вас. - person AbuBakar Khan; 24.10.2018
comment
Да, вы можете, выполнив javap -c ‹ClassFile›, но вы не сможете легко просмотреть это во время выполнения. - person Ashraff Ali Wahab; 24.10.2018

Что ж, это было странно решать, но это связано не с версией JDK или DCEVM, а с диспетчерским сервлетом Spring.

Мой диспетчерский сервлет отсутствовал:

<annotation-driven />

Вот почему он не смог зарегистрировать класс контроллера и вызвал нежелательное поведение. Также отсутствовали добавленные схемы XML.

xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"

Просто для завершения или если это кому-то поможет, я опубликую полную конфигурацию сервлета диспетчера.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <annotation-driven />

    <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

    <context:component-scan base-package="com.test" />
    </beans:beans>
person AbuBakar Khan    schedule 25.10.2018