+ All Categories
Home > Documents > Spring in to Seam

Spring in to Seam

Date post: 20-Oct-2015
Category:
Upload: lainiguez
View: 18 times
Download: 3 times
Share this document with a friend
Popular Tags:
52
Spring into Seam Stacking the deck by integrating Spring beans and Seam components Dan Allen TetraTech, Inc. 4302
Transcript
Page 1: Spring in to Seam

Spring into SeamStacking the deck by integrating Spring beans and Seam components

Dan Allen

TetraTech, Inc.

4302

Page 2: Spring in to Seam

Who am I?

> Author of Seam in Act ion

> Published art icles:

– Seamless JSF (developerWorks)

– Spring into Seam (JavaWorld)

> Commit ter on the JBoss Seam Project

> Software consultant

> Linux and open source advocate

> http:/ / www.mojavelinux.com

Page 3: Spring in to Seam

3

AGENDA

> Why integrate?

> POJO integrat ion

> EL integrat ion ("Poor man's integrat ion")

> Spring- Seam hybrid components

> Inject ing Seam components into Spring beans

> Persistence context propagat ion and unif ied transact ions

Page 4: Spring in to Seam

4

AGENDA

> Why integrate?> POJO integrat ion

> EL integrat ion ("Poor man's integrat ion")

> Spring- Seam hybrid components

> Inject ing Seam components into Spring beans

> Persistence context propagat ion and unif ied transact ions

Page 5: Spring in to Seam

5

Why integrate?

> Applications are typically heterogeneous

– Shaped by their history; reflect expert ise of developers

> Extended inventory of unique functionality

– Seam Perfect compliment to JSF, making it a compelling web framework choice Makes EL ubiquitous; stretches across ent ire stack Introduces real- world variable scopes (conversat ion, business process) Scopes the persistence context properly and manages global transact ions

– Spring Advanced AOP (AspectJ, Spring AOP) Lightweight and Java EE remoting (provides both client and endpoint) Proxy factory beans (e.g. JAX- RPC, JAX- WS, JMS, MBean) Template classes (e.g. JdbcTemplate, HibernateTemplate, JmsTemplate)

> Staged migration

> Different philosophies: stateful vs stateless; annotations vs XML

Page 6: Spring in to Seam

6

AGENDA

> Why integrate?

> POJO integration> EL integrat ion (aka "Poor man's integrat ion")

> Spring- Seam hybrid components

> Inject ing Seam components into Spring beans

> Persistence context propagat ion and unif ied transact ions

Page 7: Spring in to Seam

7

Developing with POJOs> The pillar of Spring

> Seam encourages it , but not to such an extreme

> Container agnostic classes

– No imposed interfaces

– No environment- dependent lookups

– Can be tested easily in isolat ion

> Dependency information stored in metadata

– Annotations

– XML

> Classes can jump containers

> Injected object can come from anywhere

– Can even be a proxy

Page 8: Spring in to Seam

8

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>

> Just like a Spring bean definit ion, 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. Init ializingBean)

References a Seam component

Page 9: Spring in to Seam

9

AGENDA

> Why integrat ion?

> POJO integrat ion

> EL integration ("Poor man's integration")> Spring- Seam hybrid components

> Inject ing Seam components into Spring beans

> Persistence context propagat ion and unif ied transact ions

Page 10: Spring in to Seam

10

EL integration ("Poor man's integration")

> Uses exist ing 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); / / ...}

Page 11: Spring in to Seam

11

EL resolvers

> By default, EL looks for a JSF managed bean

> Seam extends EL to look for a Seam component

> Spring can also extend EL to look for a Spring bean

– Standard approach for integrating JSF with Spring

> Primarily used to resolve expression root, but Seam takes EL further

#{beanName.propertyName}

JSF container Seam container Spring container

Page 12: Spring in to Seam

12

The Spring EL resolver at work

Page 13: Spring in to Seam

13

Registering the Spring resolver (1)

> Two options, depending on what is available

> Registered in JSF configuration f ile (/ 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>

Page 14: Spring in to Seam

14

Registering the Spring resolver (2)

> Two options, depending on what is available

> Registered in JSF configuration f ile (/ 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>

Page 15: Spring in to Seam

15

Which is better, the EL or variable resolver?

EL resolver

> Supports binding expressions

– 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 expressions

– "Magic" propert ies (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

Page 16: Spring in to Seam

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> ...< / h:dataTable>

@Name("tournamentList")public class TournamentListAction { @In("#{tournamentManager}") private TournamentManager tournamentMgr;

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

injected priorto method call

Page 17: Spring in to Seam

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> ...< / h:dataTable>

> getUpcomingTournaments() method treated as bean property

> Factory protects method from redundant use

> Putt ing factory result in PAGE scope makes it available on JSF postback

< components> < factory name= "upcomingTournaments" scope= "PAGE" value= "#{tournamentManager.upcomingTournaments}"/ >< / components>

Page 18: Spring in to Seam

18

Poor man's invoke action: Indirect method

< h:form> Add Sponsorship Level Name: < h:inputText value= "#{sponsorshipLevel.name}"/ > < h:commandButton action= "#{sponsorshipLevelAction.save}" value= "Save"/ >< / h:form> @Name("sponsorshipLevelAction")

public class SponsorshipLevelAction { @In("#{tournamentManager}") private TournamentManager tournamentMgr;

@In private SponsorshipLevel sponsorshipLevel;

public boolean save() { return tournamentMgr.addSponsorshipLevel(sponsorshipLevel); }}

injected priorto method call

Page 19: Spring in to Seam

19

Poor man's invoke action: Direct method

< h:form> Add Sponsorship Level Name: < h:inputText value= "#{sponsorshipLevel.name}"/ > < h:commandButton act ion= "#{tournamentManager.addSponsorshipLevel(sponsorshipLevel)}" value= "Save"/ >< / h:form>

> Method binding expression only works with EL resolver (not variable resolver)

> Leverages JBoss EL parameterized binding extension

Seam = EJB 3 + JSF = Spring + JSF

Page 20: Spring in to Seam

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 contexts

– Add functionality provided by Seam interceptors to Spring beans Biject ion, declarat ive conversation boundaries, events, etc.

> Allow Spring beans to consume (stateful) Seam components

> Let Seam manage the persistence context for Spring

Overall goal: Make integration more transparent and effective

Page 21: Spring in to Seam

21

AGENDA

> Why integrate?

> POJO integrat ion

> EL integrat ion (aka "Poor man's integrat ion")

> Spring- Seam hybrid components> Inject ing Seam components into Spring beans

> Persistence context propagat ion and unif ied transact ions

Page 22: Spring in to Seam

22

Spring- Seam hybrid components

> Has dual cit izenship – 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 context

– Default context is STATELESS (i.e. pass- through)

– Remaining Seam contexts 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

Page 23: Spring in to Seam

23

Bootstrapping Spring from Seam

> Step 1: Add Spring namespace to Seam component descriptor

< components xmlns= "http:/ / jboss.com/ products/ seam/ components" ... xmlns:spring= "http:/ / jboss.com/ products/ seam/ spring" xsi:schemaLocation= " ... http:/ / jboss.com/ products/ seam/ spring http:/ / jboss.com/ products/ seam/ spring- 2.0.xsd">< / components>

> Step 2: Declare built- in Spring context loader component

< spring:context- loader/ >

> Step 3: Identify locations of Spring bean configuration f iles(not required if using / WEB- INF/ applicationContext.xml)

< spring:context- loader config- locations= "/ WEB- INF/ spring- beans.xml,classpath:spring- beans-dao.xml"/ >

Page 24: Spring in to Seam

24

Seam XML namespace for Spring

> Seam registers an XML namespace handler with Spring configuration f ile

> Receives callback when encountering Seam XML element

> Augments bean definit ions or contributes definit ions to Spring context

> Facilitates two way communication between Seam and Spring

Seam Spring

Page 25: Spring in to Seam

25

Registering the Seam XML namespace

> Adds a Seam XML vocabulary to Spring configuration f ile

< beans xmlns= "http:/ / www.springframework.org/ schema/ beans" ... xmlns:seam= "http:/ / jboss.com/ products/ seam/ spring- seam" xsi:schemaLocation= " ... http:/ / jboss.com/ products/ seam/ spring- seam http:/ / jboss.com/ products/ seam/ spring- seam- 2.0.xsd">< / beans>

Page 26: Spring in to Seam

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 instanceUsed to inject Seam component instance into property of Spring bean

> < seam:configure- scopes>Infuses Seam container with Seam scopes

Page 27: Spring in to Seam

27

Spring- Seam hybrid component creation process

Page 28: Spring in to Seam

28

Optional attributes for hybrid component

> scope – Stores Spring bean (or proxy) in Seam context

< 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" ... / >

Page 29: Spring in to Seam

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 proxy is default choice in Spring

> Seam needs access to bean class

– Cannot wrap JDK dynamic proxies

– Need to tell Spring to use Cglib proxy

< < interface> >TournamentManager

TournamentManagerJDKProxyTournamentManagerImpl

TournamentManagerCglibProxy

Page 30: Spring in to Seam

30

Reconfiguring Spring- applied interceptors

> AOP advice configuration:

< aop:config proxy- target- class= "true">

< aop:advisor id= "tournamentManagerTx" advice- ref= "defaultTxAdvice"

pointcut= "execution(* org.open18.business.TournamentManager.*(..))"/ >

< / aop:config>

> AspectJ annotation- based configuration:

< aop:aspectj- autoproxy proxy- target- class= "true"/ >

> Java 5 annotation- based transaction configuration:

< tx:annotation- driven proxy- target- class= "true"/ >

Page 31: Spring in to Seam

31

Reconfiguring a proxy factory bean

> Two ways to switch to a Cglib proxy:

– Set proxyTargetClass property to true

– Don't specify proxyInterfaces property

> Also need to tell Seam the class of the target object using the class attribute

< bean id= "tournamentManager" class= "...transaction.interceptor.TransactionProxyFactoryBean"> < seam:component class= "...business.impl.TournamentManagerImpl"/ > < property name= "proxyInterfaces" value= "org.open18.business.TournamentManager"/ > < property name= "proxyTargetClass" value= "true"/ > < property name= "target" ref= "tournamentManagerTarget"> < property name= "transactionAttributes"> ...< / property>< / bean>

Page 32: Spring in to Seam

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 flexibility

> Step 1: Register Seam scopes

< seam:configure- scopes/ >

> Step 2: Assign Seam scope to Spring bean

< bean id= "tournamentManager" class= "..." scope= "seam.CONVERSATION"> < / bean>

> Step 3: Enable auto- create behavior (optional)

< seam:configure- scopes default- auto- create= "true"/ >

No longer need < seam:component> tag

Page 33: Spring in to Seam

33

AGENDA

> Why integrate?

> POJO integrat ion

> EL integrat ion ("Poor man's integrat ion")

> Spring- Seam hybrid components

> Injecting Seam components into Spring beans> Persistence context propagat ion and unif ied transact ions

Page 34: Spring in to Seam

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 expression:< seam:instance name= "#{tournamentHome.instance}"/ >

> Two containers work together to "wire" a bean

> Required to inject a Spring- Seam hybrid component

Page 35: Spring in to Seam

35

When stateless and stateful collide

> Spring advocates stateless architecture

> Seam advocates stateful architecture

> Risks of mixing these two architectures:

– Violat ion of thread safety Act: Singleton puts reference to a thread- bound object in a shared locat ion (field on

class) Consequence: Reference is exposed to concurrent threads

– Scope impedance Act: Object in longer- term scope holds reference to bean in shorter- term scope Consequence: Object in shorter- term scope out lives expected lifet ime

> Caused by:

– Inappropriate use of singletons

– Static injection

– Hard references

Page 36: Spring in to Seam

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 biject ion expects object to be single- threaded

> Can synchronize access using the synchronized keyword per method

– Synchronizing introduces bott lenecks and deadlock scenarios

> Concurrency options

– Pooling of singleton using Spring's AbstractPoolingTargetSource

– Seam's @Synchronized annotation (preferred over synchronized keyword) Can detect deadlock and t imeout the call (throws exception) Timeout is configurable

> Spring and Seam both offer scoped proxies to eliminate shared references

Page 37: Spring in to Seam

37

Adding a layer of separation

> Inject a locator proxy rather than hard reference

< seam:instance name= "componentName" proxy= "true"/ >

> Each t ime 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 bott lenecks

– Method calls don't need to be synchronized

– Object doesn't need to be pooled

Page 38: Spring in to Seam

38

A comparison of scoped proxies

> Spring bean made "scope aware" using AOP: scoped proxy

– Nest < aop:scoped- proxy/ > inside of bean definit ion

– Prevents scope impedance and thread- safety violat ion

– Intended to be used with session, request, and custom scopes

> Spring's scoped proxy not compatible with Spring- Seam hybrid components!

– Must use < seam:instance proxy= "true"/ > instead

> How they differ:

– Spring proxy is defined on bean definit ion

– Seam proxy is defined at point of injection

Page 39: Spring in to Seam

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

– Definit ions can be isolated in separate file

– Spring can't tell the difference; can use bean "ref" syntax

< seam:instance name= "currentUser" proxy= "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>

Page 40: Spring in to Seam

40

Introducing Spring to state

Parameterized EL

Pros:

> Can use POJO as is

> No risk of scope impedance in design

Cons:

> Methods act stat ic; not good OO

> Must be called from EL (JBoss EL)

> Violates encapsulation

< 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 just testing the integration Use if committed to the integration

Page 41: Spring in to Seam

41

AGENDA

> Why integrate?

> POJO integrat ion

> EL integrat ion ("Poor man's integrat ion")

> Spring- Seam hybrid components

> Inject ing Seam components into Spring beans

> Persistence context propagation and unified transactions

Page 42: Spring in to Seam

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 f lexible; can consume externally defined configuration

> Not only does Spring not share, it handles the persistence context incorrectly

Page 43: Spring in to Seam

43

The persistence context in 60 seconds

> Maintains set of managed entit ies retrieved from database; f irst- level cache

– For any persistent id, there is a unique entity instance

> Supports transparent persistence:

– Automatic change detection – Changes to managed entit ies are tracked; synchronized to database when flush occurs (e.g. when transaction ends)

– Persistence by reachability – Persists or updates related ent it ies that are accessible through a mapped property of the original (i.e. @ManyToOne)

– Lazy loading – Related entit ies configured as lazy are fetched on demand

> Persistence context ends when persistence manager (EntityManager) is closed

– Entity instances in persistence context become detached

– Transit ive persistence stops working

Persistence context should remain open as long as entity instances are being used

Page 44: Spring in to Seam

44

Where Spring gets it wrong

> Treats persistence manager (and context) as subsidiary of the transaction

– Strips it of its value

– Raises odds of encountering an ORM violat ion (lazy- load error, non-unique)

> OpenSessionInViewFilter binds persistence manager to current thread

– Makes the situation even more confusing

– Persistence context st ill ends when request ends; delays problem

Page 45: Spring in to Seam

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.LocalContainerEntityManagerFactoryBean"> < property name= "persistenceUnitName" value= "tournamentPU"/ > < property name= "dataSource" ref= "dataSource"/ > < property name= "jpaDialect"> < bean class= "org.springframework.orm.jpa.vendor.HibernateJpaDialect"/ > < / property>< / bean>

components.xml< persistence:managed- persistence- context name= "entityManager"ent ity- manager- factory= "#{entityManagerFactory}" auto- create= "true"/ >

@In EntityManager entityManager

Page 46: Spring in to Seam

46

Regifting the persistence manager for Spring

> Need to give the Seam- managed persistence context back to Spring

> Spring isn't aware of the switch

applicationContext.xml< bean id= "entityManagerFactorySpring" class= "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> ...< / bean>< bean id= "entityManagerFactory" class= "org.jboss.seam.ioc.spring.SeamManagedEntityManagerFactoryBean"> < property name= "persistenceContextName" value= "entityManager"/ >< / bean>

components.xml< persistence:managed- persistence- context name= "entityManager"ent ity- manager- factory= "#{entityManagerFactorySpring}" auto-create= "true"/ >

the one Spring will use

Page 47: Spring in to Seam

47

Visualizing the persistence hand- off

Page 48: Spring in to Seam

48

How Seam cleans up the mess

> Seam prevents Spring from closing the persistence manager

– Persistence context 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 exceptions; no need to use merge()

> Spring can transparently inject Seam- managed persistence context into @PersistenceContext property on Spring bean

Page 49: Spring in to Seam

49

One transaction to rule them all

> Don't want two different transaction managers for one resource

> Addit ionally, Seam wraps each request in two transactions

– One from Restore View phase until after Invoke Applicat ion 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>

components.xml< spring:spring- transaction platform- transaction-manager= "#{txManager}"/ >

must be Seam's version

Page 50: Spring in to Seam

50

Guice integration on the horizonWe gave you EJB 3...

Next, we gave you Spring...

Now, we give you Guice!

@Name("cafe")@Guicepublic class Cafe { @Inject private Juice juiceOfTheDay; @Inject @Orange private Juice anotherJuice; / / ...

}

public class CafeModule implements Module { public void configure(Binder binder) { binder.bind(Juice.class) .toInstance(new JuiceImpl("Apple Juice", 10)); binder.bind(Juice.class) .annotatedWith(Orange.class) .toInstance(new JuiceImpl("Orange Juice", 12)); }}

< guice:injector name= "cafeInjector"> < guice:modules> < value> ...guice.CafeModule< / value> < / guice:modules>< / guice:injector>< guice:init injector= "#{cafeInjector}"/ >

Injection by type

Page 51: Spring in to Seam

51

Wrap up

> Spring and Seam are not mutually exclusive

> 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, proxy factories, and exporters

– Seam can handle conversational state

– Seam can manage the persistence context correctly

Page 52: Spring in to Seam

Dan Allen http:/ / mojavelinux.comTetraTech, Inc. [email protected]


Recommended