Sie sind auf Seite 1von 52

Spring into Seam

Stacking the deck by integrating Spring beans and Seam components

Dan Allen TetraTech, Inc. 4302

Who am I?
> Author of Seam in Act ion > Published art icles: Seamless JSF (developerWorks) Spring int o Seam (JavaWorld) > Commit ter on the JBoss Seam Project > Software consultant > Linux and open source advocat e > htt p:/ / www.mojavelinux .com

AGENDA
> > > > > > Why int egrat e? POJO int egrat ion EL integration ("Poor man's integration") Spring- Seam hybrid component s Inject ing Seam components int o Spring beans Persist ence contex t propagat ion and unified transact ions

AGENDA
> > > > > > Why integrate? POJO int egrat ion EL integration ("Poor man's integration") Spring- Seam hybrid component s Inject ing Seam components int o Spring beans Persist ence contex t propagat ion and unified transact ions

Why integrate?
> Applications are typically heterogeneous Shaped by their history; reflect ex pertise of developers > Ex tended inventory of unique functionality Seam

Perfect compliment to JSF, making it a compelling web framework choice Makes EL ubiquitous; stretches across entire stack Introduces real- world variable scopes (conversation, business process) Scopes the persistence context properly and manages global transactions Advanced AOP (AspectJ, Spring AOP) Lightweight and Java EE remoting (provides both client and endpoint) Prox y factory beans (e.g. JAX- RPC, JAX- WS, JMS, MBean) Template classes (e.g. JdbcTemplate, HibernateTemplate, JmsTemplate)

Spring

> Staged migration > Different philosophies: stateful vs stateless; annotations vs XML

AGENDA
> > > > > > Why int egrat e? POJO integration EL integration (aka "Poor man's integration") Spring- Seam hybrid component s Inject ing Seam components int o Spring beans Persist ence contex t propagat ion and unified transact ions

Developing with POJOs


> The pillar of Spring > Seam encourages it, but not to such an ex treme > Container agnostic classes No imposed interfaces No environment- dependent lookups Can be tested easily in isolation > Dependency information stored in metadata Annotations XML > Classes can jump containers > Injected object can come from anywhere Can even be a prox y

POJO integration
> Register POJO as Seam component Declare in Seam component descriptor (e.g. components.xml) Assign dependencies using component configuration < component name= "tournamentManager" scope= "APPLICATION" class= "...business.impl.TournamentManagerImpl" startup= "true"> < property name= "tournamentDao"> #{tournamentDao}< / property> < / component> References a Seam component > Just like a Spring bean definition, but Seam manages component > Useful for using classes from a third- party POJO library > Does not benefit from Spring services > May even have to emulate some Spring behavior (e.g. InitializingBean)

AGENDA
> > > > > > Why int egrat ion? POJO int egrat ion EL integration ("Poor man's integration") Spring- Seam hybrid component s Inject ing Seam components int o Spring beans Persist ence contex t propagat ion and unified transact ions

10

EL integration ("Poor man's integration")


> Uses existing Spring beans and configuration > EL acts as adapter layer Keys on the id (or name) of the Spring bean > Good place to start integration, may never outgrow it < bean id= "tournamentManager" class= "...business.impl.TournamentManagerImpl"> < property name= "tournamentDao" ref= "tournamentDao"/ > < / bean> public interface TournamentManager { public List< Tournament> getUpcomingTournaments(); public boolean addSponsorshipLevel(SponsorshipLevel); / / ... }

11

EL resolvers
> By default, EL looks for a JSF managed bean > Seam extends EL to look for a Seam component > Spring can also ex tend EL to look for a Spring bean Standard approach for integrating JSF with Spring > Primarily used to resolve ex pression root, but Seam takes EL further

#{beanName .propertyName}

JSF container

Seam container

Spring container

12

The Spring EL resolver at work

13

Registering the Spring resolver (1 )


> Two options, depending on what is available > Registered in JSF configuration file (/ WEB- INF/ faces- config.xml) > Variable resolver: JSF > = 1.1 and Spring > = 1.1 < faces- config> < application> < variable- resolver> org.springframework.web.jsf.DelegatingVariableResolver < / variable- resolver> < / application> < / faces- config>

14

Registering the Spring resolver (2 )


> Two options, depending on what is available > Registered in JSF configuration file (/ WEB- INF/ faces- config.xml) > EL resolver: JSF > = 1.2 and Spring > = 2.5 < faces- config> < application> < el- resolver> org.springframework.web.jsf.el.SpringBeanFacesELResolver < / el- resolver> < / application> < / faces- config>

15

Which is better, the EL or variable resolver?


EL resolver > Supports binding ex pressions Assign value to property Invoke method > Pluggable resolver mechanism Has access to whole expression Does not require JavaBean naming conventions > Hooks into JBoss EL Parameterized ex pressions "Magic" properties (e.g. size()) > Works as a standalone API Variable resolver > Can only resolve expression root (i.e. #{beanName.propertyName}) > Only resolves property value > Tied to runtime JSF FacesContext

The verdict: EL

16

Poor man's data access: Indirect method


< h3> Upcoming Tournaments< / h3> < h:dataTable var= "_tournament" value= "#{upcomingTournaments}"> < h:column> < f:facet name= "header"> Name< / f:facet> #{_tournament.name} < / h:column> @Name("tournamentList") ... public class TournamentListAction { < / h:dataTable> @In("#{tournamentManager}") private TournamentManager tournamentMgr; injected prior to method call

@Factory(value = "upcomingTournaments", scope = PAGE public List< Tournament> loadUpcomingTournaments() { return tournamentMgr.getUpcomingTournaments(); } }

17

Poor man's data access: Direct method


< h3> Upcoming Tournaments< / h3> < h:dataTable var= "_tournament" value= "#{upcomingTournaments}"> < h:column> < f:facet name= "header"> Name< / f:facet> #{_tournament.name} < / h:column> ... < components> < / h:dataTable> < factory name= "upcomingTournaments" scope= "PAGE" value= "#{tournamentManager.upcomingTournaments}"/ > < / components> > getUpcomingTournaments() method treated as bean property > Factory protects method from redundant use > Putting factory result in PAGE scope makes it available on JSF postback

18

Poor man's invoke action: Indirect method


< h:form> Add Sponsorship Level Name: < h:inputTex t value= "#{sponsorshipLevel.name}"/ > < h:commandButton action= "#{sponsorshipLevelAction.save}" value= "Save"/ > @Name("sponsorshipLevelAction") < / h:form> public class SponsorshipLevelAction { @In("#{tournamentManager}") private TournamentManager tournamentMgr; injected prior to method call @In private SponsorshipLevel sponsorshipLevel;

public boolean save() { return tournamentMgr.addSponsorshipLevel(sponsorshipLeve } }

19

Poor man's invoke action: Direct method


< h:form> Add Sponsorship Level Name: < h:inputTex t value= "#{sponsorshipLevel.name}"/ > < h:commandButton action= "#{tournamentManager.addSponsorshipLevel(sponsorshipLevel)}" value= "Save"/ > < / h:form> > Method binding ex pression only works with EL resolver (not variable resolver) > Leverages JBoss EL parameterized binding ex tension

Seam = EJB 3 + JSF = Spring + JSF

20

Going beyond poor man's integration


Basic improvement > Eliminate need to use EL notation in @In annotation @In("#{tournamentManager}") To keep your Spring beans isolated, stop here. Otherwise, you may want to... > Create Spring- Seam hybrid components Store Spring beans in Seam contex ts Add functionality provided by Seam interceptors to Spring beans

Bijection, declarative conversation boundaries, events, etc.

> Allow Spring beans to consume (stateful) Seam components > Let Seam manage the persistence contex t for Spring Overall goal: Make integration more transparent and effective

21

AGENDA
> > > > > > Why int egrat e? POJO int egrat ion EL integration (aka "Poor man's integration") Spring- Seam hybrid components Inject ing Seam components int o Spring beans Persist ence contex t propagat ion and unified transact ions

22

Spring- Seam hybrid components


> Has dual citizenship Spring bean and Seam component Spring bean is wrapped as Seam component Requires that bean is looked up through Seam > Works much the same as the Seam EJB 3 integration > Not dependent on EL > Seam method interceptors are applied to Spring bean Can be disabled > Spring bean can be stored in a Seam contex t Default contex t is STATELESS (i.e. pass- through) Remaining Seam contex ts act as Spring custom scopes > Can result in chicken/ egg problem during startup Safest bet: Use Seam to boot Spring Handled by built- in Seam component

23

Bootstrapping Spring from Seam


> Step 1: Add Spring namespace to Seam component descriptor < components x mlns= "http:/ / jboss.com/ products/ seam/ components" ... xmlns:spring= "http:/ / jboss.com/ products/ seam/ spring" x si:schemaLocation= " ... http:/ / jboss.com/ products/ seam/ spring http:/ / jboss.com/ products/ seam/ spring- 2.0.xsd "> < / components> > Step 2: Declare built- in Spring contex t loader component < spring:contex t- loader/ > > Step 3: Identify locations of Spring bean configuration files
(not required if using / WEB- INF/ applicationContex t.x ml)

< spring:contex t- loader config- locations= "/ WEB- INF/ spring- beans.x ml,classpath:spring- beansdao.xml"/ >

24

Seam XML namespace for Spring


> > > > Seam registers an XML namespace handler with Spring configuration file Receives callback when encountering Seam XML element Augments bean definitions or contributes definitions to Spring context Facilitates two way communication between Seam and Spring

Seam

Spring

25

Registering the Seam XML namespace


> Adds a Seam XML vocabulary to Spring configuration file < beans xmlns= "http:/ / www.springframework.org/ schema/ beans" ... xmlns:seam= "http:/ / jboss.com/ products/ seam/ spring- seam" x si:schemaLocation= " ... http:/ / jboss.com/ products/ seam/ spring- seam http:/ / jboss.com/ products/ seam/ spring- seam- 2.0.xsd "> < / beans>

26

Elements in the Seam XML namespace


> < seam:component> Creates a Seam- Spring hybrid component > < seam:instance> Defines a Spring factory bean that retrieves a Seam component instance Used to inject Seam component instance into property of Spring bean > < seam:configure- scopes> Infuses Seam container with Seam scopes

27

Spring- Seam hybrid component creation process

28

Optional attributes for hybrid component


> scope Stores Spring bean (or prox y) in Seam contex t < bean id= "tournamentManager" class= "..." scope= "prototype"> < seam:component scope= "CONVERSATION" ... / > < / bean> > auto- create Automatically resolve Spring bean if not present in Seam context < seam:component auto- create= "true" ... / > > intercept Controls whether Seam interceptors are applied to Spring bean < seam:component intercept= "false" ... / > > name Makes the Seam component name different from Spring bean id < seam:component name= "tournamentMgr" ... / >

29

Making Spring proxies compatible with Seam


> Two approaches to proxying: JDK dynamic proxy implements interfaces of bean class Cglib proxy subclass of bean class; can be cast to bean class > JDK dynamic prox y is default choice in Spring > Seam needs access to bean class < < interface> > Cannot wrap JDK dynamic prox ies TournamentManager Need to tell Spring to use Cglib prox y
TournamentManagerImpl TournamentManagerJDKProxy

TournamentManagerCglibProxy

30

Reconfiguring Spring- applied interceptors


> AOP advice configuration: < aop:config proxy- target- class= "true"> < aop:advisor id= "tournamentManagerTx " advice- ref= "defaultTxAdvice" pointcut= "ex ecution(* org.open18.business.TournamentManager.*(..))"/ > < / aop:config> > AspectJ annotation- based configuration: < aop:aspectj- autoprox y proxy- target- class= "true"/ > > Java 5 annotation- based transaction configuration: < tx :annotation- driven proxy- target- class= "true"/ >

31

Reconfiguring a proxy factory bean


> Two ways to switch to a Cglib prox y: Set prox yTargetClass property to true Don't specify prox yInterfaces property > Also need to tell Seam the class of the target object using the class attribute < bean id= "tournamentManager" class= "...transaction.interceptor.TransactionProx yFactoryBean"> < seam:component class= "...business.impl.TournamentManagerImpl"/ > < property name= "prox yInterfaces" value= "org.open18.business.TournamentManager"/ > < property name= "proxyTargetClass" value= "true"/ > < property name= "target" ref= "tournamentManagerTarget"> < property name= "transactionAttributes"> ...< / property> < / bean>

32

Spring- Seam hybrid component shorthand


> Leverages Spring custom scopes (Spring > = 2.0) > Alternative to singleton and prototype > Scopes are enum constants in org.jboss.seam.ScopeType prefixed with "seam." > Give up some flex ibility > Step 1: Register Seam scopes < seam:configure- scopes/ > > Step 2: Assign Seam scope to Spring bean < bean id= "tournamentManager" class= "..."<scope= "seam.CONVERSATION" > No longer need seam:component> tag < / bean> > Step 3: Enable auto- create behavior (optional) < seam:configure- scopes default- auto- create= "true"/ >

33

AGENDA
> > > > > > Why int egrat e? POJO int egrat ion EL integration ("Poor man's integration") Spring- Seam hybrid component s Injecting Seam components into Spring beans Persist ence contex t propagat ion and unified transact ions

34

Giving back to Spring


> Inject Seam component instance into property of Spring bean Declare < seam:instance> as Spring bean property value Use < seam:instance> to create Spring bean alias > Variants: Component name: < seam:instance name= "sponsorshipValidator"/ > EL value ex pression: < seam:instance name= "#{tournamentHome.instance}"/ > > Two containers work together to "wire" a bean > Required to inject a Spring- Seam hybrid component

35

When stateless and stateful collide


> Spring advocates stateless architecture > Seam advocates stateful architecture > Risks of mix ing these two architectures: Violation of thread safety

Act: Singleton puts reference to a thread- bound object in a shared location (field on class) Consequence: Reference is exposed to concurrent threads Act: Object in longer- term scope holds reference to bean in shorter- term scope Consequence: Object in shorter- term scope outlives expected lifetime

Scope impedance

> Caused by: Inappropriate use of singletons Static injection Hard references

36

Singletons and concurrency (or lack thereof)


> Singletons are shared amongst all threads May be accessed concurrently Methods that access shared data are not thread- safe! Seam's bijection ex pects object to be single- threaded > Can synchronize access using the synchronized keyword per method Synchronizing introduces bottlenecks and deadlock scenarios > Concurrency options Pooling of singleton using Spring's AbstractPoolingTargetSource Seam's @Synchronized annotation (preferred over synchronized keyword)

Can detect deadlock and timeout the call (throws exception) Timeout is configurable

> Spring and Seam both offer scoped prox ies to eliminate shared references

37

Adding a layer of separation


> Inject a locator prox y rather than hard reference < seam:instance name= "componentName" proxy= "true"/ > > Each time property is touched, calls out to Seam container to get instance > Injected objects are guaranteed to be thread- safe > Solves scope impedance by always retrieving latest instance Only leaves behind the locator after method call > Slight overhead from recurrent lookups to Seam container > Avoids introducing bottlenecks Method calls don't need to be synchronized Object doesn't need to be pooled

38

A comparison of scoped proxies


> Spring bean made "scope aware" using AOP: scoped proxy Nest < aop:scoped- prox y/ > inside of bean definition Prevents scope impedance and thread- safety violation Intended to be used with session, request, and custom scopes > Spring's scoped prox y not compatible with Spring- Seam hybrid components! Must use < seam:instance prox y= "true"/ > instead > How they differ: Spring prox y is defined on bean definition Seam prox y is defined at point of injection

39

Making a Spring bean out of a Seam component


> Spring- Seam hybrid decorates Spring bean with Seam behavior > Inverse: Make Seam component appear like a Spring bean > Use top- level < seam:instance> Spring bean id defaults to Seam component name unless overridden Definitions can be isolated in separate file Spring can't tell the difference; can use bean "ref" syntax < seam:instance name= "currentUser " prox y= "true" scope= "SESSION"/ > < seam:instance id= "selectedTournament " name= "#{tournamentHome.instance}" proxy= "true"/ > < bean id= "tournamentManager" class= "..."> < property name= "currentUser" ref= "currentUser "/ > < property name= "tournament" ref= "selectedTournament "/ > < / bean>

40

Introducing Spring to state


Parameterized EL Pros: > Can use POJO as is > No risk of scope impedance in design Cons: > Methods act static; not good OO > Must be called from EL (JBoss EL) > Violates encapsulation Use if just testing the integration < seam:instance> Pros: > Does not require use of EL > Method signatures kept simple Cons: > Requires awareness of scopes > Can cause scope impedance if used w/ o proxy Use if committed to the integration

41

AGENDA
> > > > > > Why int egrat e? POJO int egrat ion EL integration ("Poor man's integration") Spring- Seam hybrid component s Inject ing Seam components int o Spring beans Persistence context propagation and unified transactions

42

Bring peace to the persistence land


> Persistence management is central to the application > Only one framework gets to control it Both Seam and Spring offer a way Seam is flex ible; can consume ex ternally defined configuration > Not only does Spring not share, it handles the persistence context incorrectly

43

The persistence context in 6 0 seconds


> Maintains set of managed entities retrieved from database; first- level cache For any persistent id, there is a unique entity instance > Supports transparent persistence: Automatic change detection Changes to managed entities are tracked; synchronized to database when flush occurs (e.g. when transaction ends) Persistence by reachability Persists or updates related entities that are accessible through a mapped property of the original (i.e. @ManyToOne) Lazy loading Related entities configured as lazy are fetched on demand > Persistence contex t ends when persistence manager (EntityManager) is closed Entity instances in persistence contex t become detached Transitive persistence stops working

44

Where Spring gets it wrong


> Treats persistence manager (and contex t) as subsidiary of the transaction Strips it of its value Raises odds of encountering an ORM violation (lazy- load error, nonunique) > OpenSessionInViewFilter binds persistence manager to current thread Makes the situation even more confusing Persistence contex t still ends when request ends; delays problem

45

Using a Spring- configured persistent unit


> Seam resolves the persistence manager factory using an EL value expression > Use Spring- configured persistence unit (JPA / Hibernate); poor man's integration
applicationContext.xml

< bean id= "entityManagerFactory"

class= "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBea n"> < property name= "persistenceUnitName" value= "tournamentPU"/ > < property name= "dataSource" ref= "dataSource"/ > @In EntityManager entityManager < property name= "jpaDialect"> < bean class= "org.springframework.orm.jpa.vendor.HibernateJpaDialect"/ > < / property> < / bean>
components.xml

< persistence:managed- persistence- contex t name= "entityManager"

46

Regifting the persistence manager for Spring


> Need to give the Seam- managed persistence contex t back to Spring > Spring isn't aware of the switch
applicationContext.xml

< bean id= "entityManagerFactorySpring " class= "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBea n"> the one Spring will ... use < / bean> < bean id= "entityManagerFactory" class= "org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean"> < property name= "persistenceContex tName" value= "entityManager"/ > < / bean>
components.xml

< persistence:managed- persistence- contex t name= "entityManager" entity- manager- factory= "#{entityManagerFactorySpring}" autocreate= "true"/ >

47

Visualizing the persistence hand- off

48

How Seam cleans up the mess


> Seam prevents Spring from closing the persistence manager Persistence contex t remains open for at least the whole request Open Session in View for free Extended across requests if Seam conversation is in use No lazy- load ex ceptions; no need to use merge() > Spring can transparently inject Seam- managed persistence context into @PersistenceContex t property on Spring bean

49

One transaction to rule them all


> Don't want two different transaction managers for one resource > Additionally, Seam wraps each request in two transactions One from Restore View phase until after Invoke Application phase One around Render Response phase (read only) > Once again, use EL to tap into Spring; poor man's integration
applicationContext.xml

< bean id= "txManager " class= "org.springframework.orm.jpa.JpaTransactionManager"> < property name= "entityManagerFactory" ref= "entityManagerFactory"/ > < / bean> must be Seam's version
components.xml

< spring:spring- transaction platform- transactionmanager= "#{txManager}"/ >

50

Guice integration on the horizon


public class CafeModule implements Module { public void configure(Binder binder) { Next, we gave you Spring... binder.bind(Juice.class) Now, we give you Guice! .toInstance(new JuiceImpl("Apple Juice", 10)); binder.bind(Juice.class) .annotatedWith(Orange.class) .toInstance(new JuiceImpl("Orange Juice", @Name("cafe") 12)); @Guice } public class Cafe { Injection by } @Inject type < guice:injector name= "cafeInjector"> private Juice juiceOfTheDay; < guice:modules> @Inject @Orange < value> ...guice.CafeModule< / value> private Juice anotherJuice; < / guice:modules> / / ... < / guice:injector> } < guice:init injector= "#{cafeInjector}"/ >
We gave you EJB 3...

51

Wrap up
> > > > Spring and Seam are not mutually ex clusive POJO- based development enables sharing Can start small with "Poor man's integration" (EL) In full stride, you are using both containers for their strengths Bring advanced AOP to Seam Leverage Spring's template classes, prox y factories, and exporters Seam can handle conversational state Seam can manage the persistence contex t correctly

Dan Allen TetraTech, Inc.

http:/ / mojavelinux.com dan.allen@mojavelinux.com

Das könnte Ihnen auch gefallen