Wednesday, August 13, 2014

Spring for Java EE Developers - Part 2

The second installment in my series of blog posts about transitioning to Spring when coming from Java EE (or maybe other DI frameworks).    See  Spring for Java EE Developers for the first post.   This time I'll be diving in to some more details.

 Factories

In CDI there is @Producer, and in Guice there is the Provider<T> interface.   These are very useful when you have some run-time decisions to make about what object to produce or how to configure it.   So, how do you make a factory in Spring?

Method 1 - Make a configuration bean

One simple way to create a factory in Spring is to add a @Configuration bean.   Factory methods can be annotated with @Bean, and the factory method parameters will be injected.   You will need to add CGLIB to your (run time) dependencies if you want this to work properly.

  1. Make sure you have cglib in your dependency list.
  2. Add <context:annotation-config/> to your applicationContext.xml (or other XML configuration).
  3. Create a class in a package that is scanned for annotations, and annotate it with @Configuration.
  4. Each method in the @Configuration class that produces a bean should be annotated with @Bean.   Parameters to the @Bean methods will be injected automatically, and can have @Value and @Qualifier annotations.

Method 2 - Make a factory bean / factory method

Another way is to use factory-bean and factory-method.
  1. Register the factory bean.  For example:

    <bean id="thingFactory" class="eg.ThingFactory"/>

    Where eg.ThingFactory has a method public Thing getThing()
     
  2. Register the produced object by referencing a method on the factory bean.
     
    <bean id="thing" factory-bean="thingFactory" factory-method="getThing"/>
    
    
    Spring will then call the getThing() method on the ThingFactory to get the instance.

Injecting values vs beans

In other DI frameworks, injecting a String is the same as injecting any other component.

In the Spring bean XML format, there is a difference between injecting a "value" vs injecting another bean.    To inject a bean, use ref="someBeanId" (a.k.a. bean 'name').   To inject a value, use value="some value or Spring EL".

Using Spring annotations, you can add  @Qualified for a named bean implementation (if there are more than one), and @Value to specify a Spring EL expression.

Transactional Beans

In EJB3, there are some simple transaction annotations that allow you to declare the transaction support you want for your business logic.   Spring has a very similar feature.

@Transactional - provides transaction control.   Very similar to EJB3 - class level and method level control. 

<tx:annotation-driven/> enables the transaction annotation support.

You can also use TransactionTemplate for  programmatic control when needed.

Post-Commit Actions and Transaction Synchronization

Use TransactionSynchronizationManager to get an interface that is similar to JTA Transaction.registerSynchronization().   Something like this:

TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter()
    {
           void afterCommit()
           {
                // ... do stuff ...
           }
    });

A few notes on this:
  • If this is used outside of a transaction, the method will fail.   You can have it call the 'after commit' immediately if not inside a transaction, or just let it throw an error and fix the problem.
  • TransactionSynchronizationManager is not an injectable thing.   You have to use the static methods.
  • TransactionSynchronizationAdapter is an empty implementation of TransactionSynchronization that you can use to override specific methods.   Pretty handy.
See this question on SO.

Next Time...

In the next post I'll try to cover Extended Persistence Contexts and some of the web MVC stuff. 

No comments:

Post a Comment