sitelink1 | |
---|---|
sitelink2 | |
sitelink3 | http://1 |
extra_vars4 | ko |
extra_vars5 | http://directwebremoting.org/dwr/server/spring |
extra_vars6 | sitelink1 |
DWR and Spring
Initial considerations
- DWR 3 requires Spring version 2.5 or greater. Make sure you have the appropriate version of Spring.
- Make sure you are happy with everything on the getting started page.
- Make sure your Spring beans work properly outside of DWR (unit test).
- Select the configuration style based on your Spring version (see below).
- Configure DWR to work with Spring (see below).
- Look at the demo pages:
http://localhost:[PORT]/[YOUR-WEBAPP]/dwr/index.html
to check that your spring beans appear.
Step 1 - Give DWR access to the Spring context
In order to integrate DWR with Spring, DWR needs to gain access to the Spring context. There are two options here:
Use Spring MVC
If you are using Spring MVC your web.xml should look something like this:
<servlet> <servlet-name>springDispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:yourSpringContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springDispatcher</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>springDispatcher</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping>
The only thing you need to add is the mapping of /dwr/* to the Spring dispatcher servlet. A complete working example of this configuration can be found here.
Use the DWRSpringServlet
The DwrSpringServlet can be used if you are not using Spring MVC. This servlet gains access to the Spring context configured in your web.xml. Necessary web.xml configuration:
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:yourSpringContext.xml </param-value> </context-param> <servlet> <servlet-name>dwr</servlet-name> <servlet-class>org.directwebremoting.spring.DwrSpringServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dwr</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping>
A complete working example of this configuration can be found here.
Step 2 - Configure DWR's remoting
The next and final step is to configure DWR's remoting - once again there are several options. In the past (3 below) this step was accomplished in the dwr.xml via Creators and Converters. However, Spring 2.x introduced a new feature named XML Namespace Handlers. This allows DWR and Spring MVC to remote Spring beans easily with a custom syntax and removes the need for dwr.xml. Configuration for the custom namespace is covered in 1 and 2 below.
- Use the DWR/Spring namespace (Spring 2.5 or greater, DWR 2.x or greater, dwr.xml not required or recommended)
- Use the DWR/Spring namespace with annotations (Spring 2.5 or greater, DWR 2.x or greater, dwr.xml not required or recommended)
- Use the DWRSpringServlet (Will work for older versions of Spring or DWR - dwr.xml required. Not the recommended approach.)
The namespace
The first task you need to accomplish is adding the following lines (in bold, below) to any of your Spring XML files that includes at least one DWR specific tag. Add them inside the beans
declaration (at the beginning of the file):
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd">
The controller tag
If you are not using Spring MVC - skip this section. The controller tag only applies to Spring MVC configurations.
If you are using Spring MVC you must declare one <dwr:controller id="dwrController" debug="true" />
tag. This tag does not allow inner tags and the id attribute is optional.
In Spring MVC, for each controller you have to map the URLs that it will handle. The simplest way to do this is by using the <dwr:url-mapping />
tag. If you use the url-mapping tag the DWR test page will be unavailable.
Alternatively, you may specify your own SimpleUrlHandlerMapping. DWR needs mappings for the following URLs: /engine.js, /interface.js, /call/**, /interface/**
. An example of a SimpleUrlHandlerMapping that will allow the DWR test page to work can be found here (see step 2, numbered item 3).
The configuration tag
The <dwr:configuration/>
is used to mimic the behavior of the configuration available indwr.xml. This tag is optional and it may have nested tags (init, creator, signatures,..). These nested tags mimic the behavior of those available in dwr.xml. Example:
<dwr:configuration> <dwr:convert type="bean" class="org.uk.ltd.dwr.dev.model.Address" /> </dwr:configuration>
The remote tag
Inside each bean you want to remote include a <dwr:remote javascript="Fred">
tag. There you can specify the methods that are going to be proxied and those that won't. For example:
<bean id="timeConvert" class="com.mycompany.ui.util.TimeConvert">
<dwr:remote javascript="AjaxTimeConvert">
<dwr:include method="convert" />
</dwr:remote>
</bean>
Exposing beans in other application contexts - the proxy-ref element
It is also possible to remote a bean already defined in a reachable application context indicating the reference to it by using the proxy-ref element.
Two complete (one with Spring MVC, one without) working examples of DWR and Spring using the namespace can be found here.
The namespace with Annotations
Please see The namespace before reading this section. Several of the namespace sections apply to annotation configuration as well.
If you would like to use annotations to remote your Spring beans DWR provides two tags that make it easy.
- annotation-scan - Enables DWR to scan the classpath, detect beans annotated with @RemoteProxy & @RemoteMethod and register the beans and Creator proxies for them. This element has several available attributes:
- base-package - The base package to initiate scanning from - i.e. com.myApp.*.
- regex - A regular expression that will be used in the classpath scanner.
- scanRemoteProxy - Should DWR scan for remote proxies? Defaults to true.
- scanDataTransferObject - Should DWR scan for converters? Defaults to true.
- scanGlobalFilter - Defaults to true.
- annotation-config - Enables DWR to scan the Spring context, detect beans annotated with @RemoteProxy & @RemoteMethod and register Creator proxies for them.
A complete working example of this configuration can be found here.
The Spring Creator and dwr.xml
If you feel comfortable using dwr.xml you may use the Spring creator. This creator will lookup beans in your Spring <beans>.xml file and rely on Spring to instantiate them. This creator will be useful to you if you already use Spring and totally useless if you don't.
You allow DWR to use the spring creator to create and remote your beans as follows:
<allow> ... <create creator="spring" javascript="Fred"> <param name="beanName" value="Shiela"/> </create> ... </allow>
There are several ways to find your spring configuration files:
Spring MVC
Define a DispatcherServlet and declare the beans in <dispatcher>-servlet.xml. There are no specifics for DWR remoted beans.ContextLoaderListener
For other MVC frameworks.Using location* parameters
If you prefer to specify which beans.xml to use in your dwr.xml file then you can use a location* parameter. You can specify as many as you wish although the names must be unique and start 'location'. For example: location-1, location-2. These locations are used as parameters to a Spring ClassPathXmlApplicationContext:<allow> ... <create creator="spring" javascript="Fred"> <param name="beanName" value="Shiela"/> <param name=location value="beans.xml"/> </create> ... </allow>
Setting the BeanFactory directly
The SpringCreator has a staticsetOverrideBeanFactory(BeanFactory)
method that provides a way to programatically override any BeanFactories found by other means (if any).
Please, take into account that not all methods are equally easy in practice. Probably, unless you know what you're doing you're better served using one of the first two.
Common Problems
Scoped Beans
One of the common pitfalls when integrating Spring and DWR are scoped beans (session, request, ...). In practice is easy to get them going, just remember two basic rules.
- Always declare and implement an interface with the remoted methods.
- Remember to include
<aop:scoped-proxy proxy-target-class="false" />
in the bean declaration
Here's an example:
<bean id="calc" class="...CalculatorImpl" scope=session>
<dwr:remote javascript="Calculator">
<dwr:include method="add"/>
</dwr:remote>
<aop:scoped-proxy proxy-target-class="false" />
</bean>
Aspects & DWR
If you're receiving the dreaded object is not an instance of declaring class
error always check the following:
- You have an interface and an implementation
- You have declared
<aop:aspectj-autoproxy proxy-target-class="false" />
in your Spring XML - You have decorated your remoted bean with
<aop:scoped-proxy />
Mappings! Mappings! Mappings!
It is important to note that the creation of the SimpleUrlHandlerMapping may cause your existing mappings to fail if you have not explicitly created a Handler Mapping in your Spring configuration. By default Spring creates a BeanNameUrlHandlerMapping if you have not explicitly created a Handler Mapping. So when the SimpleUrlHandlerMapping is created for DWR, Spring will no longer create the default BeanNameUrlHandlerMapping and existing mappings will not work. Spring allows you to have multiple Handler Mappings, to fix this you need to create a BeanNameUrlHandlerMapping explicitly in your spring.xml (in addition to the SimpleUrlHandlerMapping). See the Spring documentation section 13.4.1 for more information.
Id is required for element 'annotation-config' when used as a top-level tag
This appears to be happening with Spring 3.x and above. We use a Spring class to parse the annotation-config element and if you do not specify an id the parse is unhappy. For now a solution to this appears to be simply adding an id attribute.