Die Template Engine Thymeleaf kann über Fragments bestimmte Blöcke einer HTML Datei verarbeiten. Fragmente können z.B. eingefügt oder ersetzt werden.

Bootstrap CSS Beispiel

Damit Bootstrap CSS auf den Seiten funktioniert, müssen im Header JS und CSS Dateien eingebunden werden. Ansonsten funktioniert Bootstrp CSS nicht korrekt oder der Inhalt wird nicht wie gewünscht angezeigt. Da dieses immer wieder der selbe Block an Anweisungen ist, ist es ein idealer Kandidat, um ihn zu inkludieren.

Wo werden Fragmente abgelegt?

Thymeleaf Fragmente werden üblicherweise unter templates/fragments abgelegt.

Wie wird ein Fragment gekennzeichnet?

Ein Fragment wird im HTML Code mit th:fragment=”name” gekennzeichnet.

<html xmlns:th="http://www.thymeleaf.org">
<head>
    <div th:fragment="header-css" th:remove="tag">
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <!-- Bootstrap -->
        <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
    ...
    </div>
</head>

In unserem Header hat das Fragment den Namen header-css. Das th:remove Attribut hat hier eine besondere Funktion. Später mehr dazu.

Umsetzung mit Thymeleaf Fragments

Das HTML das an den Browser ausgeliefert werden soll, muss natürlich valide sein. So soll das fertige Ergebnis aussehen:

<!DOCTYPE HTML>
<html>
<head>
<title>Hallo Welt !!!</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- Bootstrap -->
<script src="/webjars/jquery/3.3.1-1/jquery.min.js"></script>
<script src="/webjars/popper.js/1.14.3/umd/popper.min.js"></script>
<link href="/webjars/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" />
<script src="/webjars/bootstrap/4.1.3/js/bootstrap.min.js"></script>
</head>

...

Inkludierung des Fragments

Das Fragment soll uns nun den oben gekennzeichneten Block einfügen. Das Thymeleaf Attribut th:replace benötigt 2 Angaben. Die erste Angabe ist der Dateiname die das Framgent enthält und nach dem :: den Namen des Fragments. Hier also wird in dem Verzeichnis fragments nach der Datei header.html gesucht, welche das Fragment header-css enthält.

Daraus ergibt sich folgender Code:

<head>
<title>Customers</title>
<title th:replace="fragments/header.html :: header-css"></title>
</head>

Hier muss man einen kleinen Trick anwenden, da nur wenige Elemente im HEAD erlaubt sind, damit wir in der IDE keine Warnungen angezeigt bekommen. Wir verwenden einfach einen zweiten TITLE-Tag und ersetzen den Inhalt mit dem Fragment header-css. Das zusätzliche Attribut th:remove=”tag” in dem Fragment sorgt nun dafür dass das umschließende Tag entfernt wird und nur der gewünschte Inhalt im gerenderten Template ausgeliefert wird.

Wer hat sich nicht schon Mal gefragt, was die Blackbox Hibernate im Hintergrund so alles macht?

Statistiken

Statistiken von Hibernate

Hibernate umfangreiche Statistiken für uns erstellen, um zum Beispiel besser zur verstehen warum es an der einen oder anderen Stelle klemmt. Die automatische Erstellung der Statistiken im Hintergrund nagt natürlich an der Performance der Anwendung und sollte daher nur in der Entwicklung verwendet werden. Zu Testzwecken kann das Feature gegebenenfalls auch auf einem PreProduktion System aktiviert werden, damit man eine realere Umgebung Simulieren kann.

Um das Feature zu aktivieren muss man generate_statistics auf true setzen. Dieses kann über die persistence.xml erledigt werden.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    ...
    <persistence-unit name="default" >
         <properties>
         ...
             <property name="hibernate.generate_statistics" value="true" />
         ...
         </properties>
    </persistence-unit> 
</persistence>

Um nicht die persistence.xml zu modifizierem, welche mit deployt wird, sollte man für die Testfälle besser die System Properties anpassen. Diese über das Kommandozeilenparameter -D

java -jar app.jar -Dhibernate.generate_statistics=true

oder in der IDE angegeben werden:

Spring Boot

Möchte man das Feature unter Spring Boot verwenden und trägt das so in die application.properties ein, dann wird das nicht funktionieren. Um die Properties an den JPA Provider (hier also Hibernate) zu übergeben, muss dieses in einen Prefix in der application.properties bekommen. In dem Fall von Hibernate ist das spring.jpa.properties.hibernate.

# Generate additional statistics. Do not use in production
spring.jpa.properties.hibernate.generate_statistics=true

Statistiken

Wenn man wie oben beschrieben die Generierung der Statistiken aktiviert hat, dann bekommt man eine nette Ausgabe auf der Konsole zu den abgesetzten Queries zur Datenbank.

40999 nanoseconds spent acquiring 2 JDBC connections;
25173 nanoseconds spent releasing 1 JDBC connections;
327100 nanoseconds spent preparing 3 JDBC statements;
1215257 nanoseconds spent executing 3 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
901269 nanoseconds spent executing 1 flushes (flushing a total of 1 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)

Queries

Queries formatieren

Normalerweise werden die Queries inline geloggt. D.h. je Zeile ein Query. Das macht insgesamt das Log gut lesbar, aber dafür sind die SQL Queries um so schlechter zu lesen. Auch hierfür bietet Hibernate eine Lösung an. Man kann die Ausgabe der Queries im Log formatieren lassen. Auch hier gilt natürlich der Grundsatz, dieses nicht in Produktion zu verwenden. Setzt man format_sql auf true, dann erhält man eine Mehrzeilige, formatierte Ausgabe der Queries in dem Log.

Hibernate: 
   create table customer (
       id bigint not null,
        lastname varchar(50),
        name varchar(50),
        primary key (id)
    ) engine=MyISAM

In der application.properties trägt man analog zu dem obigen Beispiel es mit dem Prefix spring.jpa.properties.hibernate ein.

# Prettify Hibernate SQL Queries in log
spring.jpa.properties.hibernate.format_sql=tru

Binding Parameter

Parameter der Queries

Mit den beiden oben genannten Methoden kann man schon sehr viel Informationen aus dem Log von Hibernate entnehmen. Eine wichtige Zutat um das Geheimnis der Blackbox Hibernate zu lüften fehlt allerdings noch. Man kann zwar jetzt die konkreten Queries im Log sehen, aber man kann nicht erkennen welche Parameterwerte gebunden sind.

Konfiguration von Spring Boot

Mit dem sogenannten Tracing kann man sich die Werte der Parameter mit in dem Log ausgeben lassen. Gesteuert wird das Ganze über den Hibernate Type. Dieser muss auf Trace gestellt werden:

# Show binding parameter values
logging.level.org.hibernate.type=trace

Die Ausgabe im Log erscheint dann wie folgt:

Hibernate: 
    insert 
    into
        customer
        (lastname, name, id) 
    values
        (?, ?, ?)
2018-11-15 12:54:47.652 TRACE 6971 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [Bernhard]
2018-11-15 12:54:47.652 TRACE 6971 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [Lisa]
2018-11-15 12:54:47.652 TRACE 6971 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [BIGINT] - [11]

Jooq 3.11.7

Seit meinen letztem Beitrag über das Release von Jooq 3.11.0 sind jede Menge Fehler behoben worden und auch ein paar neue Features hinzugekommen. Die wichtigsten Änderungen möchte ich hier in diesem Beitrag kurz zusammenfassen.

Mit der Version 3.11.7 ist es jetzt die 7. Aktualisierung des Java SQL DSL Framework seit der Veröffentlichung von 3.11.0.

Neue Features in 3.11.2

  • Keine alten XSDs mehr Mit dem Release 3.11.2 werden keine alten XSD Dateien mehr in den Binary’s ausgeliefert.

  • Disable ORDER BY in emulierten OFFSET … FETCH Paginierung Klauseln In Datenbanken die OFFSET … FETCH nicht unterstützen, wird seit Jahren das Verhalten emuliert. Da Datenbanken aus einer Window Funktion die Sortierung nicht garantieren, wird diese im äußeren Query durchgeführt. Die Erfahrung hat gezeigt, dass das oft nicht nötig ist. Als kleiner Performance Tweak kann daher die Sortierung jetzt abgeschaltet werden.

  • Anzahl der Rows wird im LoggerListener wieder ausgegeben Mit dem Commit wurde das Verhalten geändert. Das ursprünglich Verhalten wurde wiederhergestellt und die Anzahl der Rows geloggt.

Neue Features in 3.11.5

  • Der Parser liest nun CREATE INDEX .. ON .. USING btree

Neue Feature in 3.11.6

Bugfixes seit 3.11.0

Seit dem Release sind mehr als 70 Fehler behoben worden. Eine vollständige Liste der Änderungen gibt es in den Release Notes.

Link fehlerhaft

Aktuell besteht ein Bug in dem ansonsten so nützlichen Live Hover Informationen in Spring Tool Suite 4. Viele Anwendungen laufen ohne einen speziellen Application Context, so dass die Anwendung unter / erreichbar ist.

# Set application context path
server.servlet.context-path=/spring-mvc-thymeleaf-demo

Setzt man allerdings einen Application Context, dann ist der anzeigte Link fehlerhaft. Es fehlt der Path unter dem die Anwendung läuft, d.h. der Link funktioniert effektiv nicht (siehe Bild unten).

Bugfix

Mit dem nächsten Punktrelease ist Abhilfe in Sicht. Unter Issue 129 wird das Ticket bearbeitet. Dann sollte der Live Hover Bug behoben sein.

PasswordEncoder

Ohne weiteres Zutun legt Spring Security die Passwörter unverschlüssel ab. Das sollte heute aber nicht mehr der Fall sein, da zum Beispiel wenn die Passwörter der Benutzer in einer Datenbank gespeichert werden diese bei einem Einbruch als Plaintext vorliegen. Daher werden (sollten / es gibt immer wieder Beispiele die das Gegenteil beweisen) die Passwörter verschlüsselt abgelegt. Dieses kann zum Beispiel ein Hash des Passwortes sein.

Um Spring Security flexible zu gestalten, kann man zur Laufzeit einen PasswordEncoder setzen. Die Einstellungen die die Sicherheit einer Spring Anwendung betreffen, werden in einer WebSecurityConfigurerAdapter erweiterten Konfiguration vorgenommen. Hierfür muss die Einstellung für die Authentifikation geändert werden. Dafür die ist die Methode passwordEncoder() verantwortlich.

Als ein guter Kandidat für die verschlüsselte Ablage ist BCrypt. In Spring Security implementiert die Klasse BCryptPasswordEncoder den BCrypt Algorithmus.

Damit dieses per DI injeziert werden kann, benötigen wir eine Bean die uns den BCryptPasswordEncoder liefert.

@Bean PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

Jetzt kann ein PasswordEncoder per @Autowired zur Laufzeit gesetzt werden und als Parameter für passwordEncoder() Funktion dienen.

@Autowired
private PasswordEncoder passwordEncoder;

Grundgerüst einer Anwendung

Dependency

Als Abhängigkeit ist natürlich spring-boot-starter-security einzufügen.

dependencies {
    // Spring Boot
    ...
    implementation('org.springframework.boot:spring-boot-starter-security')
    ... 

Konfiguration WebSecurityConfigurerAdapter

Hier ein sehr simples Beispiel mit einer in Memory Benutzerauthentifizierung. Ich glaube jeder hat schon einmal die verwendeten Benutzernamen und Passwörter gesehen… 🙂

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Bean PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .passwordEncoder(passwordEncoder)
            .withUser("user")
            .password("$2a$10$9z954e6ETmwauiiBbwCNbOwU90UnUrh9hpRUWwNmWUx6aFic2nE46") // user
            .roles("USER")
                .and()
            .withUser("admin")
            .password("$2a$10$Tljz0HJByMV97Y92B65QBu0TckqbJDlT1kgmibMijhbMtpHPORanK") // admin
            .roles("ADMIN");
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                .antMatchers("/admin/**").hasAnyRole("ADMIN")
                .anyRequest().hasAnyRole("USER").and()
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/allcustomers")
                .permitAll();
    }
}

SQLite Dialect

Um Hibernate zur Zusammenarbeit mit SQLite zu bewegen, gibt es seit kurzem ein Release für https://github.com/gwenn/sqlite-dialect auf Maven. D.h. es kann direkt über Maven Central bezogen werden. Früher wurde das Programm nur über Jitpack.io verteilt, was zusätzliche Konfiguration im Buildskript erforderte.

Nun kann man die beötigten Abhängigkeiten mit 2 Zeilen hinzufügen:

// SQLite
compile('org.xerial:sqlite-jdbc:3.25.2')
compile('com.github.gwenn:sqlite-dialect:0.1.0')

Jetzt muss nur noch Konfiguration angepasst werden:

spring:
  datasource:
    url: jdbc:sqlite:empty.db

oder

spring.datasource.url=jdbc:sqlite:empty.db

Nun sollten in der Anwendung erstellte Repositories auf der SQLite Datenbank arbeiten.

Lombok 1.18.4

Am 30.10.2018 ist die neue Version 1.18.4 von Lombok erschienen. Wie immer sind einige Bugs in Zusammenhang mit Java Versionen größer 9 behoben worden. Es sind aber auch inkompatible Änderungen vorgenommen worden. Das Jar kann von hier runtergeladen werden.

Lombok unterstützt nun Eclipse Photon. Der lombok.patcher verwendete OpCodes.ASM4, welches nun nicht mehr von Eclipse verwendet wird. Eclipse verwendet nun invoke dynamic.

Inkompatible Änderungen

  • FieldNameConstants wurden aufgrund eines Tickets neu redesigned. Das Feature bleibt weiterhin als experimentel gekennzeichnet, da noch nicht klar ist, ob es wirklich eine Verbesserung der Lesbarkeit mit sich bringt. Dokumentation FieldNameConstants.

  • Lombok kopiert nun immer bestimmte Annotationen, damit das Verhalten nicht verloren geht. Z.B. @NonNull.

Weitere Änderungen und neue Features

Alle Änderungen sind im https://projectlombok.org/changelog zu entnehmen.

Swap ohne Platz für eine extra Partition

Wer kennt das nicht, ein vorkonfigurierter Rechner, der auch nicht geändert werden darf, hat keine expliziete Swap-Partition für Linux. Auch wenn die Workstation 8GB Arbeitsspeicher besitzt, kann es jedoch sehr schnell eng werden mit dem RAM.

Abhilfe?

Linux kann auf Swap Files verwalten. Analog zu den Partitionen, kann man diese während des Betriebes ein- und aushängen. Dazu dient swapon und swapoff.

Beispiel

Ich benötige auf der Workstation ca. 4GB Auslagerungsspeicher.

sudo fallocate -l 4096M /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

Mit fallocate allozieren wir 4GB mit der 4096M Angabe. Dann werden die Dateirechte gesetzt. Jetzt muss die Datei nur noch in Swap File gewandelt werden. Hierfür dient mkswap. In der /etc/fstab muss nun nur noch ein Eintrag hinzugefügt werden und Systemd hängt beim nächsten Systemstart das Swap File aufmatisch ein.

/swapfile none swap defaults 0 0

Am 31.10.2018 wurde das Update Release von Spring Tool Suite 4 in der Version 4.0.1 veröffentlicht. Der Download steht unter https://spring.io/tools zur Verfügung oder über Updates innerhalb der Eclipse Installation.

Spring Bugfixes

  • NPE innerhalb des SpringIndexer
  • Spring Boot configuration property auto-completion bietet keine Properties der Super Klassen an
  • Jede Menge NPEs im Language Server behoben
  • Live Boot Hint Decorators funktionieren nicht, wenn in der Anwendung ObjectMapper mit NON_DEFAULT vorhanden ist
  • Property Support funktioniert nun auch mit verschachtelten Projektstrukturen

Eclipse

  • Support für das neue Buildship (Gradle Plugin) in der Version 3.0
  • Eclipse enthält nun auch wieder Server Adapters für Apache Tomcat

Full Changelog

Alle Änderungen finden sich wie immer im Wiki.

Spring Boot 2.1.0

Am 30.10.2018 wurde Spring Boot 2.1.0 als erstes Punktrelease veröffentlicht. Auch diesmal gibt es wieder jede Menge interessante und wichtige Neuerungen in dem beliebten Java Framework.

Welche Frameworks wurden geupdatet?

Zunächste wollen wir uns einen Überblick über die geänderten Abhängigkeiten von Spring Boot 2.1.0 verschaffen:

  • Hibernate 5.3
  • Micrometer 1.1
  • Reactor Californium
  • Spring Data Lovelace
  • Spring Framework 5.1
  • Tomcat 9
  • Undertow 2

Performance Verbesserungen

Als Teil der anhaltenden Bemühungen die Performance von Spring Boot Anwendungen stetig zu steigern, wurde teilweise ein signifikater Fortschritt erziehlt bei den Startupzeiten und dem Speicherverbrauch.

Wie bereits in dem Artikel Spring Boot 2.1 Changelog beschrieben, können Anwendungen jetzt im sogenannten deferred Mode von Spring Data JPA gestartet werden. Dabei wird die Initialisierung (das Bootstrapping) von Hibernate in einen Hintergrund Thread ausgelagert und paralell zur restlichen Initialisierung der Anwendung ausgeführt.

spring.data.jpa.repositories.bootstrap-mode=deferred    

Java 11 Support

Mit dem Update auf Spring Framework 5.1 folgt das Spring Boot 2.1.0 Framework wartet ebenfalls mit der Unterstützung von Java 11 auf. Gleichzeitig wird weiterhin Java 8 als minimale Java Version beibehalten.

In den Properties werden DataSize Angaben unterstützt

In der application.properties können jetzt als Einheiten GB,MB,KB etc. angegeben werden. Ähnlich zu den unter Spring Boot 2.0.0 eingeführten Durations.

Neue Actuator Endpoints

Es wurden neue Actuator Endpoints zur Verfügung gestellt. Ein Endpoint stell Informationen zum CacheManager dar und der zweite Endpoint gibt eine Graph Representation der Komponenten von Spring Integration.

/actuator/caches
/actuator/integrationgraph  

Bean Overriding

Mit dem Release 2.1.0 wird das Überschreiben von Bean per default verhindert. Sollte dieses in der Anwendung weiterhin benötigt werden, so kann dieses über die Property

spring.main.allow-bean-definition-overriding=true

geändert werden.

Änderungen die Spring Security betreffen

Bislang war es so, dass wenn spring security im Classpath vorhanden war, dass ausnahmslos alle Endpoints gesichert waren. Hiervon gibt es jetzt eine Ausnahme! Die Endpoints /info und /health werden wegen der Konsistenz jetzt nicht mehr automatisch gesichert. Sollte diese Endpoints gesichert werden, dann muss dieses expliziet geschehen.

Änderungen im Logging

Mit Spring Framework 5.1 wurden auch Verfeinerungen im Logging vorgenommen. Es sind Spring MVC und Spring WebFlux von den Änderungen betroffen. Möchte man das alte Debuggingverhalten von Spring Boot 2.0.0 wiederherstellen, dann kann das über die Property logging.level.web geschehen.

logging.level.web=debug # altes Verhalten vor Spring Boot 2.1.0 wiederherstellen

Weitere Änderungen

Weitere Änderungen sind im Spring Boot 2.1.0 Changelog zu entnehmen.

Alle Änderungen in diesem Release sind wie immer ausführlich im Release Notes Spring Boot 2.1.0 vorhanden.

Updates der Abhängigkeiten im Einzelnen

An dieses Stelle werde ich kurz auf die wichtigsten Änderungen in den Frameworks eingehen.

Hibernate 5.3.7

Der Changelog von Hibernate ist relativ klein und enthält wenig aufregenes.

Micrometer

Das Update von Micrometer enthält eine Reihe von weiteren Monitorsystemen. Mit AppOptics, Azure Monitor, Dynatrace, Elastic, Humio, KairosDB, Stackdriver, Sysdig, StatsD kommen also insgesamt 9 weitere Monitorsysteme neu hinzu.

Ebenfalls werden neue Metriken für Jetty Server Thread Pool, PostgreSQL Datenbank, Festplattenplatz, Log4J 1.2 und Kafka gesammelt.

Neben den neuen Metriken und den Anbindungen an die Monitorsysteme, werden eine ganze Reihe weiterer Verbesserungen in Micrometer eingebaut.

Spring Reactor Californium

Die Namensgebung für den Releasetrain des Reactor Projects wird nach den Elementen vergeben. Aktuell ist Californium angesagt. Neues hierzu ist in dem Video von der JavaOne zu sehen.