Весна, NotReadablePropertyException и версия Glassfish

Я работаю над веб-приложением, которое использует Spring MVC.

Он работал нормально на Glassfish 3.0.1, но при переходе на Glassfish 3.1 он начал вести себя странно. Некоторые страницы только частично показывают или вообще ничего не показывают, и в журнале много сообщений такого типа:

    [#|2012-08-30T11:50:17.582+0200|WARNING|glassfish3.1|javax.enterprise.system.container.web.com.sun.enterprise.web|_ThreadID=69;_ThreadName=Thread-1;|StandardWrapperValve[SpringServlet]: PWC1406: Servlet.service() for servlet SpringServlet threw exception
    org.springframework.beans.NotReadablePropertyException: Invalid property 'something' of bean class [com.something.Something]: Bean property 'something' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
        at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:729)
        at org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:576)
        at org.springframework.beans.BeanWrapperImpl.getBeanWrapperForPropertyPath(BeanWrapperImpl.java:553)
        at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:719)
        at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:99)
        at org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:226)
        at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:120)
        at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:178)
        at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:198)
        at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getName(AbstractDataBoundFormElementTag.java:164)
        at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.writeDefaultAttributes(AbstractDataBoundFormElementTag.java:127)
        at org.springframework.web.servlet.tags.form.AbstractHtmlElementTag.writeDefaultAttributes(AbstractHtmlElementTag.java:421)
        at org.springframework.web.servlet.tags.form.TextareaTag.writeTagContent(TextareaTag.java:95)
        at org.springframework.web.servlet.tags.form.AbstractFormTag.doStartTagInternal(AbstractFormTag.java:102)
        at org.springframework.web.servlet.tags.RequestContextAwareTag.doStartTag(RequestContextAwareTag.java:79)

Сообщение об ошибке не является неправильным, потому что у рассматриваемого свойства нет метода установки (получает его значение через конструктор). Но, как я уже сказал, это не было проблемой при использовании Glassfish 3.0.1, только при использовании его на новом сервере со Glassfish 3.1.

Кто-нибудь знает, есть ли что-то в версии Glassfish, которая может вызвать это? Или это какая-то конфигурация, которая отсутствует на новом сервере?

Некоторый код:

Контроллер:

@ModelAttribute
public SomethingContainer retriveSomethingContainer(@PathVariable final long id {
    return somethingContainerDao.retrieveSomethingContainer(id);       
}

@InitBinder("somethingContainer")
public void initBinderForSomething(final WebDataBinder binder) {
    binder.setAllowedFields(new String[] {
        "something.title",
        "something.description",
    });
}

SomethingContainer:

@Embedded
private final Something something = new Something();

public Something getSomething() {
    return something;
}
//no setter

public String getDescription() {
    return something.getDescription();
}

Update:

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

Обновление 2:

На сервере 3.0.1 один из аргументов jvm был -client. На 3.1-сервере это был -сервер. Мы изменили его на -client, и это привело к частому снижению частоты ошибок, это происходило через день с -server, потребовалось 2 недели, чтобы это произошло с -client.

Обновление 3:

Некоторая информация о серверах (может быть добавлена ​​дополнительная информация по запросу ..)

Сервер1 (рабочий):

Windows Server 2003
Java jdk 6 build 35
Glassfish 3.0.1 build 22
-xmx 1024m

Server2 (тот, у кого проблемы):

Windows Server 2008 64-bit
Java jdk 6 build 31
Glassfish 3.1 build 43
-xmx 1088m
-xms 1088m

Мы используем Spring версии 3.1.0.

Обновление 4:

Я воссоздал ошибку, переименовав поле в jsp во что-то, чего нет в атрибуте модели.

Но, что более важно, я кое-что заметил: поля, в которых система не может найти геттеры, часто являются полями суперклассов тех, на которые есть ссылки в атрибуте модели. Чтобы продолжить мой пример, SomthingContainer действительно такой:

public class SuperSomethingContainer {
    [...]
    private Something something;
    public Something getSomething() {
        return something;
    }
}

public class SomethingContainer extends SuperSomethingContainer {
    [...]
}

Ссылка в контроллере остается неизменной, поэтому она ссылается на поле в суперклассе рассматриваемого объекта.

Обновление 5:

Я попытался подключиться к производственному серверу с помощью отладчика после возникновения ошибки. Я поставил точку останова в операторе return метода контроллера, возвращающего объект с ошибкой, и попытался выяснить, смогу ли я получить доступ к полю с проблемами в тот момент. И это я мог, поэтому проблема должна лежать в Spring MVC /сгенерированных jsp-классах.

(Кроме того, поле с ошибкой имело тип «someobject.something [0] .somethingelse [0]», но когда список someelse-списка был пуст, ошибки не было! Для меня это означает, что оно каким-то образом не могу найти метод get списка (?))

Обновление 6:

Кажется, что проблема связана с генерацией Java-классов из jsps. Мы не использовали прекомпиляцию jsps при развертывании, поэтому они компилируются при первом использовании. Проблема возникает при первом посещении страницы и компиляции jsp. Я также заметил, что, как только проблема возникла, jsps, которые компилируются после, будут давать ошибки. Я сохранил несколько сгенерированных java-файлов, и при следующей перезагрузке я сравню их с рабочими. Все ближе:)

Обновление 7:

Сравнил скомпилированные java-файлы jsp, которые привели к ошибке, с теми, которые этого не сделали, и не было никакой разницы. Так что это как бы пропускает.

Итак, теперь я знаю, что Java-объект, покидающий контроллер, в порядке (проверено отладчиком), а класс java, сгенерированный из jsp, в порядке. Так что, должно быть, что-то среднее, теперь мне нужно выяснить, что ...

Обновление 8:

Еще один раунд отладки, еще более сузивший проблему. Оказывается, весна делает некоторое кеширование свойств, принадлежащих различным классам. В org.springframework.beans.BeanWrapperImpl, метод getPropertyValue есть следующее:

private Object getPropertyValue(PropertyTokenHolder tokens) throws BeansException {
    String propertyName = tokens.canonicalName;
    String actualName = tokens.actualName;
    PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);
    if (pd == null || pd.getReadMethod() == null) {
        throw new NotReadablePropertyException(getRootClass(), this.nestedPath + propertyName);
    }

Проблема в том, что cachedIntrospectionResults не содержит рассматриваемое свойство, но содержит все остальные свойства класса. Нужно будет еще покопаться, чтобы попытаться выяснить, почему он отсутствует, если он отсутствует с самого начала или теряется где-то вдоль линии.

Кроме того, я заметил, что отсутствующие свойства - это те, у которых нет сеттеров, только геттеры. И это, кажется, учитывает контекст, как указано в трассировке стека. Поэтому отсутствие объекта при посещении одной страницы не означает, что оно недоступно при посещении другой.

Обновление 9:

Еще один день, больше отладки. На самом деле найденонекоторые хорошие вещи. Вызов getCachedIntrospectionResults () в предыдущем блоке кода завершился вызовом CachedIntrospectionResults # forClass (theClassInQuestion). Это вернуло объект CachedIntrospectionResults, содержащий далеко не все ожидаемые свойства (11 из 21). Зайдя в метод forClass, я обнаружил:

static CachedIntrospectionResults forClass(Class beanClass) throws BeansException {
    CachedIntrospectionResults results;
    Object value = classCache.get(beanClass);
    if (value instanceof Reference) {
        Reference ref = (Reference) value;
        results = (CachedIntrospectionResults) ref.get();
    }
    else {
        results = (CachedIntrospectionResults) value;
    }
    if (results == null) {
    //build the CachedIntrospectionResults, store it in classCache and return it.

Оказалось, что возвращенный CachedIntrospectionResults был найден classCache.get (beanClass). Поэтому то, что хранилось в classCache, было повреждено /не содержало всего, что должно. Я установил точку останова на строке classCache.get (beanClass) и попытался запустить ее через отладчик:

  

classCache.put (beanClass, null);

Когда метод был завершен и перестроен CachedIntrospectionResults, все снова заработало. Таким образом, то, что хранится в classCache, не синхронизировано с тем, что было бы и должно быть создано, если бы было разрешено восстановить его. Связано ли это с тем, что что-то пошло не так при первом построении, или если classCache поврежден где-то вдоль строки, которую я в настоящее время не знаю.

Я начинаю подозревать, что это как-то связано с загрузчиками классов, так как ранее у меня возникали проблемы из-за изменений в работе загрузчика классов при обновлении Glassfish ..

7 голосов | спросил 16 revs
Tobb
1 Jam1000000amThu, 01 Jan 1970 03:00:00 +030070 1970, 03:00:00

4 ответа


0

Я попросил моего коллегу расследовать ошибку, и он смог воссоздать ее в модульном тесте. Это было сделано путем вызова метода, который создает CachedIntroSpectionResults для класса, в то же время подчеркивая jvm путем добавления строк в память с очень низкими настройками памяти. Этот подход заставил его потерпеть неудачу 20/30000 раз.

Что касается причины, я получил только устное объяснение, поэтому у меня нет всех подробностей, но это было что-то вроде этого: у Java есть свои собственные результаты самоанализа, и они упакованы Spring. Проблема в том, что java-результаты используют мягкие ссылки, что делает их склонными к сборке мусора. Таким образом, когда Spring создавал свои обертки вокруг этих мягких ссылок в то же самое время, когда работал сборщик мусора, он фактически очищал некоторые основы того, что использовал Spring, что приводило к тому, что свойства «терялись».

Решение, по-видимому, заключается в обновлении с Spring 3.1.0.RELEASE до Spring 3.1.3.RELEASE. Здесь есть некоторые изменения, и Spring больше не переносит мягкие ссылки при определении свойств класса (мягкие ссылки используются в редких, особых случаях, а не всегда). После обновления версии Spring ошибка не была воспроизведена с помощью модульного теста, осталось выяснить, так ли это на практике.

Обновление: прошло несколько недель, никаких признаков ошибки. Так что обновление Spring версии сработало:)

ответил zaffargachal 24 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 24 Sep 2012 14:16:02 +0400 2012, 14:16:02
0

Может быть несколько возможных причин. Я не уверен насчет фактического, но я могу дать вам способ выяснить проблему

Шаг 1: на сервере 2 на компьютере разверните приложение в Glassfish 3.0.1 build 22 , теперь, если на компьютере с сервером 2 он работает нормально, это означает, что могут быть проблемы с библиотеками Glass fish, причиной может быть следующая проблема

  1. Любая библиотека, отсутствующая в Glassfish 3.1 build 43 , которая находится в Glassfish 3.0.1 build 22 . Вы можете решить, скопировав все библиотеки с рабочего сервера Glassfish на новый сервер.
  2. Мои библиотеки Библиотеки Glassfish конфликтуют с весенней версией. [ Симилиарная проблема, с которой я столкнулся на tomcat, и когда я заменил мои весенние библиотеки с 3.0.1 на 3.0.3, это сработало для меня] , так что замените свои весенние библиотеки на последнюю.

Шаг 2: , и если результатом шага 1 является то, что приложение не работает на компьютере сервера 2 в Glassfish 3.0.1, сборка 22, может быть следующая причина

  1. если какие-либо библиотеки, которые вы вставили на java lib , либо не включены в этот сервер, либо имеют разные версии.

  2. Любые папки, которые установлены в classpath или используют переменные среды на сервере 1, либо не существует на сервере 2, либо не содержит jar-файлов или jar-файлов с разными версиями

ответил zaffargachal 24 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 24 Sep 2012 14:16:02 +0400 2012, 14:16:02
0

Я думаю, что я действительно нашел кандидата по причине этого.

После получения ошибки на одном из тест-серверов после очень короткого промежутка времени и небольшого использования мы сделали несколько дополнительных проверок причины. Оказалось, что у тестового сервера была только половина доступной памяти, что заставило нас взглянуть на нее более тщательно. Оказалось, что он не использовал всю свою память, но при использовании JConsole для исследования использования памяти другой частью пространства нового поколения в куче оказалось, что одно из пространств surivior было заполнено полностью. Я предполагаю, что из-за этого некоторые части переполняются, что приводит к тому, что переполненные части становятся GC-редактируемыми или недоступными из-за того, что не находятся там, где предполагалось.

Нам еще предстоит проверить, что это на самом деле проблема и в производственной среде, но как только ошибка снова появится, мы проверим, и если это так, мы изменим некоторые параметры памяти, чтобы освободить место для областей выживания кучи нового поколения. (-XX: SurvivorRatio = 6 или что-то в этом роде).

Таким образом, кажется, что более крупным приложениям Spring MVC требуется большое пространство для выживания, особенно в новых версиях Glassfish.

ответил Tobb 9 +04002012-10-09T13:12:49+04:00312012bEurope/MoscowTue, 09 Oct 2012 13:12:49 +0400 2012, 13:12:49
0

Действительно, возникла проблема с новым введенным классом ExtendedBeanInfo в Spring 3.1.0, который был исправлен в Spring 3.1 .1 - смотрите ( https://jira.spring.io/browse/SPR-8347).

ответил Tobb 9 +04002012-10-09T13:12:49+04:00312012bEurope/MoscowTue, 09 Oct 2012 13:12:49 +0400 2012, 13:12:49

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132