Spring Framework Tomasz Dobek
Plan prezentacji Spring z lotu ptaka Kontener Spring IoC Spring AOP Menedżer transakcji w Springu Spring DAO Testy integracyjne Podsumowanie
Spring Lekki kontener do budowy aplikacji Nie opisuje go żadna specyfikacja Najnowsza wersja 2.0 Istnieje też równoległy projekt Spring Webflow Spring powstał jako alternatywa dla EJB 2.1
Motywacja projektu Spring Wymuszamy dobry styl programowania Nie uzależniamy kodu aplikacji od naszego API Wspieramy testowanie modułów (unit-testing) poza kontenerem Wysoka konfigurowalność projektów Architekt może skroić Springa do swoich potrzeb
Składniki Spring Kontener IoC AOP DAO (JDBC, Hibernate, JPA, Toplink... ) Transakcje Framework MVC
Spring z lotu ptaka
Spring IoC
Kontener IoC Inversion of Control Zależności pomiędzy obiektami nie znajdują się w kodzie klas tych obiektów. Zależnościami zarządza kod zewnętrzny z punktu widzenia aplikacji (tu: kontenera). Wymusza to od nas myślenie interfejsami. Do realizacji tej techniki Spring używa Dependency Injection i Dependency Lookup
Przykład – DI przez settery Public class BlaImpl implements BlaIntf { private int intVal; Public void setIntVal(int value) { this.intVal = value; }
DI przez konstruktor Public class BlaImpl2 implements BlaIntf { private int intVal; public BlaImpl2(int val) { this.intVal = val;...
DI przez fabrykę <bean id=„factoryBean” class=„...”... <bean id=„instanceBean” class=„...” factory-bean=„factoryBean” factory-method=„createInstance”>...
Zależności od Beanów...
Dependency lookup Możemy sami poprosić kontener w naszym kodzie o Beana Interfejsy kontenera: BeanFactory ApplicationContext WebApplicationContext
DL - przykład Public static void main(String[] args) { InputStream is = new FileInputStream("beans.xml"); BeanFactory factory = new XmlBeanFactory(is); }
Zasięg Beanów Singleton (domyślny) Jedna instancja na kontener Prototype Każde żądanie tworzy nową instancję Request Session Global Session
Przykład - Eclipse Pobierz szkielet projektów do Eclipse’a /home/tmp/td209515/spring-workspace.tar.gz Rozpakuj i uruchom Eclipse'a wskazując rozpakowany katalog jako workspace Stwórz implementację interfejsu Stwórz plik konfiguracyjny Uruchom Main.java
Zaawansowane możliwości Leniwe ładowanie beanów Definiowanie własnych zakresów Definiowanie własnych znaczników w pliku konfiguracyjnym ApplicationContext Lokalizacje Sterowanie beanów zdarzeniami Auto-wiring
Spring AOP Framework
Spring AOP wprowadzenie Własny framework AOP Używa czystej Javy Ograniczona funkcjonalność Na Spring AOP zbudowana jest większość funkcjonalności Springa Spring AOP nie jest konkurencją dla np. AspectJ
AOP - przypomnienie Aspect Join point Advice Before advice After (returning/throwing/finally) advice Around advice Pointcut
Konfiguracja Spring AOP Aspekty traktowane są na równych prawach z innymi beanami. Sposoby konfiguracji: Konfiguracja w pliku XML z innymi Beanami
Konfiguracja - Public class BeforeExample public void doAccessCheck() {... } } // przy metodzie Bla.operation()
Konfiguracja - XML <aop:pointcut id=„businessService” expression=„execution(* com.xyz.myapp.service.*.* (..))”/> <aop:before pointcut-ref=„businessService” method=„doAccessCheck”/>...
Realizacja Spring AOP Obiekt AOP Proxy pośredniczy w wywołaniach metod naszego obiektu Jeśli występuje join point wywoływany jest w odpowiedni sposób kod aspektu
Przykład Do poprzedniego przykładu dodaj do interfejsu 1 metodę Napisz implementację drukującą coś na konsoli Zdefiniuj aspekt pointcut i advice uruchamiający tą metodę przy wywołaniu dowolnej metody Zobacz efekt
Zarządca transakcji w Springu
Transakcje w Springu Te same poziomy ISOLATION co w JTA Te same wartości PROPAGATION co w JTA Lepsze zarządzanie wyjątkami niż w JTA Wspiera JDBC, Hibernate, JPA, JDO Deklaratywnie i/lub programistycznie Brak zależności od serwera aplikacji
Używanie transakcji Interfejs PlatformTransactionManager public interface PlatformTransactionManager { TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
Używanie transakcji (2) Interfejs TransactionDefinition Isolation (domyślnie: DEFAULT) Propagation (domyślnie: REQUIRED) Timeout Read-only Oczywiście wszystko konfigurujemy jako Beany z użyciem AOP
Transakcje - konfiguracja
Konfiguracja (c.d.)...
Konfiguracja - public class DefaultFooService implements FooService { Foo getFoo(String fooName); Foo getFoo(String fooName, String barName); void insertFoo(Foo foo); void updateFoo(Foo foo); }
Realizacja transakcji Do realizacji użyto oczywiście IoC i AOP
Transakcje - ciekawostki Atrybut „rollback-for” Atrybut „no-rollback-for” Transakcje programistyczne: Korzystamy z klasy TransactionTemplate Podajemy co chcemy zrobić w transakcji i o nic się nie martwimy return transactionTemplate.execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { updateOperation1(); return resultOfUpdateOperation2(); } });
Spring DAO
Integracja wielu technologii do łączenia się z warstwą danych: JDBC, Hibernate, Toplink, JDO, JPA, iBATIS SQL Maps Zunifikowany zestaw wyjątków Wiele użytecznych klas Wykonywanie najczęstszych czynności Wplatanie wywołań API danej technologii
Nowa hierarchia wyjątków
Przykład - Hibernate Mamy przykładowy mapping Hibernate Definiujemy interfejs dostępu do danych Implementujemy go używając jednej z technologi (tu: Hibernate) Konfigurujemy beany. Uruchamiamy testy. Jeśli zmienimy technologie, zmieniamy konfigurację i implementacje interfejsu
Konfiguracja źródła danych product.hbm.xml hibernate.dialect=org.hibernate.dialect.HSQLDialect
Klasa HibernateTemplate Klasa opakowująca wywołania wewnątrz API Hibernate Umożliwia wykonywanie poleceń w Hibernate API przez callbacki. Inicjujemy ją w naszej implementacji DAO przez Dependency Injection
Konfiguracja Beanów public class ProductDaoImpl implements ProductDao { private HibernateTemplate hibernateTemplate; public void setSessionFactory(SessionFactory sessionFactory) { this.hibernateTemplate = new HibernateTemplate(sessionFactory); } public Collection loadProductsByCategory(String category) throws DataAccessException { return this.hibernateTemplate.find("from test.Product product where product.category=?", category); }
Testowanie aplikacji
Testowanie Spring Framework wspiera TDD Pisanie testów modułów jest proste (obiekty POJO) – może być poza kontenerem Spring ułatwia pisanie testów integracyjnych.
Interfejsy do pisania testów AbstractDependencyInjectionSpringContextTests AbstractTransactionalDataSourceSpringContextTests
Wsparcie dla testów integracyjnych Cache’owanie kontenera IoC AbstractDependencyInjectionSpringContextTests ::getConfigLocations() AbstractDependencyInjectionSpringContextTests ::getConfigLocations() Wykorzystanie „auto-wiring by type” do konfigurowania beanów testowych Zawieranie testów w transakcjach i wycofywanie ich pod koniec testu
Pisanie beanów testujących Wystarczy napisać settery do pól Nie przeładujemy kontenera chyba że wywołamy setDirty() Transakcje: możemy zatwierdzić wołając setComplete() Mamy też dostęp do źródła danych przez JdbcTemplate Mamy za darmo dostęp do applicationContext
Testy integracyjne - przykład Mamy aplikację z dostępem do bazy danych Chcemy sprawdzić testami poprawność konfiguracji (Hibernate, beany, obiekty DAO)
Kolejne ułatwienia - adnotacje 10) Takie testy wymagają dziedziczenia z AbstractAnnotationAwareTransactionalTests !!!
Testy integracyjne - przykład public final class HibernateTitleDaoTests extends AbstractDependencyInjectionSpringContextTests { private HibernateTitleDao titleDao; public void setTitleDao(HibernateTitleDao titleDao) { this.titleDao = titleDao; } public void testLoadTitle() throws Exception { Title title = this.titleDao.loadTitle(new Long(10)); assertNotNull(title); } protected String[] getConfigLocations() { return new String[] { "classpath:com/foo/daos.xml" }; } }
Przykład c.d. - konfiguracja...
Ciekawostki – wersja 2.0 Obsługa języków dynamicznych JRuby, Groovy, BeanShell Portlet MVC Pełne wsparcie dla JMS. Biblioteka tagów JSP. Uproszczona konfiguracja w XML
Podsumowanie Spring ułatwia budowanie aplikacji opartej na wielu technologiach. Spring wspiera tworzenie dobrze zaprojektowanych aplikacji. Spring nie jest inwazyjny (kod). Spring wspiera TDD. Spring jest lekki.
Spring, a EJB3 EJB3 rozwiązał wiele problemów, które wcześniej były rozwiązane w Springu Czy Spring jest nadal potrzebny ?
Pytania Jeśli starczy czasu Jeśli starczy czasu Bądź na maila :