Filtrowanie preferowanych pakietów i zasobów na serwerze WebLogic przy pomocy REGEX
Serwer aplikacyjny Javy EE WebLogic oferuje możliwość nadpisania bibliotek dostarczanych standardowo przez kontener.
Funkcjonalność ta opera się o deskryptor weblogic.xml
umieszczany w folderze WEB-INF
artefaktu WAR lub deskryptor weblogic-application.xml
umieszczany w katalogu META-INF
archiwum EAR.
W dokumentacji znajdziesz przykłady użycia elementów prefer-application-packages
i prefer-application-resources
odpowiednio dla ładowania klas i zasobów.
Przykładowe filtry czasami kończą się (a czasami nie) sufiksem .*
, przypominając formatem REGEX, bądź GLOB.
Dokumentacja jednak nie wyjaśnia szczegółów tego formatu, które są znaczące, gdy chcemy zaaplikować złożone filtrowanie.
<wls:container-descriptor>
<wls:prefer-application-packages>
<wls:package-name>com.sample.*</wls:package-name>
</wls:prefer-application-packages>
</wls:container-descriptor>
Czy powyższa konfiguracja preferuje klasy z pakietów com.sample
, com.sample.example
, com.sample.example.subexample
czy jedną z takich kombinacji?
W jaki sposób skonfigurować dopasowanie dla wszystkich pakietów z com.sample.*
oprócz com.sample.example
?
Czy możemy przefiltrować klasy z dokładnością do pełnej nazwy, czy funkcjonalność dotyczy jedynie pakietów (wnioskując od nazwy elementu)?
WebLogic FilteringClassLoader
Odpowiedź na wszystkie pytania znajdziesz, szukając klasy FilteringClassLoader
wśród zależności dostarczanych przez WebLogica.
Nazwa ta jest bowiem widoczna przy użyciu narzędzia Classloader Analysis Tool.
Natrafisz na nią już w bibliotece klienckiej obsługi protokołu T3 ${WL_HOME}/server/lib/wlthint3client.jar
, dokładniej w pakiecie weblogic.utils.classloaders
.
Artefaktu niestety nie znajdziesz w repozytorium mavenowym ze względów licencyjnych. Alternatywą weryfikacji biblioteki oprócz instalacji serwera we własnym zakresie jest jej wypakowanie z kontenera oficjalnego obrazu dockerowego:
#!/bin/bash
# Login, review and accept license at https://container-registry.oracle.com/ > Middleware > weblogic
docker login container-registry.oracle.com
image=container-registry.oracle.com/middleware/weblogic:14.1.1.0-dev
sourcePath=/u01/oracle/wlserver/server/lib/wlthint3client.jar
destinationPath=./
containerId=$(docker create "$image")
docker cp "$containerId:$sourcePath" "$destinationPath"
docker rm "$containerId"
Przekładając kod bajtowy klasy weblogic.utils.classloaders.FilteringClassLoader
na poszczególne kroki, algorytm filtrowania zdaje się wyglądać następująco:
- Wczytaj wyrażenia z deskryptora i usuń końcowy znak
*
ze wzorca; - Dodaj
{0,1}
jeśli wzorzec kończy się na.
; - Poprzedź wzorzec znakiem
^
; - Utwórz
java.util.regex.Pattern
i wywołajmatcher(String)
dla pełnej nazwy klasy/zasobu wyszukując wzorca metodąfind()
. - Jeśli nie znaleziono dopasowania, to oddeleguj ładowanie
loadClass/getResourceInternal/getResource/getResources
do classloadera-rodzica, w przeciwnym wypadku zwróć klasę/zasób dostarczoną przez aplikację.
Z powyższego wynika, że elementy prefer-application-packages
i prefer-application-resources
pozwalają na dokładne filtrowanie pakietów i zasobów, jak również poszczególnych klas za pomocą REGEXów.
Warto tu zwrócić uwagę na jego automatyczną modyfikację względem początku i końcowych znaków *
i .
.
Do wzorca nie jest dodawany znak końca linii, co w połączeniu z wykorzystaniem metody find()
zwiększa liczbę filtrowanych pakietów dzięki częściowemu (w alternatywie do funkcji matches()
) dopasowaniu.
Dodatkowo separator pakietów działa tutaj jako dopasowanie dowolnego znaku co na pierwszy rzut oka może nie być jednoznaczne i bardzo rzadko prowadzić do zbyt szerokiego filtrowania.
Ostatecznie mechanizm pozwala na zdefiniowanie wyrażenia regularnego, które pominie podpakiet, który chcemy pozostawić do załadowania ze zbioru bibliotek dostarczanych przez WLS (np. ^com.sample(?!\.example$)
).
Z drugiej jednak strony pamiętaj o stosowaniu prostych wyrażeń. Nadmierny backtracking, czyli cofanie się w celu sprawdzenia wielu możliwych kombinacji dopasowania, może prowadzić do wydłużenia czasu inicjalizacji aplikacji.