Spring into Seam, Part 1: Build a Spring-Seam hybrid component

Which is better, Seam or Spring? Learn why you don't have to choose

1 2 3 4 5 6 Page 6
Page 6 of 6

On becoming a Seam component

As was mentioned earlier, when a <seam:component> tag is detected inside of a <bean> element, Seam's NamespaceHandler implementation wraps the Spring bean in an instance of SpringComponent and registers it with the Seam container, making the Spring bean a full-fledged Seam component. That means that when a method is invoked on the Spring bean, all the normal Seam interceptors are applied. Think about that for a moment. You can now use all of Seam's bijection goodness in your Spring beans! Let's assume that a Spring bean named tournamentDao, responsible for performing searching against the database, is also setup as a Spring-Seam hybrid component as explained above. Listing 11 shows how this data access object can be injected into the tournament manager business object using Seam's @In annotation, an alternative to using Spring's dependency injection mechanism. Additionally, Seam's @Logger annotation is used to instantiate and inject a logger.

Listing 11. Using bijection in a Spring bean

public class TournamentManagerImpl implements TournamentManager {
    @Logger
    private Log log;
    
    @In
    private TournamentDao tournamentDao;

    public List<Tournament> findTournaments(TournamentSearchCriteria searchCriteria) {
        if (searchCriteria == null) {
            log.debug("Fetching all tournaments");
            return tournamentDao.getAllTournaments();
        }
        else {
            log.debug("Performing a criteria-based search for tournaments");
            return tournamentDao.searchTournaments(searchCriteria);
        }
    }

    public void setTournamentDao(TournamentDao tournamentDao) {
        this.tournamentDao = tournamentDao;
    }
}

Now we need to supply the search criteria argument to the finder method and capture the result. That is done through the use of a factory defined in the Seam component descriptor (components.xml). The finder method is referenced as a value expression and the return value is bound to a Seam context variable using

<factory name="tournamentResults" value="#{tournamentManager.findTournaments(tournamentSearchCriteria)}"/>

Notice that the value expression takes advantage of the JBoss EL, which allows a parameter to be passed to a method, in this case the conversation-scoped search criteria. It's now possible to iterate over the search results in the user interface by referencing the value expression

#{tournamentResults}

. You could also take advantage of additional Seam annotations, such as

@Factory

,

@Restrict

,

@RaiseEvent

,

@Observer

, and

@Transactional

, to name a few.

If you would rather not dirty your Spring beans with Seam interceptors, preferring to leave your Spring beans pristine, you can disable Seam interceptors by setting the intercept attribute of <seam:component> to false. Disabling interceptors can improve performance, especially if you aren't going to be using any of the functionality they provide anyway. The change to the definition is shown in bold in Listing 12.

Listing 12. Disabling Seam interceptors

<bean id="tournamentManager" class="org.open18.partner.business.impl.TournamentManagerImpl"> <seam:component intercept="false"/>

</bean>

Auto-create components and container initialization
When the two containers are started in isolation, the load order again reaches a deadlock when auto-create hybrid components are formed from Spring singleton beans. If the Spring container is started first, then when the auto-create variable is registered, an error will be thrown that complains that you are attempting to invoke a Seam component outside of an initialized application. If the Seam container is started first, then when the auto-create variable is registered, an error will be thrown stating that the application scope is not active. In both cases, the Spring initialization process is operating outside of the boundaries of the Seam initialization process. To remedy this problem, and any other intercontainer dependencies, it is best to allow Seam to start Spring.

With or without interception enabled, you can still use Seam's component configuration mechanism to set initial property values on a Spring-Seam hybrid component. This includes log injection for the field or property accessor decorated with @Logger. However, customizing properties through Seam should probably be used sparingly (perhaps only for environment-specific overrides) since it can confuse other developers -- or perhaps even you, down the road -- when attempting to get a complete picture of the component definition. The recommendation is to use Spring's property configuration mechanism instead.

Spring-Seam hybrid components, by default, are configured to be auto-created. However, in this case, the term is a bit misleading. That's because the Spring bean may already be initialized at the time the context variable is first requested, perhaps because it was created when the Spring container started. But Seam still considers the context variable uninitialized at this point, because Seam hasn't yet consulted the Spring container to determine if the bean has been created. Thus, the auto-create attribute on <seam:component> really means "attempt to resolve the Spring bean without being told to do so." If this is not the desired behavior, you can disable it by changing the value of the auto-create attribute of <seam:component> to false, as in Listing 13.

Listing 13. Disabling automatic lookup

<bean id="tournamentManager" 
  class="org.open18.partner.business.impl.TournamentManagerImpl">
  <seam:component auto-create="false"/>
</bean>

The auto-create setting is especially relevant considering that most Spring-Seam hybrid components are stateless, resulting in a context variable that is never permanently initialized. Thus, you will likely always want the value of the auto-create attribute to be true. If its value is false, then it necessitates the use the create flag on the @In annotation when referencing the corresponding context variable. EL value expressions that reference the context variable are not affected, since they perform the lookup implicitly.

Upon the context variable being requested, if the create flag is true and if the Spring bean exists, it will be returned to Seam. If the create flag is true and the Spring bean doesn't exist, the Spring container will attempt to create it, and then return the instance to Seam. If the create flag is false, no attempt will be made to communicate with the Spring container.

The best of both worlds

You can now use Spring beans as needed in your Seam application. The Spring Framework is filled with potential Seam components and convenient functionality. I would be a fool to tell you otherwise. Supplementing Seam with Spring will likely prove to be very valuable to the success of your application. Why choose?

In fact, Seam can even make Spring beans better by teaching them a thing or two about maintaining application state -- and you'll learn how that works in the next article in this series. Until then, you can try building your own Spring-Seam hybrid components to get a feel for how the two frameworks complement each other.

Dan Allen is an independent software consultant, author, and open source advocate. After graduating from Cornell University with a degree in Materials Science and Engineering in 2000, Dan became captivated by the world of free and open source software, which is how he got his start in software development. He soon discovered the combination of Linux and the Java EE platform to be the ideal blend on which to build his professional career. In his search for a robust Web framework, Dan happened upon JBoss Seam, which was quickly granted this most coveted spot in his development toolbox. Excited about Seam, Dan decided to share his thoughts with the world. He is now the author of Seam in Action, published by Manning Publications, a project which he picked up immediately after completing his three-part series on Seam for IBM developerWorks. Dan is also a committer on the Seam project, an active participant in the Seam community, and a Java blogger. You can keep up with Dan's development experiences by subscribing to his blog at www.mojavelinux.com.

Learn more about this topic

1 2 3 4 5 6 Page 6
Page 6 of 6