I’ve come up with (IMHO) a somewhat cleaner way to integrate with Spring than shown in the FAQ (see
ticket #4132 ) . I’m curious if other folks have comments.
The basic idea is if
com.example.MyApplication is your
Application subclass, then you use this new class
AutowiringApplicationServlet (visible
here )to automatically wire up your application:
When it gets created, your MyApplication will be automatically configured from the containing application context, i.e., any @Autowired , @Required annotations and interfaces such as
BeanFactoryAware will be respected, just as if the bean had been defined directly in the application context.
This is the cleanest and simplest way to do it I’ve found… are there even better/cleaner ways out there? Thanks.
You can autowire your Application class as your example shows, but how about other classes? In a large web app, you will no doubt have a lot of CustomComponents and other classes which you will need to autowire.
There’s a project in incubator which uses the same methods you do. It provides autowiring by passing a SpringAwareApplication reference through constructors which take care of the autowiring:
Just a while back I was considering on improving the project by making the autowiring through a static method which has access to Spring. But then I got the context:spring-configured to work with help from Petri Hakala and Henri Sara and it’s been a lot easier to work with. Here’s a thread where we discussed it:
You just stick them in your application context… the same one (or a parent).
In other words, everything is setup just like a normal Spring MVC web application, with ContextLoaderListener, DispatcherServlet, etc. The
AutowiringApplicationServlet just serves to connect your
Application to the Spring context that it’s already living within.
The Vaadin Application (
MyApplication in the example) acts just like any other bean in the
dispatcher-servlet.xml application context. Everything works just like a normal Spring MVC setup… which is the whole point, right?
Specifically, this kind of thing works:
public class HelloWorld extends Application {
@Autowired
private UserDAO userDAO;
@Override
public void init() {
Window mainWindow = new Window("HelloWorld Demo");
Label label = new Label("userDAO = " + this.userDAO);
mainWindow.addComponent(label);
setMainWindow(mainWindow);
}
}
For completeness, here’s some snippets from
web.xml :
Archie, would you mind posting complete versions of your .xml files (web, applicationContext and dispatcher-servlet) for your example?
I’m new to Spring MVC (but not to Spring), Web applications and Vaadin, and I’m having trouble getting an example based on your post running. Everything appears to be created properly (logging shows all the beans are being created), but when Vaadin runs the application class, it dies on a NullPointerException, because a bean that should have been injected into the main class is not there.
I’m wondering if I’ve got something my versions of the files that is messing something up, or maybe I’m missing something?
I managed to figure it out. As I suspected, I had extra code in the web.xml files that was getting in the way. Specifically, I still had the default Vaadin entries in the file. Once I removed those, things were working as expected.
I would still like to see your .xml files, though.
There are definite upsides to this kind of integration. One thing I really like is that you don’t need to mess with application wide xml configuration just to integrate with Vaadin, it acts like just another servlet. This should make it easier to add Vaadin to existing projects and use other technologies besides Vaadin.
The
demo.zip that I uploaded demonstrates the Spring “MVC” approach using the
DispatcherServlet , URL mappers, and Spring “controller” beans.
You can also do a simpler thing, which is to map the
AutowiringApplicationServlet directly into your
web.xml . With this approach, you still get your
applicationContext.xml thanks to Spring’s
ContextLoaderListener , but there’s no
DispatcherServlet involved… and so your
web.xml just looks like this:
Those solutions looks very good for me also. Tomorrow I have to test that demo2 with vaadin Portlet 2.0. I am trying to get my Service connected to application class.
I am new to Vaadin. My current application uses spring mvc, security etc. Before I invest time in Vaadin, I want to know any problem to integrate spring mvc and spring security with Vaadin.
Absolutely wonderful. I just started investigating Vaadin, and I did NOT like the idea of having to rework my entire application just to integrate it. Right now, everything in my app goes through Spring Framework, Spring MVC and Spring Security, and I didn’t want to have to invert things by making a Vaadin-based servlet be the main dispatcher. I only plan on sprinkling parts of my application with Vaadin and leaving everything else alone, so by doing it your way I get the best of both worlds. IMHO, it should go like this: Spring → Vaadin, and not Vaadin → Spring.
(Sorry for reviving this thread, if anyone takes offense)
What about the scope of these Vaadin components when you have them managed by Spring? Surely they’d have to be scoped on “prototype” in order not to share component state across sessions? Will everything be cleaned up correctly when sessions expire?
That’s fine. Forum is open for everyone and everyone is welcomed to comment.
Indeed you are right here. Although the original approach (configuration files, AutowiringApplicationServlet) aim to populate application-wide beans (like services) into Vaadin application. But of course you can use Spring to create session-wide beans, and you need “prototype” option for these beans. In my application I need to create several objects per session, so I use “ApplicationContext” injected into my application and create beans manually.
I hope the once day the real support for “session” type will be added.
All I’ve done is added spring’s RequestContextListener to web.xml, defined the bean to be injected with the scope of session in my spring beans file, and marked it as autowired in the code.
Thank you for example. I believe, you also have
org.springframework.web.context.ContextLoaderListener in your web.xml to create Spring application context on Web application startup. I am not familiar with
RequestContextListener , but from Javadocs I got that this class exposes the request attributes (e.g.
HttpServletRequest and
HttpSession objects) to application via thread local variable so that they are available within the lifespan of request. I have not found any direct relation between that class and support of “session”-scoped beans. One need something that will create
WebApplicationContext instance and I know only one class capable to do this:
org.springframework.web.servlet.DispatcherServlet . So:
If you use
DispatcherServlet in your web.xml and forward the requests to Vaadin servlet, then everything is clear. But you don’t need
ContextLoaderListener then.
If you don’t use it and dispatch all requests to Vaadin – there is some magic behind. I wonder, who creates the Web Context then?
[quote]
If you don’t use it and dispatch all requests to Vaadin – there is some magic behind. I wonder, who creates the Web Context then?
[/quote] I’m pretty sure it’s the RequestContextListener but I could be wrong. [1]
Honestly, in my simple world (!), I just
a) added the ContextLoaderListener & RequestContextLoaderListener to web.xml
b) configured the ContextLoaderListener with the spring XML files
c) added the autowire stuff to my code
And away I went.
I am using loadtime weaving, if that’s relevant. Not sure it is, though… Maybe I should knock together a simple project.
Cheers,
Charles.
[1]
Some Time Later
I can confirm that it is the RequestContextListener that’s sprinkling some magic pixie dust over the setup. If I comment it out of my web.xml, I get the following exception - which is clearly where I found out that I had to add the RequestContextListener!
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:123)
org.springframework.web.context.request.SessionScope.get(SessionScope.java:90)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:844)
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:786)
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:283)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374)
org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:140)
org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:59)
org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$before$org_springframework
The
ContextLoaderListener is a servlet context listener that associates a Spring application context with your servlet context and makes it accessible to other Spring classes. Typically this is defined via an
applicationContext.xml file that sits in
WEB-INF .
The
RequestContextListener is a servlet filter that, at the start of each request, stuffs a reference to the request object etc. in a private ThreadLocal variable so that other Spring classes that want to answer the question “what is the current HTTP request associated with this thread?” can get the answer to that question by invoking the appropriate static method.
The
DispatcherServlet is a regular Java servlet that Spring provides. Each such servlet has its own Spring application context - distinct from, though a “child” of, the one mentioned above associated with the
ContextLoaderListener . If your servlet is named
foobar then the default XML file name is
foobar-servlet.xml .
The autowiring of your Vaadin application using the
AutowiringApplicationServlet can be done at either level, i.e., using the
ContextLoaderListener context or using the
DispatcherServlet context. Examples of both are given in previous posts to this thread (
here and
here , respectively).
Regarding session scope, this is supported by Spring and works just fine, and does not have any direct interaction with whether you are using Vaadin or not. Of course, Vaadin applications are also “session scoped”, so there is a natural usage correspondence.
In my own experience, I have not used session scoped Spring beans much. Instead, I usually end up having almost all beans be stateless singletons, such as DAO’s and service beans.