Spring Konzepte und Annotationen

Das Spring Framework erlaubt die schnelle Umsetzung von robusten, leicht wartbaren Enterprise Applikationen basierend auf der Umsetzung zahlreicher Design Pattern sowie einem modularen Design.

Spring basiert insgesamt auf 20 Modulen aus den Bereichen Datenhaltung, Web, Aspect-oriented programming (AOP), Aspects, Instrumentation, Messaging, Testing sowie dem Core Container [4].

Ein wichtiges in Spring [3] umgesetztes Design Pattern ist Inversion of Control (IOC).

Objekte, die vom Spring IOC Container gemanagt (initialisiert, konfiguriert und zusammengestellt) werden, werden Beans genannt.

IOC wird, benannt nach Martin Fowler, auch Dependency Injection (DI) genannt. Hierbei definieren Objekte ihre Abhängigkeiten zu anderen Objekten, wobei der IOC Container diese zur Laufzeit mit Hilfe den gegebenen Konfigurationen und Metadaten auflöst.

DI führt zwangsweise zu übersichtlicherem Code und loser Kopplung zwischen Klassen. Im folgenden sind die wichtigsten Spring Boot Annotationen und kurze Erklärungen aufgeführt.

Dependency Injection

@Required wird für DI über Setter-Methoden für eine Bean Property angewandt die zwingend beim Startup (Configuration time) instantiiert werden müssen. Damit werden später auftretende NullPointerException abgewendet.

@AutoWired teilt Spring mit, wo es mittels Injection Objekte in andere Klassen einfügen soll. Die Injection erfolgt über den Typ des Objekts. Standardmäßig werden diese Abhängigkeiten als required angesehen, mittels @Autowired(required=false) kann man dieses Verhalten jedoch ausschalten. Pro Klasse kann nur ein Konstruktor required sein.

@Primary definiert eine Bean als priorisiert für den Autowire-Vorgang, wenn mehrere Kandidaten zur Verfügung stehen würden.

@Qualifier("name") erlaubt, den Autowire-Vorgang noch genauer zu spezifizieren. So kann man eine Bean mittels eines Qualifiernamens mit einem Konstruktorargument zusammenschalten. Der selbe Name darf mehrfach vergeben werden.

@Resource("beanName") kombiniert @AutoWired und @Qualifier(“beanName”). Die Injection erfolgt über den eindeutigen Namen. Es ist jedoch nur für Felder und Bean Setter-Methoden mit einem einzigen Argument anwendbar.

@Lazy erlaubt seit Spring 3.0 Beans lazy zu laden, d.h. diese werden nicht bereits beim Applikationsstart sonder erst bei Benutzung erzeugt.

Klassen-/Methoden-Annotationen

@Repository für DAO (Data Access Object) Klassen. DAO stellt ein Pattern dar, dass auf einheitliche Weise den Zugriff auf Datenquellen kapselt (Datenbanken, XML-Files, etc.).

@Component ist ein generischer Stereotyp für eine Bean, also Klassen die weder Service noch Repository sind. Die Annotationen @Controller, @Service und @Repository stellen Spezialisierungen dieser Annotation dar.

@Service markierte eine Klasse als Dienstklasse, ist also ein Spezialform der @Component-Annotation.

@Configuration markiert eine Klasse als Konfigurationsklasse für Bean Definitionen. Dies bietet den Vorteil, dass Abhängigkeiten zwischen Beans definiert werden können. @ComponentScan erlaubt zusätzlich das automatische Auffinden von Beans. Des Weiteren können Init und Destroy-Methoden von Beans mittels @Bean(initMethod = “init”) und @Bean(destroyMethod = “destroy”) definiert werden. Mittels @Import und @ImportResource können weitere Konfigurationklassen geladen werden.

@Scope("name") definiert den Lebenszyklus einer Bean [2], u.a. singleton (es kann nur eine Instanz erzeugt werden), request (gültig für eine einzelne HTTP-Anfrage), session (gültig für eine HTTP-Session), prototype (Bean Definition wird auf eine beliebige Anzahl von Objektinstanzen angewandt). Es können ebenso die Klassenannotationen @RequestScope, @SessionScope, usw. genutzt, sowie eigene Scopes definiert werden. Der Defaultwert ist singleton, wobei die Bean erzeugt wird wenn der Container erzeugt wird (im Gegensatz zur Lazy-Initialisierung zum Zeitpunkt der ersten Nutzung). Singleton wird typischerweise für stateless, prototype für stateful Beans genutzt.

@Transactional annotiert Methoden oder Service-Klassen, die Geschäftslogik umsetzen.

@Bean("name") markiert eine Methode, die ein Bean-Objekt erzeugt, konfiguriert und initialisiert, die vom Spring IOC Container im ApplicationContext verwaltet werden soll. Der Container weiß somit wie die Bean erzeugt werden soll (lazy), welche Lifecycle-Constraints gelten (init, destroy) und wie deren Abhängigkeiten zu anderen Beans ist. @Bean wird typischerweise in @Configuration-Klassen genutzt. In anderen Klassen markiert sie einfache Factory-Methoden. Der Name der Bean ist identisch mit dem Klassenname, sofern nicht händisch ein oder mehrere andere Bezeichner gewählt werden. Besitzt eine Bean eine Methode names close() oder shutdown() werden diese automatisch beim beenden des Containers ausgeführt.

@PostConstruct und @PreDestroy erlauben eigenes Verhalten beim Erzeugen und Beenden einer Bean zu definieren.

@Order und @Priority um Elemente in einem Array oder Liste in einer bestimmten Weise zu sortieren.

Sprint Boot Annotationen

@EnableAutoConfiguration wird normalerweise auf die Hauptklasse der Anwendung angewandt. Damit wird Spring Boot der Einstiegspunkt für die Suche nach Beans mitgeteilt.

@SpringBootApplication wird der Hauptklasse der Anwendung zugewiesen, die im Top-Level-Paket liegen muss. Spring Boot wird dadurch alle Unterordner scannen. @SpringBootApplication kombiniert @Configuration, @EnableAutoConfiguration und @ComponentScan.

Attribut-Annotationen

@Value("#{...}") definiert den Standardwert für einen Parameter mit dem dieses erzeugt wird. Es kann auch dazu benutzt werden, um ein Attribut mit dem Wert aus einer Konfigurationswerte zu initialisieren.

@PropertySource erlaubt das Auslagern der Konfiguration in eine oder mehrere Dateien, wie zum Beispiel config.properties. Diese würde mittels @PropertySource("classpath:config.properties") eingebunden werden. Die Zuweisung an eine Variable im Code erfolgt mittels @Value("${my.variable}") oder per env.getProperty("my.variable").

Spring MVC Annotationen

@Controller markiert eine Klasse als Controller (bzw. Servlet). Diese Klasse wird automatisch nach @RequestMapping Annotationen durchsucht.

@RequestMapping(path="URL", method=RequestMethod.{GET|POST|PUT}) bildet URLs auf Klassen oder Methoden ab. Bei Anwendung auf einer Klasse definiert es den Basispfad für Anfragen des Controllers. Angewandt auf eine Method, definiert es die URI durch den die Methode ausgeführt wird. Typischerweise bilden die Klassenannotationen auf einen Form-Controller ab.

Seit Spring 4.3 sind auch kurze Varianten verfügbar: @GetMapping, @PostMapping, @PutMapping, @PatchMapping, @DeleteMapping.

@ExceptionHandler bestimmt auf Methodenlevel wie Ausnahmen im Controller behandelt werden. Sie definiert welcher Typ von Ausnahme (oder Typen) gefangen und von der Methode behandelt werden soll.

@PathVariable wird auf ein Methodenargument angewandt um den Wert einer URI Templatevariable auf das Attribut abzubilden.

@RequestMapping(value = "{id}", method = RequestMethod.GET)
public Customer getCustomer(@PathVariable int id) {...}

Beispielhafter Aufrufpfad: /customers/1

@RequestParam bildet Anfrageparameter in der URL auf Methodenvariablen im Controller ab.

@RequestMapping(value="/add", method = RequestMethod.PUT)
public void createCustomer(@RequestParam("id") int id, @RequestParam String preName, @RequestParam String surName) {
    Customer customer = new Customer(id, preName, surName);
    this.customers.add(customer);
}

Beispielhafter Aufrufpfad: /customers/add?id=3&preName=A&surName=B (Case Sensitive!)

@RequestBody annotiert Methodenargumente von Anfragehandlern und deutet an, dass diese auf den Werte des HTTP Anfrage-Body gebunden werden sollen.

@RequestHeader annotiert Methodenargumente von Anfragehandlern und deutet an, dass diese auf den Wert des HTTP Anfrage-Header gebunden werden sollen.

javax.inject.*

Dieses Paket bietet Dependency Injection für Java an.

@Inject kann anstelle von @Autowired für Attribute, Methoden und Konstruktoren verwendet werden. Um einem abhängigen Attribut einen Qualifier mitzugeben, verwendet man in diesem Fall @Named("...").

Weitere Annotationen dieses Pakets sind @ManagedBean, @Singleton und @Qualifier.

Spring Cloud Annotationen

@EnableConfigServer startet einen zentralen Konfigurationsserver mit dem die anderen Anwendungsdienste kommunizieren können. Dieser Ansatz spielt seine stärken besonders bei verteilten Systemen aus. Die Annotation wird auf Klassen angewandt.

@EnableEurekaServer aktiviert den Discovery-Service. Dieser erlaubt den Microservices sich gegenseitig zu finden. Diese Annotation wird auf die Hauptklasse angewandt.

@EnableDiscoveryClient stellt das Gegenstück zu @EnableEurekaServer dar. Die Annotation wird auf der Einstiegsklasse der Anwendung angewandt. Damit wird dem Service gesagt, dass er sich bei Eureka zu registrieren hat.

@EnableCircuitBreaker wird auf Klassen angewandt, die als “Schutzschalter” agieren sollen, d.h. diese Klasse beobachtet, öffnet und schließt diesen. Dabei kann das kaskadierende Fehlschlagen mehrere Microservices verhindert werden.

@HystrixCommand wendet das Circuit-Breaker-Pattern auf Methoden an. Hiermit reagiert Hystrix auf Fehler bei deren Ausführung und aktiviert ggf. den Schutzschalter. Dabei werden die Aufrufe auf eine Fallback-Method umgeleitet.

Ausblick

Diese Zusammenfassung ist bei Weitem nicht vollständig. Es fehlen etwa die Annotationen DataAccess, Taskausführung und Scheduling, sowie Testen.

Vielen Annotationen können zudem Parametrisierungen mitgegeben werden. Diese wurden hier der Übersichtlichkeit halber weitestgehend außer acht gelassen.

Weitergehende Quellen

[1] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-annotation-config/

[2] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-scopes

[3] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/index.html

[4] http://docs.spring.io/spring/docs/current/spring-framework-reference/html/overview.html#overview-modules