sunnuntai 6. maaliskuuta 2011

Vaadin Spring integration

Q:

What is the simplest way to integrate Spring into Vaadin? I want to able to access my Spring beans in custom Vaadin Components through annotated, automatically-injected fields. Injecting the main Application class only will not be enough.

A:

One way to enable Spring dependency injection features in Vaadin application is to use two of Spring's servlet lifecycle listeners and a custom injector. One listener handles creation of application context when the web application is initialized the first time. The second listener will activate on each request, and bind the application context to current thread. The custom injector is then called during Vaadin component initialization and is responsible for looking up application context from the current thread and injecting annotated fields of the component.

This way there will be no need for byte-weaving libraries run during compilation and other trickery. The only drawback is that each component must explicitly call the injector in its constructor. Maybe one day Vaadin will include a component instantiation listener similar to Wicket that could be used to handle this automatically.


web.xml
<web-app>

    <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <listener>
      <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    ...

</web-app>

Custom injector
public class Injector {

    public static void inject(Component component) {
        inject(component, getApplicationContext());
    }

    private static ApplicationContext getApplicationContext() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        HttpSession session = request.getSession(false);
        return WebApplicationContextUtils.getRequiredWebApplicationContext(session.getServletContext());
    }

    private static void inject(Component component, ApplicationContext applicationContext) {
        AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
        beanFactory.autowireBeanProperties(component, AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT, false);
    }
}

Vaadin component wanting to use Spring beans must call Injector.inject() during component initialization
public class ExampleComponent implements Component {

    @Autowired
    private SpringService springService;

    public ExampleComponent() {
         Injector.inject(this);
    }

}

A sample application based on Vaadin Maven archetype that demonstrates the use of this approach, download psp-vaadin-spring.zip.

2 kommenttia:

  1. Thanks for the example, how ever the applicaionContext.xml was not valid and not correct. It is working with:

    VastaaPoista
  2. Mike, you're correct. I fixed the sample app.

    VastaaPoista