#### Architekturen - Monolith
- Alle Aspekte der Anwendung in einem Projekt
- Keine Trennung zwischen Fachlichkeiten
- Keine externen Abhängigkeiten zur Laufzeit
Architekturen - Modulith
#### Architekturen - Modulith
- Unterteilung der Anwendung in Fachlichkeiten
- Auslagerung der Fachlichkeiten in Module
- Module definieren öffentliche Schnittstellen
- Auslagerung in Form von Package, Modul, Projekt
- Keine Auslagerung zur Laufzeit
- Zusammengeführt durch Kern
Architekturen - Services
#### Architekturen - Services
- Modulith als Kern
- Auslagerung einzelner Module in Services
- Services haben eigene Datenhaltung
Architekturen - Microservices
#### Architekturen - Microservices
- Auslagerung jedes Modules in Services
- Expliziter Kern durch implizite Abhängigkeiten zwischen Services ersetzt
- Services replizieren Daten in eigener Datenhaltung
#### Vergleich - Wartungsaufwand
- Einführung neuer Features
- Entfernung alter Features
- Behebung von Fehler
- Aktualisierung der Abhängigkeiten
- Refactoring
#### Vergleich - Personalaufwand
- Teamgröße sowie Teamanzahl
- Erhöhte Komplexität erfordert mehr Personal
- Mehr Personal erfordert erhöhte Flexibilität
#### Vergleich - Teamgröße
| Monolith | Modulith | Services | Microservices |
|----------|----------|----------|---------------|
Klein | Klein - Groß | Mittel - Groß | Groß - Mehrere
#### Vergleich - Fazit
- Anforderungen und Teamgröße limitieren jeweils Architekturmöglichkeiten
- Architektur aus Deckung der Architekturmöglichkeiten wählen
- Teamgröße muss sich mit Anforderungen decken
#### Vergleich - Fazit
- Monolith für unbekannte Projekte
- Modulith für mehr Wartbarkeit
- Services für Skalierbarkeit
- Microservices für Zuverlässigkeit
### Umsetzung
#### Technologien - Webengineering I
- Servlets
- Rohes HTTP
- Erfordert eigene Implementierung
- JSP
- Implementierung von Servlets
- Ausschließlich HTML
#### Technologien - Webengineering II
- JSF
- Implementierung von Servlets
- Quasi ausschließlich HTML
- ?
- Vollständiges HTTP
- Vielseitige Media-Types
- Einfache Bedienung
#### Technologien - Webengineering II
- JSF
- Implementierung von Servlets
- Quasi ausschließlich HTML
- Spring, Quarkus, Micronaut...
- Vollständiges HTTP
- Vielseitige Media-Types
- Einfache Bedienung
### Spring-Boot
#### Spring
- Application Framework
- Dependency-Injection-Container
#### Spring-Boot
- Basiert auf Spring
- Erweitert um Java EE
- Convention-over-Configuration
- Annotation-Base Configuration
- Spring ursprünglich eigentlich XML
#### Spring-Boot - Bootstrap
```java
@SpringBootApplication
public class MySpringApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringApplication.class, args);
}
}
```
#### Schichten
- Frontend
- Middleware
- Backend
#### Spring Schichten - Frontend
- Schnittstelle zur Außenwelt
- Einordnung
- Wird nicht referenziert
- Referenziert Middleware
#### Spring Schichten - Middleware
- Implementiert Businesslogik
- Einordnung
- Wird von Frontend und Middleware referenziert
- Referenziert Backend
#### Spring Schichten - Backend
- Persistence Ebene / andere Services
- Einordnung
- Wird von Middleware referenziert
- Referenziert nichts
### Frontend
#### Frontend
- Implementierung erfolgt durch Controller
- API in ReST, GraphQL usw.
#### Frontend - Controller
```java
@RestController
public class PersonController {
...
}
```
#### Frontend - Methods
GET /persons
```java
@RestController
public class PersonController {
@RequestMapping(
method = RequestMethod.GET,
path = "/persons"
)
public List<Person> getPersons() {
...
}
}
```
#### Frontend - Methods
POST /persons {"firstName": "John", "lastName": "Doe"}
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@RequestMapping(
method = RequestMethod.POST
)
public void createPerson(@RequestBody Person person) {
...
}
}
```
#### Frontend - Methods
PUT /persons {"firstName": "John", "lastName": "Doe"}
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@RequestMapping(
method = RequestMethod.PUT
)
public void updatePerson(@RequestBody Person person) {
...
}
}
```
#### Frontend - Paths
GET /persons
```java
@RestController
public class PersonController {
@GetMapping(path = "/persons")
public List<Person> getPersons() {
...
}
}
```
#### Frontend - Paths
GET /persons
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@GetMapping
public List<Person> getPersons() {
...
}
}
```
#### Frontend - Paths
GET /persons/subpath
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@GetMapping(path = "/subpath")
public String getSomething() {
...
}
}
```
#### Frontend - Path Variables
GET /persons/John%32Doe
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@GetMapping(path = "/{name}")
public Person getPerson(@PathVariable String name) {
...
}
}
```
#### Frontend - Parameters
GET /persons?firstName=John&lastName=Doe
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@GetMapping
public Person getPerson(
@RequestParam String firstName,
@RequestParam String lastName
) {
...
}
}
```
#### Frontend - Bodies
PUT /persons {"firstName": "John", "lastName": "Doe"}
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@PutMapping
public void updatePerson(@RequestBody Person person) {
...
}
}
```
#### Frontend - Media-Types
POST /persons/convert {"firstName": "John", "lastName": "Doe"}
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@PostMapping(
path = "/convert",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_XML_VALUE
)
public Person convertPerson(@RequestBody Person person) {
...
}
}
```
#### Frontend - Media-Types
POST /persons/291/document/43006
```java
@RestController
@RequestMapping(path = "/persons")
public class PersonController {
@GetMapping(
path = "/{id}/documents/{documentId}",
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE
)
public byte[] get(
@PathVariable Long id,
@PathVariable Long documentId
) {
...
}
}
```
#### Frontend - Media-Types
- Konvertierung zwischen Java und JSON, XML usw.
- Häufig genutzte Media-Types automatisch unterstützt
- Darunter z.B. auch Text, HTML oder Binär
- Serialisierung kann konfiguriert werden
### Middleware
#### Middleware
- Implementierung erfolgt durch Services
- Teilt die Businesslogik in Fachlichkeiten auf
#### Middleware - Umsetzung
- Empfohlen als Interfaces mit Implementierungen
- Austauschbar
- Konfigurierbar
- **aber** keine Pflicht
#### Middleware - Service Interface
```java
public interface PersonService {
Person getPerson(String name);
}
```
#### Middleware - Service Implementation
```java
@Service
public class PersonServiceImpl implements PersonService {
@Override
public Person getPerson(String name) {
...
}
}
```
#### Middleware - Default Implementation
```java
@Service
@ConditionalOnMissingBean(PersonService.class)
public class DefaultPersonService implements PersonService {
@Override
public Person getPerson(String name) {
...
}
}
```
#### Middleware - Conditional Implementation
```java
@Service
@ConditionalOnProperty("service.dumbMode")
public class DumbModePersonService implements PersonService {
@Override
public Person getPerson(String name) {
...
}
}
```
#### Middleware - Service
```java
@Service
public class DocumentService {
public byte[] getDocument(Person person) {
...
}
}
```
### Backend
#### Backend
- Implementierung erfolgt durch Repositories / Services
- Datenbanken, Dateisystem und anderes Services
#### Backend - JPA Übersicht
- Objekt-Relationales-Mapping
- Entities
- Abbildungen von Objekten auf Tabellen
- Transaktionsmanagement
- Aggregation von zusammengehörigen Änderungen
- Gewährleistung von Datenintegrität
#### Backend - JPA Entities
- `@Entity` zur Deklaration eine Entity
- `@Id` zur Markierung des ID-Feldes
- `@GeneratedValue` zur automatischen Generierung
- usw.
#### Backend - JPA Repository
- Implementiert Datenbankschnittstelle für eine Entity
- Verschiedene Arten von Datenbankschnittstelle möglich (JPA, ElasticSearch etc.)
- Deklaration als Interface, Implementierung erfolgt automatisch
- Queries werden anhand des Names automatisch generiert
- Standard-Methoden bereits vorgegeben
#### Backend - JPA Repository
```java
Person findById(Long id);
```
`SELECT * FROM person WHERE id=:personId`
#### Backend - JPA Repository
```java
Person findByFirstNameAndLastName(
String firstName,
String lastName
);
```
`SELECT * FROM person WHERE firstName=:firstName AND lastName=:lastName`
#### Backend - JPA Repository
```java
@Query("SELECT n FROM Person p "
+ "WHERE p.tag IN (:tags) "
+ "AND p.creationDate >= :timestamp")
List<Person> findWithTagsAfter(
String[] tags,
OffsetDateTime timestamp
);
```
#### JPA-Repository - Better Practice
- Vielzahl an vordefinierten Operationen
- Wrapper-Klasse für explizite Schnittstellen
- Mehr Aufwand - Mehr Konsistenz
- Projekt-spezifisches Wording
- Verändern der Methodensignatur
- Keine ungewollten Operationen
#### JPA-Repository - Beispiel
```java
@Repository
public class PersonRepository {
private final SpringPersonRepository delegate;
public PersonRepository(
@Autowired SpringPersonRepository delegate
) {
this.delegate = delegate;
}
public @Nullable Note find(@NotNull Long id) {
return delegate.findById(id).orElse(null)
}
}
```
### Referenzierung
#### Referenzierung
- Spring ist ein Dependency-Injection-Container
- Bootstrap baut Objektgraphen auf
- Objektgraph ist normalerweise statisch
- Objektgraph erlaubt aber dynamische Erweiterung
- Zwei primäre Quellen für Objekte
- Components
- Configurations
#### Referenzierung - Verwendung
```java
@RestController
public class PersonController {
public PersonController(
@Autowired PersonService personService
) {
...
}
}
```
#### Referenzierung - Verwendung
```java
@Service
public class PersonServiceImpl {
public PersonServiceImpl(
@Autowired PersonRepository personRepository
) {
...
}
}
```
#### Referenzierung
- Benötigt Aufruf durch Dependency-Injection-Container
- Auflösung der Referenzen über Typ
- Mehrfach vorhandene Objekt über Namen ggf. Classifier
- Boostrap scheitert wenn Referenz nicht auslösbar
- kein entsprechendes Objekt
- mehrere entsprechende Objekte
#### Referenzierung
- Zwei Einstiegspunkte in den Objektgraphen
- Components
- Configurations
#### Referenzierung - Components
- Klassen direkt oder indirekt annotiert mit `@Component`
- Durch `@RestController`, `@Service` und `@Repository` indirekt annotiert
#### Referenzierung - Components
```java
@Component
public class IndependentComponent {
...
}
```
#### Referenzierung - Components
```java
@Component
public class DependentComponent {
public DependentComponent(
@Autowired RequiredComponent component
) {
...
}
}
```
#### Referenzierung - Configurations
- Klassen annotiert mit `@Configuration` über Methoden annotiert mit `@Bean`
#### Referenzierung - Configurations
```java
@Configuration
public class SomeConfiguration {
@Bean
public IndependentComponent createComponent() {
...
}
}
```
#### Referenzierung - Configurations
```java
@Configuration
public class SomeConfiguration {
@Bean
public DependentComponent createComponent(
@Autowired RequiredComponent component
) {
...
}
}
```
### Configurations
#### Configurations
- Indirekte Deklaration von Objekten
- Ändern und Erweitern bestehender Objekte
- Aufruf durch den Dependency-Injection-Container
#### Configurations - Beispiel
```java
@Configuration
public class MyConfiguration {
@Bean
public MyComponent createComponent() {
...
}
}
```
#### Configurations - Beispiel
```java
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
```
### Validation
#### Validation
- Überprüfung der Eingaben
- Client ist nicht vertrauenswürdig
- Spring unterstützt `javax.validation` Annotations
#### Validation - Verwendung
- `@Valid` zur Markierung von zu validierenden Parametern
- `@NotNull`
- `@NotBlank` mindestens EIN nicht Whitespace-Charakter
- `@Size` Einschränkung der Länge von Strings & Collections
- `@Min`, `@Max` Einschränkung des numerischen Wertebereichs
- `@Email` erwartet eine valide Email-Adresse
#### Validation - Beispiel
```java
public class Note {
...
@NotBlank(message = "description must not be blank")
private String description;
...
}
```
#### Validation - Beispiel
```java
@PostMapping
public Note createNote(
@RequestBody @Valid NoteProposal proposal
) {
...
}
```
### Praxis
#### Praxis - Aufgaben
- TODOs abfragen
- TODO anlegen
- TODO abfragen
- TODO ändern
- TODO löschen
#### Praxis - TODOs abfragen
`GET /todo`
- Repository: Methode zum Abrufen alle TODOs anlegen
- Service: Repository aufrufen
- Controller: Endpunkt anlegen, Service aufrufe
#### Praxis - TODO anlegen
`POST /todo {"title": "Cleanup"}`
- Repository: Methode zum Speichern anlegen
- Service: Aus Proposal ein TODO machen, in Repository speichern
- Controller: Endpunkt anlegen, Service aufrufen
#### Praxis - TODO abfragen
`GET /todo/{id}`
- Repository: Methode zum Abrufen eines TODO anlegen
- Service: Repository aufrufen und Existenz überprüfen
- Controller: Endpunkt anlegen, Service aufrufen
#### Praxis - TODO ändern
`PUT /todo/{id} {"done": true}`
- Repository: -
- Service: TODO laden, anpassen, in Repository speichern
- Controller: Endpunkt anlegen, Service aufrufen
#### Praxis - TODO löschen
`DELETE /todo/{id}`
- Repository: Methode zum Löschen anlegen
- Service: TODO laden, in Repository löschen
- Controller: Endpunkt anlegen, Service aufrufen