Pokazywanie postów oznaczonych etykietą groovy. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą groovy. Pokaż wszystkie posty

2011-05-17

Jeszcze raz Groovy i Spring

Jakiś czas temu miałem problem z dynamiczną rekompilacją komponentów Spring napisanych w Groovy. Wtedy przyczyną był błąd w samym Groovy, szczegóły opisałem tutaj. Po aktualizacji Groovy wszystko było ok, ale niedawno stwierdziłem że mechanizm dynamicznego przeładowywania znowu przestał działać. Ponieważ w międzyczasie wykonałem spory refactoring aplikacji, to nie bardzo wiedziałem gdzie zacząć szukać sprawcy. Uznałem, że tym razem to nie Groovy - skoro raz zrobili błąd i go poprawili, to szansa na to że znowu się pojawił jest niewielka. Po włączeniu logów na poziomie DEBUG stwierdziłem, że Spring też jest niewinny - gdy plik źródłowy Groovy był zmieniany, w logach pojawiał się spodziewany komunikat: Target refreshed successfully ... czyli skrypt był ładowany od nowa. Pomimo tego w aplikacji dalej używana była pierwotna wersja. Nie będę zanudzał Czytelnika szczegółowym opisem trudności i niebezpieczeństw, którym musiałem stawić czoła aby odkryć istotę problemu i przejdę od razu do clou tego posta. Tym razem bruździł Tomcat, a dokładnie jego ClassLoader.
Jeżeli skrypt zostanie umieszczony w aplikacji webowej w katalogu WEB-INF/classes i będziemy się do niego odwoływać w Springu tak:
<lang:defaults refresh-check-delay="1000"/>
<lang:groovy id="myBean" source="classpath:Bean.groovy"/>
... to po pierwszym wczytaniu Tomcat umieści plik Bean.groovy w cache i do restartu go nie ruszy. Co ciekawe Spring potrafi zauważyć zmianę daty ostatniej modyfikacji pliku i próbuje go ponownie wczytać, ale ClassLoader cały czas zwraca pierwotnie wczytaną wersję. Wystarczy przenieść plik do WEB-INF i zmienić wpis w konfiguracji na:
<lang:defaults refresh-check-delay="1000"/>
<lang:groovy id="myBean" source="/WEB-INF/Bean.groovy"/>
... by wszystko wróciło do normy. Spring wczytuje wtedy plik za pośrednictwem ServletContextu a nie ClassLoadera i dostaje zaktualizowaną wersję. Howgh.
Share:

2010-08-26

Groovy 1.7.0 i Spring

W jednej z aplikacji które popełniłem, używam skryptów Groovy jak kontrolerów Spring MVC. Jest to wygodne w sytuacji, kiedy kod kontrolera często się zmienia a nie ma możliwości restartu całej aplikacji. Dzięki poniższej definicji:

komponent some.Controller będzie automatycznie przeładowywany (czyli skrypt będzie ponownie kompilowany) jeżeli plik źródłowy Script.groovy się zmieni (ale nie częściej niż podany czas - tutaj 1000 ms). Wszystko działało tak jak powinno do momentu upgrade'u Springa do wersji 3.0.0.RELEASE - wtedy aplikacja przestała zauważać zmiany w skryptach. Uznałem, że chwilowo mogę bez tego żyć a w wersji 3.0.1 pewnie poprawią. Kiedy jednak po kolejnych uaktualnieniach doszedłem do wersji 3.0.3 i dalej nie było ani trochę lepiej, zacząłem intensywniej szukać. Okazało się, że Spring jest niewinny a problemy sprawia sam Groovy, którego wersję podniosłem do 1.7.0 na fali ogólnego uaktualniania aplikacji (w zależnościach Springa jest 1.6.3). Aby dynamiczne przeładowywanie zaczęło znowu działać trzeba albo cofnąć się do wersji 1.6.x, albo użyć najnowszego Groovy (w tej chwili 1.7.4). Dla zainteresowanych zgłoszenie w JIR-ze GROOVY-3981.
Share:

2008-01-10

Groovy i Hibernate w jednym stali domu

Postanowiłem w pewnej Bardzo Dużej Aplikacji Webowej podnieść wersję Groovy z 1.0 na 1.5. Bo w 1.5 są adnotacje, typy generyczne, typy wyliczeniowe oraz jakże mile widziane w naszej korporacji "significant performance gains".

Sama zmiana wersji jest banalna. Projekt jest budowany Mavenem, więc zmieniamy w pom.xml wersję z 1.0 na 1.5.1 i przy okazji identyfikator grupy z groovy na org.codehaus.groovy (reorganizacja w centralnym repozytorium). Potem mvn install i za chwilę mamy gotową aplikację. Aplikację, która nie chce się deployować.

Okazuje się, że Groovy 1.5, a konkretnie znajdująca się w jego zależnościach biblioteka ASM 2.2 wywołuje konflikt z cglib 2.1_3. Cglib jest wykorzystywana przez Hibernate, a w rzeczonej aplikacji Hibernate jest kluczową technologią. Po zmianie ASM na wersję 1.5.3 działającą z cglibem przestaje działać Groovy, więc nie tędy droga. Rozwiązaniem jest użycie wersji cglib-nodep, która nie wymaga ASMa (a dokładnie klasy ASMowe, przeniesione do innych pakietów, ma włączone do swojego kodu).

Pewnym problemem jest Maven - artefakty cglib 2.1.3, asm 1.5.3 i asm-attrs 1.5.3 są w zależnościach Hibernate. O ile zmianę wersji ASMa możemy wymusić za pomocą dependency management:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-attrs</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
</dependencyManagement>

to zmiana cglib na cglib-nodep wymaga wykluczenia cglib z zależności Hibernate i dodania cglib-nodep jako nowej zależności:
<dependencies>
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate</artifactid>
<exclusions>
<exclusion>
<groupid>cglib</groupid>
<artifactid>cglib</artifactid>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupid>cglib</groupid>
<artifactid>cglib-nodep</artifactid>
<version>2.1_3</version>
</dependency>
</dependencies>

Nie jest to rozwiązanie do końca eleganckie. Konieczna jest modyfikacja (i późniejsze pilnowanie) zależności Hibernate we wszystkich projektach wchodzących w skład aplikacji. Jednak w następnej wersji (3.2.6) problem ma być załatwiony - Hibernate będzie wykorzystywać cglib 2.2 i ASM 2.2 (zgłoszenie HHH-2875).

[aktualizacja 2008.03.03]

8. lutego została wydana wersja 3.2.6, jednak nie ma w niej zapowiadanej poprawki - została przesunięta na wersję 3.3, czyli bliżej nieokreśloną przyszłość.
Share: