Gesamtarchitektur I und IoC
Schichten einer Web-Anwendung Initiiert durch J2EE und Spring: Strukturierte Sicht auf UI und Fachlogik (Domäne) Ergibt 5 Schichten: Man unterscheidet Präsentations- und Domänenmodell! UI Geschäftsmodell Presentation V UI Application (MC) Services C Domain M Sichtbare Komponenten UI-Zusammenhang: Navigation, Workflow, Anwendungsobjekte, Use Cases, Session, Verbindung zu Services Geschäftslogik und Transaktionen: Use-Cases, Objektübergreifende Operationen, Objektverwaltung (Suchen, Auflisten...) Fachlogik Domänenmodell, persistente Einheiten Persistenz Persistence Persistenzoperationen, Persistenzverwaltung. (c) schmiedecke 07 SE2-11-Anforderungsmanagement 2
Mail-Service Analysemodell User +loggedin Mail +timestamp +text Contact Header appendix login.jsp MailList.jsp MailViewer.jsp NotSent.jsp MailEditor MailSent.jsp (c) schmiedecke 07 SE2-11-Anforderungsmanagement 3
Mail-Service CRUD-Prototyp Zu jeder Model-Klasse wird eine Controller-Klasse und eine JpaController-Klasse generiert. Die Controller-Klasse enthält alle Attribute und Methoden, die die JSPs benötigen. Backing Bean Die JpaController-Klasse stellt den Zugang zu den Persistenten Objekten her. Service (c) schmiedecke 07 SE2-11-Anforderungsmanagement 4
CRUD-Architektur class MailCRUD FacesServ let mail.list.j sp mail.details.j sp mail.edit.j sp user.list.j sp user.details.j sp user.edit.j sp MailController UserControlle r MailJpacontroller UserJpaControlle r (c) schmiedecke 07 SE2-11-Anforderungsmanagement 5 Mail Us er
CRUD-Architektur Anwendungsarchitektur Echte GUIs sind an Use Cases ausgerichtet Services sind am Domain Model ausgerichtet Assoziationsgebüsch FacesServlet Login.jsp MailList.jsp MailViewer.jsp MailEditor.jsp SendingStatus.jsp <<ManagedBean>> UserServiceBean <<ManagedBean>> MailServiceBean <<ManagedBean>> ContactServiceBean EntityManager EntityManagerFactory <<ManagedBean>> PersistenceManager (c) schmiedecke 07 SE2-11-Anforderungsmanagement 6
Aufräumen mit einer Session Facade FacesServlet Login.jsp MailList.jsp MailViewer.jsp MailEditor.jsp SendingStatus.jsp <<ManagedBean>> MailSessionFacade <<ManagedBean>> UserServiceBean <<ManagedBean>> MailServiceBean <<ManagedBean>> ContactServiceBean Hier wird das Domain Model angefügt - später (c) schmiedecke 07 SE2-11-Anforderungsmanagement 7
Abhängigkeiten zwischen Schichten FacesServlet Login.jsp MailList.jsp MailViewer.jsp MailEditor.jsp SendingStatus.jsp <<ManagedBean>> MailSessionFacade <<ManagedBean>> UserServiceBean <<ManagedBean>> MailServiceBean <<ManagedBean>> ContactServiceBean Rote Assoziationen können nicht naiv gesetzt werden. Alternative? Klebstoff benötigt (c) schmiedecke 07 SE2-11-Anforderungsmanagement 8
IoC Inversion of Control Objektmanagement durch die Umgebung IoC-Framework Oder als IoC-Pattern implementiert Service-Konzept: Anwendung "bestellt" Objekt: "brauche ContactServiceBean" Framework liefert, gemäß Spezifikation, neues Objekt aktuell verfügbares Objekt allgemein veröffentlichtes Objekt kümmert sich um Instanziierung, Verwaltung, Thread-Safety,... Beliefern Dependency Injection (c) schmiedecke 07 SE2-6-IoC-Frameworks 9
IoC - Klebstoff oder Trennmittel? Eine Frage der Sichtweise Wenn man Klebstoff hat, muss man die Schichten nicht hart verdrahten: IoC gilt als Technik der Schichtentrennung (c) schmiedecke 07 SE2-6-IoC-Frameworks 10
Direkte Instanziierung direkte Kontrolle A B A B public class A { private B b; 1 : new() public A() { b = new B(); } } Entwurfsentscheidungen: 1. A benötigt Referenz auf B. 2. B ist eine konkrete Klasse mit Standard-Konstruktor. 3. A besitzt die Referenz auf B exklusiv. (c) schmiedecke 07 SE2-6-IoC-Frameworks 11
Veränderungen an B wirken sich aus: A C B 1 : new C() 2 : new B() public class A { private B b; public A() { C c = new C(); b = new B(c); } } Geänderte Entwurfsentscheidung, z.b.: kein Standardkonstruktor für B B ist abstrakte Klasse. (c) schmiedecke 07 SE2-6-IoC-Frameworks 12
Umkehrung der Kontrolle: IoC-Framework erzeugt B-Instanz A B IoCFramework 2 : setb() 1 : create() public class A { private B b; public A() {} public void setb(b b) { this.b = b; } } Dependency Injection Änderungen an B wirken sich nicht aus. B muss keine konkrete Klasse sein. A-Instanzen müssen vor Benutzung mit B-Referenz "versorgt" sein. (c) schmiedecke 07 SE2-6-IoC-Frameworks 13
Dependency Injection Typ 1 Interface Injection PersistenceManager DataSource import org.apache.avalon.framework.*; public class PersistenceManager implements Serviceable { DataSource datasource; public void service (ServiceManager sm) throws ServiceException { datasource = (DataSource)sm.lookup("dataSource"); } public void getdata() { // use datasource PersistenceManager IoCFramework Service // to do some work 1 : create() } } 2 : service() 3 : lookup() (c) schmiedecke 07 SE2-6-IoC-Frameworks 14
Diskussion Interface Injection + keine Konfiguration erforderlich. - Java-Code ist framework-spezifisch. (c) schmiedecke 07 SE2-6-IoC-Frameworks 15
Dependency Injection Typ 2 Setter Injection PersistenceManager DataSource // Spring Framework: PersistenceManager ist normales Bean public class PersistenceManager { DataSource datasource; public void setdatasource(datasource datasource) { this.datasource = datasource; } public void getdata() { // use datasource to do some work } <bean } id="datasourcebean" class="..."> <property name="driverclassname"> <value>com.mydb.jdbc.driver</value> </property> <property name="url"> <value>jdbc:mydb://server:port/mydb</value> </property> <property name="username"> <value>root</value> </property> </bean> <bean id="persistencemanagerbean" class="example.persistencemanager"> <property name="datasource"> <ref bean="datasourcebean"/> </property> </bean> (c) schmiedecke 07 SE2-6-IoC-Frameworks 16
Diskussion Setter Injection + Java-Code ist Framework-unabhängig + Testumgebung einfach in XML konfigurierbar (Dummy- Objekte) - Die Abhängigkeit ist im Code nicht erkennbar. - Abhängigkeiten können nicht zur Compilezeit validiert werden. - DataSource muss public sein würde man eigentlich gern verbergen. (c) schmiedecke 07 SE2-6-IoC-Frameworks 17
Dependency Injection Typ 3 Constructor Injection PersistenceManager DataSource // PicoContainer Framework: keine Konfiguration public class PersistenceManager { DataSource datasource; public PersistenceManager(DataSource datasource) { this.datasource = datasource; } public void getdata() { // use datasource to do some work } } // die Klasse wird nicht direkt instanziiert, // sondern vom PicoContainer "besorgt". // Vorher muss sie unter "key" registriert sein, s.u. pico.getcomponentinstance(key); (c) schmiedecke 07 SE2-6-IoC-Frameworks 18
Dependency Injection Typ 3 Constructor Injection // PicoContainer Framework: programmierte Abhängigkeit // Datasourcebean erzeugen: JDBCDataSource datasource = new JDBCDataSource(); datasource.setdriverclassname("com.mydb.jdbc.driver"); datasource.seturl("jdbc:mysql://localhost:3306/mydb"); datasource.setusername("jacob"); //IoC-Container erzeugen MutablePicoContainer pico = new DefaultPicoContainer(); // Komponenten registrieren ConstantParameter datasourceparam = new ConstantParameter(dataSource); String key = "JDBCPersistenceManager"; Parameter[] params = {datasourceparam}; pico.registercomponentimplementation (key, PersistenceManager.class, params); (c) schmiedecke 07 SE2-6-IoC-Frameworks 19
Diskussion Constructor Injection + Java-Bean-Code ist Framework-unabhängig + Good-Citizen-Pattern: Instanziierte Objekte sind "komplett" + Die Abhängigkeit ist im Code erkennbar. - Vererbung bringt Komplikationen (Constructor chaining). - Manche APIs erfordern Standard-Konstruktor. (c) schmiedecke 07 SE2-6-IoC-Frameworks 20
Wichtige IoC-Frameworks Spring Setter Injection (auch Constructor Injection möglich) reichhaltige Bibliothek Standard-Hibernate-Anschluss Ausbaustufen für MVC, AOP PicoContainer minimal, reiner IoC-Container Constructor Injection Avalon frühes Projekt, wird nicht mehr fortgesetzt Interface Injection HiveMind (c) schmiedecke 07 SE2-6-IoC-Frameworks 21
Welches IoC-Framework für JSF- Anwendungen? Mit allen kombinierbar. IoC-Pattern kann auch selbst implementiert werden. Managed Beans sind bereits ein IoC-Framework! (c) schmiedecke 07 SE2-6-IoC-Frameworks 22
Managed Beans als IoC-Framework: Instanziierung: Managed Beans werden vom Container instanziiert. Initialisierung: Initialisierungen von Properties können in der faces-config.xml angegeben werden. Auch als Assoziationen zu anderen Managed Beans <value>#{otherbean}</value Gültigkeit und Lebensdauer: Scope-Typen none, request, session, application Lebensdauer wird in faces-config.xml spezifiziert. (c) schmiedecke 07 SE2-6-IoC-Frameworks 23
Bean-Konfiguration: IoC <managed-bean> <managed-bean-name>sessionfacade</managed-bean-name> <managed-bean-class>mail.ui.mailsessionfacade</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> <managed-property> <property-name>readingservice</property-name> <value>#{readingservice}</value> </managed-property> <managed-property> <property-name>writingservice</property-name> <value>#{writingservice}</value> </managed-property> <managed-property> <property-name>addressbookservice</property-name> <value>#{addressbookservice}</value> </managed-property> </managed-bean> (c) schmiedecke 07 SE2-11-Anforderungsmanagement 24
genug für heute Nächste Woche stellen wir die Architektur fertig und fügen Authentifizierung hinzu. (c) schmiedecke 07 SE2-11-Anforderungsmanagement 25