A Match made in Heaven

Aspektorientierte Programmierung (AOP)

Mit AOP ist die zentralisierte Implementierung von Querschnittsbelangen wie Sicherheit, Transaktionen oder Tracing möglich. Ein Aspekt besteht aus einem Advice, der den auszuführenden Code enthält, und einem Pointcut, der festlegt, wo der Advice ausgeführt werden soll. Spring AOP ist zentral für das Framework und wird beispielsweise genutzt, um deklarative Transaktionen zu implementieren. Dabei werden @Transactional-Methoden oder Klassen annotiert, die durch Transaktionen ergänzt werden sollen.

Spring AOP ist nicht sehr effizient, da es Methodenaufrufe dynamisch vornimmt, was einen Performancenachteil mit sich bringt. Die Alternative ist AspectJ, bei dem die Aspekte direkt in den Bytecode hineinkompiliert werden. Eigentlich sollte eine moderne Programmiersprache eine Unterstützung für die Implementierung von Querschnittsaspekten anbieten. Das muss nicht unbedingt AOP sein, dynamische Programmiersprachen erreichen ähnliche Effekte durch Metaprogrammierung. Als Lösung können Scalas Funktionen genutzt werden. Mit ihnen ist es möglich, Methoden, Codeblöcke oder Funktionen beispielsweise um Transaktionen zu ergänzen. Die Nutzung sieht dann folgendermaßen aus:

@Component
class TxCustomerDAO(dataSource: DataSource)
  extends TransactionManagement {
  
  def save(customer: Customer): Customer =
    transactional(propagation=Propagation.REQUIRED) {
      jdbcTemplate.update(.);
  }
}

Mit transactional wird der Codeblock um Transaktionen ergänzt. Dahinter versteckt sich eine Funktion, die als ersten Parameter die Transaktionskonfiguration übernimmt und als zweiten Parameter eine Funktion. Die Funktion ist im konkreten Beispiel der Codeblock in geschweiften Klammern. In der Nutzung ergeben sich praktisch keine Unterschiede zu Springs @Transactional-Annotation. Die Implementierung der transactional-Funktion zeigt Listing 10. Sie übernimmt die Konfiguration der Transaktion mit entsprechenden Default-Werten und eine beliebige Funktion als Parameter func. Anschließend wird ein Spring TransactionTemplate mit der übergebenen Konfiguration erzeugt. Ihm wird ein TransactionCallback übergeben, das die Funktion func aufruft.

Listing 10: Transactional Funktion
def transactional[T]
( propagation: Propagation = Propagation.REQUIRED,
 ...)
(func: => T): T = 
{
  val txAttribute = 
   new TransactionAttributeWithRollbackRules(
     propagation,.)
  val txTemplate =
   new TransactionTemplate(txManager,txAttribute)
  txTemplate.execute(new TransactionCallback[T] {
   def doInTransaction(status: TransactionStatus)
     = func.asInstanceOf[T]
  })
}

Diese Lösung nutzt intern im Gegensatz zu @Transactional nicht Spring AOP, sondern Scala-Funktionen, sodass keine dynamischen Methodenaufrufe genutzt werden und die Lösung performanter sein sollte. Mit Spring AOP kann der Entwickler @Transactional auch so nutzen, dass statt einer Methode eine ganze Klasse annotiert und für die ganze Klasse Transaktionen konfiguriert. Leider können solche Mechanismen mit Scala nicht implementiert werden. Das überrascht, denn eigentlich sollten entsprechende Features in einer modernen Programmiersprache vorhanden sein.

Fazit

Scala und Spring passen gut zusammen – zumal Spring auch sehr gut an sehr verschiedene Kontexte anpassbar ist. Im Bereich Dependency Injection sind bei XML einige Optimierungen möglich – so sollte das Injizieren in Scala Properties möglich sein oder Unterstützung für Scala Objects eingerichtet werden. Bei Annotationen und JavaConfig kann die Nutzung mit Scala sehr einfach und elegant sein. Die Serviceabstraktion profitiert von Scalas Funktionen, die auch eine gute Alternative für Spring AOP darstellen. Allerdings kann Scala nur Verhalten zu Methoden hinzufügen und nicht zu ganzen Klassen.

Unter [1] ist der Bug-Report für den fehlenden Scala-Support in Spring hinterlegt. Er ist zwar schon einem Entwickler zugewiesen, aber noch keiner Spring-Version zugeordnet. Wer Interesse an Scala-Support hat, sollte für diesen Bug-Report stimmen. Der Code für den Artikel einschließlich der Spring-Erweiterungen findet sich unter https://github.com/ewolff/scala-spring. Viel Spaß beim Ausprobieren!

Weitere Arbeiten zu Spring und Scala

Der hier vorgestellte Ansatz ist nur eine Möglichkeit zur Nutzung von Scala mit Spring. Ein anderer Ansatz für Dependency Injection stellt Jan Machacek unter [2] vor. Dabei wird das Cake Pattern aus dem Scala-Kontext mit Springs Dependency Injection kombiniert. Der Blogbeitrag enthält auch Links zu Codebeispielen.

Unter [3] findet sich die Diplomarbeit von Barbara von Kalm zu Scala-Applikationen mit JSF, Spring und Hibernate, die ebenfalls auf die Nutzung von Spring mit Scala eingeht.

Speziell zu AOP und Scala findet sich unter [4] die Präsentation von Ramnivas Laddad von den Scala Days 2011. Sie gibt eine detaillierte Darstellung der Möglichkeiten und Unterschiede von Spring AOP, AspectJ und Scala.

Für das Testen mit Scala gibt es das Specs2-Framework, für das ebenfalls eine Spring-Unterstützung bereit steht [5].

Spring ist mittlerweile viel mehr als nur das Framework. Auch in den anderen Spring-Projekten gibt es Scala-Unterstützung. So gibt es eine Spring DSL für die Konfiguration mit Scala [6], die mittlerweile ein offizielles Spring-Projekt ist und zurzeit in Version 1.0.0M1 zur Verfügung steht. Für Spring Security gibt es zumindest ein Beispielprojekt [7].

Eberhard Wolff (Twitter: @ewolff) arbeitet als Architecture and Technology Manager für die adesso AG in Berlin. Er ist Java Champion, Autor einiger Fachbücher und regelmäßiger Sprecher auf verschiedenen Konferenzen. Sein Fokus liegt auf Java, Spring und Cloud-Technologien.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.