From ab99e54a03cacbd51e11282134d2e1ab7adeb144 Mon Sep 17 00:00:00 2001 From: Thomas Risberg Date: Tue, 19 May 2009 23:45:19 +0000 Subject: [PATCH] updated code examples with generics; took out Java 1.4 references; polished git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1222 50f2f4bb-b051-0410-bef5-90022cba6387 --- spring-framework-reference/src/remoting.xml | 1193 +++++++++++-------- 1 file changed, 727 insertions(+), 466 deletions(-) diff --git a/spring-framework-reference/src/remoting.xml b/spring-framework-reference/src/remoting.xml index aac4e6d7cad..5f0be3158e9 100644 --- a/spring-framework-reference/src/remoting.xml +++ b/spring-framework-reference/src/remoting.xml @@ -1,146 +1,179 @@ - +"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> Remoting and web services using Spring
Introduction - Spring features integration classes for remoting support using various - technologies. The remoting support eases the development of remote-enabled - services, implemented by your usual (Spring) POJOs. Currently, Spring supports - four remoting technologies: - - - Remote Method Invocation (RMI). Through the use - of the RmiProxyFactoryBean and the - RmiServiceExporter Spring supports both traditional - RMI (with java.rmi.Remote interfaces and - java.rmi.RemoteException) and - transparent remoting via RMI invokers (with any Java interface). - - - Spring's HTTP invoker. Spring provides a special - remoting strategy which allows for Java serialization via HTTP, - supporting any Java interface (just like the RMI invoker). The corresponding - support classes are HttpInvokerProxyFactoryBean and - HttpInvokerServiceExporter. - - - Hessian. By using Spring's - HessianProxyFactoryBean and the - HessianServiceExporter you can transparently - expose your services using the lightweight binary HTTP-based protocol - provided by Caucho. - - - Burlap. Burlap is Caucho's XML-based - alternative to Hessian. Spring provides support classes such - as BurlapProxyFactoryBean and - BurlapServiceExporter. - - - JAX-RPC. Spring provides remoting support - for web services via JAX-RPC (J2EE 1.4's web service API). - - - JAX-WS. Spring provides remoting support - for web services via JAX-WS (the successor of JAX-RPC, as introduced - in Java EE 5 and Java 6). - - - JMS. Remoting using JMS as the underlying protocol - is supported via the JmsInvokerServiceExporter and - JmsInvokerProxyFactoryBean classes. - - - While discussing the remoting capabilities of Spring, we'll use the following domain - model and corresponding services: + + Spring features integration classes for remoting support using + various technologies. The remoting support eases the development of + remote-enabled services, implemented by your usual (Spring) POJOs. + Currently, Spring supports four remoting technologies: + + Remote Method Invocation (RMI). Through + the use of the RmiProxyFactoryBean and the + RmiServiceExporter Spring supports both + traditional RMI (with java.rmi.Remote + interfaces and + java.rmi.RemoteException) and + transparent remoting via RMI invokers (with any Java + interface). + + + + Spring's HTTP invoker. Spring provides a + special remoting strategy which allows for Java serialization via + HTTP, supporting any Java interface (just like the RMI invoker). The + corresponding support classes are + HttpInvokerProxyFactoryBean and + HttpInvokerServiceExporter. + + + + Hessian. By using Spring's + HessianProxyFactoryBean and the + HessianServiceExporter you can transparently + expose your services using the lightweight binary HTTP-based + protocol provided by Caucho. + + + + Burlap. Burlap is Caucho's XML-based + alternative to Hessian. Spring provides support classes such as + BurlapProxyFactoryBean and + BurlapServiceExporter. + + + + JAX-RPC. Spring provides remoting support + for web services via JAX-RPC (J2EE 1.4's web service API). + + + + JAX-WS. Spring provides remoting support + for web services via JAX-WS (the successor of JAX-RPC, as introduced + in Java EE 5 and Java 6). + + + + JMS. Remoting using JMS as the underlying + protocol is supported via the + JmsInvokerServiceExporter and + JmsInvokerProxyFactoryBean classes. + + + + While discussing the remoting capabilities of Spring, we'll use the + following domain model and corresponding services: + + getAccounts(String name); }]]> + getAccounts(String name) throws RemoteException; }]]> - // the implementation doing nothing at the moment// the implementation doing nothing at the moment public class AccountServiceImpl implements AccountService { public void insertAccount(Account acc) { - ]]>// do something...// do something... } - public List getAccounts(String name) { - ]]>// do something...// do something... } -}]]> - We will start exposing the service to a remote client by using RMI and - talk a bit about the drawbacks of using RMI. We'll then continue to show - an example using Hessian as the protocol. +} + + We will start exposing the service to a remote client by using RMI + and talk a bit about the drawbacks of using RMI. We'll then continue to + show an example using Hessian as the protocol.
Exposing services using RMI - Using Spring's support for RMI, you can transparently expose your services through - the RMI infrastructure. After having this set up, you basically have a configuration - similar to remote EJBs, except for the fact that there is no standard support for - security context propagation or remote transaction propagation. Spring does provide - hooks for such additional invocation context when using the RMI invoker, so you can - for example plug in security frameworks or custom security credentials here. + + Using Spring's support for RMI, you can transparently expose your + services through the RMI infrastructure. After having this set up, you + basically have a configuration similar to remote EJBs, except for the fact + that there is no standard support for security context propagation or + remote transaction propagation. Spring does provide hooks for such + additional invocation context when using the RMI invoker, so you can for + example plug in security frameworks or custom security credentials + here.
- Exporting the service using the <classname>RmiServiceExporter</classname> - Using the RmiServiceExporter, we can expose the interface - of our AccountService object as RMI object. The interface can be accessed by using - RmiProxyFactoryBean, or via plain RMI in case of a traditional - RMI service. The RmiServiceExporter explicitly supports the - exposing of any non-RMI services via RMI invokers. - - Of course, we first have to set up our service in the Spring container: - - ]]><!-- any additional properties, maybe a DAO? -->]]> - Next we'll have to expose our service using the RmiServiceExporter: - - ]]><!-- does not necessarily have to be the same name as the bean to be exported --> - - - ]]><!-- defaults to 1099 --> -]]> - As you can see, we're overriding the port for the RMI registry. Often, - your application server also maintains an RMI registry and it is wise - to not interfere with that one. Furthermore, the service name is used to bind the - service under. So right now, the service will be bound at - 'rmi://HOST:1199/AccountService'. We'll use the URL later on to - link in the service at the client side. + Exporting the service using the + <classname>RmiServiceExporter</classname> + + Using the RmiServiceExporter, we can expose + the interface of our AccountService object as RMI object. The interface + can be accessed by using RmiProxyFactoryBean, or + via plain RMI in case of a traditional RMI service. The + RmiServiceExporter explicitly supports the + exposing of any non-RMI services via RMI invokers. + + Of course, we first have to set up our service in the Spring + container: + + <bean id="accountService" class="example.AccountServiceImpl"> + <!-- any additional properties, maybe a DAO? --> +</bean> + + Next we'll have to expose our service using the + RmiServiceExporter: + + <bean class="org.springframework.remoting.rmi.RmiServiceExporter"> + <!-- does not necessarily have to be the same name as the bean to be exported --> + <property name="serviceName" value="AccountService"/> + <property name="service" ref="accountService"/> + <property name="serviceInterface" value="example.AccountService"/> + <!-- defaults to 1099 --> + <property name="registryPort" value="1199"/> +</bean> + + As you can see, we're overriding the port for the RMI registry. + Often, your application server also maintains an RMI registry and it is + wise to not interfere with that one. Furthermore, the service name is + used to bind the service under. So right now, the service will be bound + at 'rmi://HOST:1199/AccountService'. We'll use the + URL later on to link in the service at the client side. + - The servicePort property has been omitted (it defaults to 0). - This means that an anonymous port will be used to communicate with the service. + The servicePort property has been omitted (it + defaults to 0). This means that an anonymous port will be used to + communicate with the service.
Linking in the service at the client - Our client is a simple object using the AccountService - to manage accounts: + + Our client is a simple object using the + AccountService to manage accounts: + - To link in the service on the client, we'll create a separate Spring container, - containing the simple object and the service linking configuration bits: - + + To link in the service on the client, we'll create a separate + Spring container, containing the simple object and the service linking + configuration bits: + + @@ -159,27 +198,34 @@ public class AccountServiceImpl implements AccountService { ]]> - That's all we need to do to support the remote account service on the client. - Spring will transparently create an invoker and remotely enable the account - service through the RmiServiceExporter. At the client - we're linking it in using the RmiProxyFactoryBean. + + That's all we need to do to support the remote account service on + the client. Spring will transparently create an invoker and remotely + enable the account service through the + RmiServiceExporter. At the client we're linking + it in using the RmiProxyFactoryBean.
Using Hessian or Burlap to remotely call services via HTTP - Hessian offers a binary HTTP-based remoting protocol. It is developed by - Caucho and more information about Hessian itself can be found at - . + + Hessian offers a binary HTTP-based remoting protocol. It is + developed by Caucho and more information about Hessian itself can be found + at .
- Wiring up the <classname>DispatcherServlet</classname> for Hessian and co. - Hessian communicates via HTTP and does so using a custom servlet. - Using Spring's DispatcherServlet principles, as known - from Spring Web MVC usage, you can easily wire up such a servlet exposing - your services. First we'll have to create a new servlet in your application - (this an excerpt from 'web.xml'): - + Wiring up the <classname>DispatcherServlet</classname> for + Hessian and co. + + Hessian communicates via HTTP and does so using a custom servlet. + Using Spring's DispatcherServlet principles, as + known from Spring Web MVC usage, you can easily wire up such a servlet + exposing your services. First we'll have to create a new servlet in your + application (this an excerpt from + 'web.xml'): + + remoting org.springframework.web.servlet.DispatcherServlet 1 @@ -189,47 +235,66 @@ public class AccountServiceImpl implements AccountService { remoting /remoting/* ]]> - You're probably familiar with Spring's DispatcherServlet - principles and if so, you know that now you'll have to create a Spring container - configuration resource named 'remoting-servlet.xml' (after - the name of your servlet) in the 'WEB-INF' - directory. The application context will be used in the next section. + + You're probably familiar with Spring's + DispatcherServlet principles and if so, you know + that now you'll have to create a Spring container configuration resource + named 'remoting-servlet.xml' (after the name of + your servlet) in the 'WEB-INF' + directory. The application context will be used in the next + section. + Alternatively, consider the use of Spring's simpler - HttpRequestHandlerServlet. - This allows you to embed the remote exporter definitions in your root application - context (by default in 'WEB-INF/applicationContext.xml'), + HttpRequestHandlerServlet. This allows you to + embed the remote exporter definitions in your root application context + (by default in 'WEB-INF/applicationContext.xml'), with individual servlet definitions pointing to specific exporter beans. - Each servlet name needs to match the bean name of its target exporter in this case. + Each servlet name needs to match the bean name of its target exporter in + this case.
- Exposing your beans by using the <classname>HessianServiceExporter</classname> - In the newly created application context called remoting-servlet.xml, - we'll create a HessianServiceExporter exporting your services: - - ]]><!-- any additional properties, maybe a DAO? --> + Exposing your beans by using the + <classname>HessianServiceExporter</classname> + + In the newly created application context called + remoting-servlet.xml, we'll create a + HessianServiceExporter exporting your + services: + + <bean id="accountService" class="example.AccountServiceImpl"> + <!-- any additional properties, maybe a DAO? --> +</bean> + +<bean name="/AccountService" class="org.springframework.remoting.caucho.HessianServiceExporter"> + <property name="service" ref="accountService"/> + <property name="serviceInterface" value="example.AccountService"/> +</bean> + + Now we're ready to link in the service at the client. No explicit + handler mapping is specified, mapping request URLs onto services, so + BeanNameUrlHandlerMapping will be used: Hence, + the service will be exported at the URL indicated through its bean name + within the containing DispatcherServlet's mapping + (as defined above): + 'http://HOST:8080/remoting/AccountService'. + + Alternatively, create a + HessianServiceExporter in your root application + context (e.g. in + 'WEB-INF/applicationContext.xml'): - - - -]]> - Now we're ready to link in the service at the client. No explicit handler mapping - is specified, mapping request URLs onto services, so BeanNameUrlHandlerMapping - will be used: Hence, the service will be exported at the URL indicated through - its bean name within the containing DispatcherServlet's - mapping (as defined above): 'http://HOST:8080/remoting/AccountService'. - - Alternatively, create a HessianServiceExporter in your - root application context (e.g. in 'WEB-INF/applicationContext.xml'): ]]> - In the latter case, define a corresponding servlet for this exporter - in 'web.xml', with the same end result: The exporter - getting mapped to the request path /remoting/AccountService. - Note that the servlet name needs to match the bean name of the target exporter. + + In the latter case, define a corresponding servlet for this + exporter in 'web.xml', with the same end result: + The exporter getting mapped to the request path + /remoting/AccountService. Note that the servlet name + needs to match the bean name of the target exporter. + accountExporter org.springframework.web.context.support.HttpRequestHandlerServlet @@ -243,12 +308,15 @@ public class AccountServiceImpl implements AccountService {
Linking in the service on the client - Using the we can link in the service - at the client. The same principles apply as with the RMI example. We'll create - a separate bean factory or application context and mention the following beans - where the SimpleObject is using the + + Using the HessianProxyFactoryBean we can + link in the service at the client. The same principles apply as with the + RMI example. We'll create a separate bean factory or application context + and mention the following beans where the + SimpleObject is using the AccountService to manage accounts: - + + @@ -256,24 +324,31 @@ public class AccountServiceImpl implements AccountService { ]]> -
+
Using Burlap - We won't discuss Burlap, the XML-based equivalent of Hessian, in detail here, - since it is configured and set up in exactly the same way as the Hessian - variant explained above. Just replace the word Hessian - with Burlap and you're all set to go. + + We won't discuss Burlap, the XML-based equivalent of Hessian, in + detail here, since it is configured and set up in exactly the same way + as the Hessian variant explained above. Just replace the word + Hessian with Burlap and you're all + set to go.
- Applying HTTP basic authentication to a service exposed through Hessian or Burlap - One of the advantages of Hessian and Burlap is that we can easily apply HTTP basic - authentication, because both protocols are HTTP-based. Your normal HTTP server security - mechanism can easily be applied through using the web.xml security - features, for example. Usually, you don't use per-user security credentials here, but - rather shared credentials defined at the Hessian/BurlapProxyFactoryBean level - (similar to a JDBC DataSource). + Applying HTTP basic authentication to a service exposed through + Hessian or Burlap + + One of the advantages of Hessian and Burlap is that we can easily + apply HTTP basic authentication, because both protocols are HTTP-based. + Your normal HTTP server security mechanism can easily be applied through + using the web.xml security features, for example. + Usually, you don't use per-user security credentials here, but rather + shared credentials defined at the + Hessian/BurlapProxyFactoryBean level (similar to a + JDBC DataSource). + @@ -282,59 +357,78 @@ public class AccountServiceImpl implements AccountService { class="org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor"> ]]> - This an example where we explicitly mention the BeanNameUrlHandlerMapping - and set an interceptor allowing only administrators and operators to call - the beans mentioned in this application context. + + This an example where we explicitly mention the + BeanNameUrlHandlerMapping and set an interceptor + allowing only administrators and operators to call the beans mentioned + in this application context. + Of course, this example doesn't show a flexible kind of security - infrastructure. For more options as far as security is concerned, - have a look at the Acegi Security System for Spring, to be found at - . + infrastructure. For more options as far as security is concerned, have + a look at the Acegi Security System for Spring, to be found at .
- -
- Exposing services using HTTP invokers - As opposed to Burlap and Hessian, which are both lightweight protocols using their - own slim serialization mechanisms, Spring Http invokers use the standard - Java serialization mechanism to expose services through HTTP. This has a huge - advantage if your arguments and return types are complex types that cannot be - serialized using the serialization mechanisms Hessian and Burlap use (refer to the - next section for more considerations when choosing a remoting technology). - Under the hood, Spring uses either the standard facilities provided by J2SE to - perform HTTP calls or Commons HttpClient. Use the latter if you need more advanced - and easy-to-use functionality. Refer to - jakarta.apache.org/commons/httpclient - for more info. -
- Exposing the service object - Setting up the HTTP invoker infrastructure for a service objects much resembles - the way you would do using Hessian or Burlap. Just as Hessian support provides - the HessianServiceExporter, Spring's HttpInvoker support provides - the org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter. - - To expose the AccountService (mentioned above) within a - Spring Web MVC DispatcherServlet, the following configuration - needs to be in place in the dispatcher's application context: - +
+ Exposing services using HTTP invokers + + As opposed to Burlap and Hessian, which are both lightweight + protocols using their own slim serialization mechanisms, Spring Http + invokers use the standard Java serialization mechanism to expose services + through HTTP. This has a huge advantage if your arguments and return types + are complex types that cannot be serialized using the serialization + mechanisms Hessian and Burlap use (refer to the next section for more + considerations when choosing a remoting technology). + + Under the hood, Spring uses either the standard facilities provided + by J2SE to perform HTTP calls or Commons + HttpClient. Use the latter if you need more + advanced and easy-to-use functionality. Refer to jakarta.apache.org/commons/httpclient + for more info. + +
+ Exposing the service object + + Setting up the HTTP invoker infrastructure for a service objects + much resembles the way you would do using Hessian or Burlap. Just as + Hessian support provides the + HessianServiceExporter, Spring's HttpInvoker + support provides the + org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter. + + To expose the AccountService (mentioned above) + within a Spring Web MVC DispatcherServlet, the + following configuration needs to be in place in the dispatcher's + application context: + + ]]> + Such an exporter definition will be exposed through the DispatcherServlet's standard mapping facilities, as explained in the section on Hessian. - Alternatively, create an HttpInvokerServiceExporter in your - root application context (e.g. in 'WEB-INF/applicationContext.xml'): + + Alternatively, create an + HttpInvokerServiceExporter in your root + application context (e.g. in + 'WEB-INF/applicationContext.xml'): + ]]> + In addition, define a corresponding servlet for this exporter in 'web.xml', with the servlet name matching the bean name of the target exporter: + accountExporter org.springframework.web.context.support.HttpRequestHandlerServlet @@ -344,24 +438,51 @@ public class AccountServiceImpl implements AccountService { accountExporter /remoting/AccountService ]]> + + f you are running outside of a servlet container and are using + Sun's Java 6, then you can use the built-in HTTP server implementation. + You can configure the SimpleHttpServerFactoryBean together with a + SimpleHttpInvokerServiceExporter as is shown in this example: + + + + + + + + + + + + + + +]]>
Linking in the service at the client - Again, linking in the service from the client much resembles the way you would - do it when using Hessian or Burlap. Using a proxy, Spring will be able to - translate your calls to HTTP POST requests to the URL pointing to the exported - service. - + + Again, linking in the service from the client much resembles the + way you would do it when using Hessian or Burlap. Using a proxy, Spring + will be able to translate your calls to HTTP POST requests to the URL + pointing to the exported service. + + ]]> - As mentioned before, you can choose what HTTP client you want to use. - By default, the HttpInvokerProxy uses the J2SE HTTP functionality, but - you can also use the Commons HttpClient by setting the + + As mentioned before, you can choose what HTTP client you want to + use. By default, the HttpInvokerProxy uses the + J2SE HTTP functionality, but you can also use the Commons + HttpClient by setting the httpInvokerRequestExecutor property: - + + ]]> @@ -370,43 +491,67 @@ public class AccountServiceImpl implements AccountService {
Web services - Spring provides full support for standard Java web services APIs: + + Spring provides full support for standard Java web services + APIs: + - Exposing web services using JAX-RPC - Accessing web services using JAX-RPC - Exposing web services using JAX-WS - Accessing web services using JAX-WS + + Exposing web services using JAX-RPC + + + + Accessing web services using JAX-RPC + + + + Exposing web services using JAX-WS + + + + Accessing web services using JAX-WS + + Why two standard Java web services APIs? - JAX-RPC 1.1 is the standard web service API in J2EE 1.4. - As its name indicates, it focuses on on RPC bindings, which became - less and less popular in the past couple of years. As a consequence, - it has been superseded by JAX-WS 2.0 in Java EE 5, being more flexible - in terms of bindings but also being heavily annotation-based. JAX-WS 2.1 - is also included in Java 6 (or more specifically, in Sun's JDK 1.6.0_04 - and above; previous Sun JDK 1.6.0 releases included JAX-WS 2.0), - integrated with the JDK's built-in HTTP server. - Spring can work with both standard Java web services APIs. - The choice is effectively dependent on the runtime platform: - On JDK 1.4 / J2EE 1.4, the only option is JAX-RPC. On Java EE 5 / Java 6, - the obvious choice is JAX-WS. On J2EE 1.4 environments that run on Java 5, - you might have the option to plug in a JAX-WS provider; check your J2EE - server's documentation. + + JAX-RPC 1.1 is the standard web service API in J2EE 1.4. As its + name indicates, it focuses on on RPC bindings, which became less and + less popular in the past couple of years. As a consequence, it has been + superseded by JAX-WS 2.0 in Java EE 5, being more flexible in terms of + bindings but also being heavily annotation-based. JAX-WS 2.1 is also + included in Java 6 (or more specifically, in Sun's JDK 1.6.0_04 and + above; previous Sun JDK 1.6.0 releases included JAX-WS 2.0), integrated + with the JDK's built-in HTTP server. + + Spring can work with both standard Java web services APIs. On Java + EE 5 / Java 6, the obvious choice is JAX-WS. On J2EE 1.4 environments + that run on Java 5, you might have the option to plug in a JAX-WS + provider; check your J2EE server's documentation. - In addition to stock support for JAX-RPC and JAX-WS in Spring Core, the Spring portfolio also - features Spring Web Services, a solution - for contract-first, document-driven web services - highly recommended for building modern, future-proof - web services. Last but not least, XFire also allows - you to export Spring-managed beans as a web service, through built-in Spring support. + + In addition to stock support for JAX-RPC and JAX-WS in Spring Core, + the Spring portfolio also features Spring Web + Services, a solution for contract-first, document-driven web + services - highly recommended for building modern, future-proof web + services. Last but not least, XFire also allows you to export + Spring-managed beans as a web service, through built-in Spring + support.
Exposing servlet-based web services using JAX-RPC - Spring provides a convenience base class for JAX-RPC servlet endpoint implementations - + + Spring provides a convenience base class for JAX-RPC servlet + endpoint implementations - ServletEndpointSupport. To expose our AccountService we extend Spring's - ServletEndpointSupport class and implement our business - logic here, usually delegating the call to the business layer. + ServletEndpointSupport class and implement our + business logic here, usually delegating the call to the business + layer. + /** * JAX-RPC compliant RemoteAccountService implementation that simply delegates * to the AccountService implementation in the root web application context. @@ -420,12 +565,12 @@ public class AccountServiceImpl implements AccountService { * In the case of Axis, this happens in "server-config.wsdd" respectively via * deployment calls. The web service engine manages the lifecycle of instances * of this class: A Spring application context can just be accessed here. - */import org.springframework.remoting.jaxrpc.ServletEndpointSupport; public class AccountServiceEndpoint extends ServletEndpointSupport implements RemoteAccountService { private AccountService biz; - + protected void onInit() { this.biz = (AccountService) getWebApplicationContext().getBean("accountService"); } @@ -437,27 +582,33 @@ public class AccountServiceEndpoint extends ServletEndpointSupport implements Re public Account[] getAccounts(String name) throws RemoteException { return biz.getAccounts(name); } -}]]> - Our AccountServletEndpoint needs to run in the same web - application as the Spring context to allow for access to Spring's facilities. In case of - Axis, copy the AxisServlet definition into your +} + + Our AccountServletEndpoint needs to run in + the same web application as the Spring context to allow for access to + Spring's facilities. In case of Axis, copy the + AxisServlet definition into your 'web.xml', and set up the endpoint in - 'server-config.wsdd' (or use the deploy tool). See the sample - application JPetStore where the OrderService is exposed as - a web service using Axis. + 'server-config.wsdd' (or use the deploy tool). See + the sample application JPetStore where the + OrderService is exposed as a web service + using Axis.
Accessing web services using JAX-RPC - Spring provides two factory beans to create JAX-RPC web service proxies, - namely LocalJaxRpcServiceFactoryBean and - JaxRpcPortProxyFactoryBean. The former can only return a JAX-RPC - service class for us to work with. The latter is the full-fledged version that can return - a proxy that implements our business service interface. In this example we use the latter - to create a proxy for the AccountService endpoint we exposed - in the previous section. You will see that Spring has great support for web services - requiring little coding efforts - most of the setup is done in the Spring configuration - file as usual: + + Spring provides two factory beans to create JAX-RPC web service + proxies, namely LocalJaxRpcServiceFactoryBean and + JaxRpcPortProxyFactoryBean. The former can only + return a JAX-RPC service class for us to work with. The latter is the + full-fledged version that can return a proxy that implements our + business service interface. In this example we use the latter to create + a proxy for the AccountService endpoint + we exposed in the previous section. You will see that Spring has great + support for web services requiring little coding efforts - most of the + setup is done in the Spring configuration file as usual: + @@ -465,21 +616,31 @@ public class AccountServiceEndpoint extends ServletEndpointSupport implements Re ]]> - Where serviceInterface is our remote business interface the clients will use. - wsdlDocumentUrl is the URL for the WSDL file. Spring needs this a startup time to create the JAX-RPC Service. - namespaceUri corresponds to the targetNamespace in the .wsdl file. - serviceName corresponds to the service name in the .wsdl file. - portName corresponds to the port name in the .wsdl file. - - Accessing the web service is now very easy as we have a bean factory for it that will expose it - as RemoteAccountService interface. We can wire this up in Spring: + + Where serviceInterface is our remote business + interface the clients will use. wsdlDocumentUrl is + the URL for the WSDL file. Spring needs this a startup time to create + the JAX-RPC Service. namespaceUri corresponds to the + targetNamespace in the .wsdl file. serviceName + corresponds to the service name in the .wsdl file. + portName corresponds to the port name in the .wsdl + file. + + Accessing the web service is now very easy as we have a bean + factory for it that will expose it as + RemoteAccountService interface. We can wire this up + in Spring: + ... ]]> + From the client code we can access the web service just as if it - was a normal class, except that it throws RemoteException. -RemoteException. + + public class AccountClientImpl { private RemoteAccountService service; @@ -492,22 +653,29 @@ public class AccountServiceEndpoint extends ServletEndpointSupport implements Re service.insertAccount(...); } catch (RemoteException ex) { - ]]>// ouch// ouch } } } -]]> - We can get rid of the checked RemoteException since - Spring supports automatic conversion to its corresponding unchecked - RemoteException. This requires that we provide a non-RMI - interface also. Our configuration is now: + + + We can get rid of the checked + RemoteException since Spring supports + automatic conversion to its corresponding unchecked + RemoteException. This requires that we + provide a non-RMI interface also. Our configuration is now: + + ... ]]> - Where serviceInterface is changed to our non RMI interface. Our RMI - interface is now defined using the property portInterface. Our client - code can now avoid handling java.rmi.RemoteException: + + Where serviceInterface is changed to our non + RMI interface. Our RMI interface is now defined using the property + portInterface. Our client code can now avoid handling + java.rmi.RemoteException: + - Note that you can also drop the "portInterface" part and specify a plain - business interface as "serviceInterface". In this case, - JaxRpcPortProxyFactoryBean will automatically switch - to the JAX-RPC "Dynamic Invocation Interface", performing dynamic invocations - without a fixed port stub. The advantage is that you don't even need to have - an RMI-compliant Java port interface around (e.g. in case of a non-Java target - web service); all you need is a matching business interface. Check out + + Note that you can also drop the "portInterface" part and specify a + plain business interface as "serviceInterface". In this case, + JaxRpcPortProxyFactoryBean will automatically + switch to the JAX-RPC "Dynamic Invocation Interface", performing dynamic + invocations without a fixed port stub. The advantage is that you don't + even need to have an RMI-compliant Java port interface around (e.g. in + case of a non-Java target web service); all you need is a matching + business interface. Check out JaxRpcPortProxyFactoryBean's javadoc for details on the runtime implications.
Registering JAX-RPC Bean Mappings - To transfer complex objects over the wire such as Account we must - register bean mappings on the client side. + + To transfer complex objects over the wire such as + Account we must register bean mappings on the + client side. + - On the server side using Axis registering bean mappings is usually done in - the 'server-config.wsdd' file. + On the server side using Axis registering bean mappings is + usually done in the 'server-config.wsdd' + file. - We will use Axis to register bean mappings on the client side. To do this we need to - register the bean mappings programmatically: + + We will use Axis to register bean mappings on the client side. To + do this we need to register the bean mappings programmatically: + -
+
Registering your own JAX-RPC Handler + In this section we will register our own - javax.rpc.xml.handler.Handler to the web service proxy - where we can do custom code before the SOAP message is sent over the wire. - The Handler is a callback interface. There is a convenience - base class provided in jaxrpc.jar, namely - javax.rpc.xml.handler.GenericHandler that we will extend: + javax.rpc.xml.handler.Handler to the web + service proxy where we can do custom code before the SOAP message is + sent over the wire. The Handler is a + callback interface. There is a convenience base class provided in + jaxrpc.jar, namely + javax.rpc.xml.handler.GenericHandler that we will + extend: + - What we need to do now is to register our AccountHandler to JAX-RPC Service so it would - invoke handleRequest(..) before the message is sent over the wire. - Spring has at this time of writing no declarative support for registering handlers, so we must - use the programmatic approach. However Spring has made it very easy for us to do this as we can - override the postProcessJaxRpcService(..) method that is designed for - this: + + What we need to do now is to register our AccountHandler to + JAX-RPC Service so it would invoke + handleRequest(..) before the message is sent + over the wire. Spring has at this time of writing no declarative support + for registering handlers, so we must use the programmatic approach. + However Spring has made it very easy for us to do this as we can + override the postProcessJaxRpcService(..) + method that is designed for this: + - The last thing we must remember to do is to change the Spring configuration to use our - factory bean: - + + The last thing we must remember to do is to change the Spring + configuration to use our factory bean: + + ... ]]> -
+
Exposing servlet-based web services using JAX-WS - Spring provides a convenient base class for JAX-WS servlet endpoint implementations - + + Spring provides a convenient base class for JAX-WS servlet + endpoint implementations - SpringBeanAutowiringSupport. To expose our AccountService we extend Spring's - SpringBeanAutowiringSupport class and implement our business - logic here, usually delegating the call to the business layer. - We'll simply use Spring 2.5's @Autowired - annotation for expressing such dependencies on Spring-managed beans. + SpringBeanAutowiringSupport class and implement + our business logic here, usually delegating the call to the business + layer. We'll simply use Spring 2.5's @Autowired + annotation for expressing such dependencies on Spring-managed + beans. + /** * JAX-WS compliant AccountService implementation that simply delegates * to the AccountService implementation in the root web application context. @@ -634,7 +824,8 @@ public class AccountServiceEndpoint extends ServletEndpointSupport implements Re * * The web service engine manages the lifecycle of instances of this class. * Spring bean references will just be wired in here. - */ +import org.springframework.web.context.support.SpringBeanAutowiringSupport; @WebService(serviceName="AccountService") public class AccountServiceEndpoint extends SpringBeanAutowiringSupport { @@ -651,29 +842,36 @@ public class AccountServiceEndpoint extends SpringBeanAutowiringSupport { public Account[] getAccounts(String name) { return biz.getAccounts(name); } -}]]> - Our AccountServletEndpoint needs to run in the same web - application as the Spring context to allow for access to Spring's facilities. This is - the case by default in Java EE 5 environments, using the standard contract for JAX-WS - servlet endpoint deployment. See Java EE 5 web service tutorials for details. +} + + Our AccountServletEndpoint needs to run in + the same web application as the Spring context to allow for access to + Spring's facilities. This is the case by default in Java EE 5 + environments, using the standard contract for JAX-WS servlet endpoint + deployment. See Java EE 5 web service tutorials for details.
Exporting standalone web services using JAX-WS - The built-in JAX-WS provider that comes with Sun's JDK 1.6 supports exposure - of web services using the built-in HTTP server that's included in JDK 1.6 as well. - Spring's SimpleJaxWsServiceExporter detects all - @WebService annotated beans in the Spring application context, - exporting them through the default JAX-WS server (the JDK 1.6 HTTP server). - In this scenario, the endpoint instances are defined and managed as Spring beans - themselves; they will be registered with the JAX-WS engine but their lifecycle - will be up to the Spring application context. This means that Spring functionality - like explicit dependency injection may be applied to the endpoint instances. - Of course, annotation-driven injection through @Autowired - will work as well. - + + The built-in JAX-WS provider that comes with Sun's JDK 1.6 + supports exposure of web services using the built-in HTTP server that's + included in JDK 1.6 as well. Spring's + SimpleJaxWsServiceExporter detects all + @WebService annotated beans in the Spring application + context, exporting them through the default JAX-WS server (the JDK 1.6 + HTTP server). + + In this scenario, the endpoint instances are defined and managed + as Spring beans themselves; they will be registered with the JAX-WS + engine but their lifecycle will be up to the Spring application context. + This means that Spring functionality like explicit dependency injection + may be applied to the endpoint instances. Of course, annotation-driven + injection through @Autowired will work as + well. + - + @@ -681,12 +879,14 @@ public class AccountServiceEndpoint extends SpringBeanAutowiringSupport { ...]]> + The AccountServiceEndpoint may derive from Spring's SpringBeanAutowiringSupport but doesn't - have to since the endpoint is a fully Spring-managed bean here. - This means that the endpoint implementation may look like as follows, - without any superclass declared - and Spring's @Autowired - configuration annotation still being honored: + have to since the endpoint is a fully Spring-managed bean here. This + means that the endpoint implementation may look like as follows, without + any superclass declared - and Spring's @Autowired + configuration annotation still being honored: + getAccounts(String name) { return biz.getAccounts(name); } }]]>
- Exporting web services using the JAX-WS RI's Spring support - Sun's JAX-WS RI, developed as part of the GlassFish project, ships Spring support - as part of its JAX-WS Commons project. This allows for defining JAX-WS endpoints as - Spring-managed beans, similar to the standalone mode discussed in the previous section - - but this time in a Servlet environment. Note that this is not portable - in a Java EE 5 environment; it is mainly intended for non-EE environments such as Tomcat, - embedding the JAX-WS RI as part of the web application. - The difference to the standard style of exporting servlet-based endpoints is - that the lifecycle of the endpoint instances themselves will be managed by Spring here, - and that there will be only one JAX-WS servlet defined in web.xml. - With the standard Java EE 5 style (as illustrated above), you'll have one servlet - definition per service endpoint, with each endpoint typically delegating to Spring - beans (through the use of @Autowired, as shown above). - Check out - https://jax-ws-commons.dev.java.net/spring/ + Exporting web services using the JAX-WS RI's Spring + support + + Sun's JAX-WS RI, developed as part of the GlassFish project, ships + Spring support as part of its JAX-WS Commons project. This allows for + defining JAX-WS endpoints as Spring-managed beans, similar to the + standalone mode discussed in the previous section - but this time in a + Servlet environment. Note that this is not portable in a Java + EE 5 environment; it is mainly intended for non-EE environments such as + Tomcat, embedding the JAX-WS RI as part of the web + application. + + The difference to the standard style of exporting servlet-based + endpoints is that the lifecycle of the endpoint instances themselves + will be managed by Spring here, and that there will be only one JAX-WS + servlet defined in web.xml. With the standard Java EE + 5 style (as illustrated above), you'll have one servlet definition per + service endpoint, with each endpoint typically delegating to Spring + beans (through the use of @Autowired, as shown + above). + + Check out https://jax-ws-commons.dev.java.net/spring/ for the details on setup and usage style.
Accessing web services using JAX-WS - Analogous to the JAX-RPC support, Spring provides two factory beans - to create JAX-WS web service proxies, namely LocalJaxWsServiceFactoryBean and - JaxWsPortProxyFactoryBean. The former can only return a JAX-WS - service class for us to work with. The latter is the full-fledged version that can return - a proxy that implements our business service interface. In this example we use the latter - to create a proxy for the AccountService endpoint (again): - + + Analogous to the JAX-RPC support, Spring provides two factory + beans to create JAX-WS web service proxies, namely + LocalJaxWsServiceFactoryBean and + JaxWsPortProxyFactoryBean. The former can only + return a JAX-WS service class for us to work with. The latter is the + full-fledged version that can return a proxy that implements our + business service interface. In this example we use the latter to create + a proxy for the AccountService endpoint + (again): + - - + + - + ]]> - Where serviceInterface is our business interface the clients will use. - wsdlDocumentUrl is the URL for the WSDL file. Spring needs this a startup time to create the JAX-WS Service. - namespaceUri corresponds to the targetNamespace in the .wsdl file. - serviceName corresponds to the service name in the .wsdl file. - portName corresponds to the port name in the .wsdl file. - - Accessing the web service is now very easy as we have a bean factory for it that will expose it - as AccountService interface. We can wire this up in Spring: + + Where serviceInterface is our business + interface the clients will use. wsdlDocumentUrl is + the URL for the WSDL file. Spring needs this a startup time to create + the JAX-WS Service. namespaceUri corresponds to the + targetNamespace in the .wsdl file. serviceName + corresponds to the service name in the .wsdl file. + portName corresponds to the port name in the .wsdl + file. + + Accessing the web service is now very easy as we have a bean + factory for it that will expose it as AccountService + interface. We can wire this up in Spring: + ... ]]> + From the client code we can access the web service just as if it was a normal class: + - NOTE: The above is slightly simplified in that JAX-WS - requires endpoint interfaces and implementation classes to be annotated with - @WebService, @SOAPBinding etc annotations. - This means that you cannot (easily) use plain Java interfaces and implementation - classes as JAX-WS endpoint artifacts; you need to annotate them accordingly first. + + NOTE: The above is slightly simplified in + that JAX-WS requires endpoint interfaces and implementation classes to + be annotated with @WebService, + @SOAPBinding etc annotations. This means that you + cannot (easily) use plain Java interfaces and implementation classes as + JAX-WS endpoint artifacts; you need to annotate them accordingly first. Check the JAX-WS documentation for details on those requirements.
Exposing web services using XFire - XFire is a lightweight SOAP library, hosted by Codehaus. Exposing XFire is done using a - XFire context that shipping with XFire itself in combination with a RemoteExporter-style bean - you have to add to your WebApplicationContext. As with all + + XFire is a lightweight SOAP library, hosted by Codehaus. Exposing + XFire is done using a XFire context that shipping with XFire itself in + combination with a RemoteExporter-style bean you have to add to your + WebApplicationContext. As with all methods that allow you to expose service, you have to create a DispatcherServlet with a corresponding - WebApplicationContext containing the services you will be - exposing: + WebApplicationContext containing the + services you will be exposing: + xfire org.springframework.web.servlet.DispatcherServlet ]]> - You also have to link in the XFire configuration. This is done by adding a context - file to the contextConfigLocations context parameter picked up by the - ContextLoaderListener (or ContextLoaderServlet - for that matter). + + You also have to link in the XFire configuration. This is done by + adding a context file to the contextConfigLocations + context parameter picked up by the + ContextLoaderListener (or + ContextLoaderServlet for that matter). + contextConfigLocation classpath:org/codehaus/xfire/spring/xfire.xml @@ -800,44 +1028,56 @@ public class AccountServiceEndpoint { org.springframework.web.context.ContextLoaderListener ]]> - After you added a servlet mapping (mapping /* to the XFire servlet - declared above) you only have to add one extra bean to expose the service using XFire. - Add for example the following configuration in your 'xfire-servlet.xml' + After you added a servlet mapping (mapping /* + to the XFire servlet declared above) you only have to add one extra bean + to expose the service using XFire. Add for example the following + configuration in your 'xfire-servlet.xml' file: - - - - - - - ]]><!-- the XFire bean is defined in the xfire.xml file --> - + <beans> -]]> - XFire handles the rest. It introspects your service interface and generates a WSDL from it. - Parts of this documentation have been taken from the XFire site; for more detailed information - on XFire Spring integration, navigate to - http://docs.codehaus.org/display/XFIRE/Spring. + <bean name="/Echo" class="org.codehaus.xfire.spring.remoting.XFireExporter"> + <property name="serviceInterface" value="org.codehaus.xfire.spring.Echo"/> + <property name="serviceBean"> + <bean class="org.codehaus.xfire.spring.EchoImpl"/> + </property> + <!-- the XFire bean is defined in the xfire.xml file --> + <property name="xfire" ref="xfire"/> + </bean> + +</beans> + + XFire handles the rest. It introspects your service interface and + generates a WSDL from it. Parts of this documentation have been taken + from the XFire site; for more detailed information on XFire Spring + integration, navigate to http://docs.codehaus.org/display/XFIRE/Spring.
- +
JMS - It is also possible to expose services transparently using JMS as the underlying - communication protocol. The JMS remoting support in the Spring Framework is pretty basic - - it sends and receives on the same thread and in the - same non-transactional Session, and as - such throughput will be very implementation dependent. - The following interface is used on both the server and the client side. + + It is also possible to expose services transparently using JMS as + the underlying communication protocol. The JMS remoting support in the + Spring Framework is pretty basic - it sends and receives on the + same thread and in the same + non-transactional Session, and + as such throughput will be very implementation dependent. + + The following interface is used on both the server and the client + side. + - The following simple implementation of the above interface is used on the server-side. + + The following simple implementation of the above interface is used + on the server-side. + - This configuration file contains the JMS-infrastructure beans that are shared on both - the client and server. + + This configuration file contains the JMS-infrastructure beans that + are shared on both the client and server. + Server-side configuration - On the server, you just need to expose the service object using the - JmsInvokerServiceExporter. + + On the server, you just need to expose the service object using + the JmsInvokerServiceExporter. + ]]> + Client-side configuration - The client merely needs to create a client-side proxy that will implement the agreed - upon interface (CheckingAccountService). The resulting - object created off the back of the following bean definition can be injected into other - client side objects, and the proxy will take care of forwarding the call to the - server-side object via JMS. + + The client merely needs to create a client-side proxy that will + implement the agreed upon interface + (CheckingAccountService). The resulting + object created off the back of the following bean definition can be + injected into other client side objects, and the proxy will take care of + forwarding the call to the server-side object via JMS. + ]]> +
- You may also wish to investigate the support provided by the - Lingo project, which (to quote the - homepage blurb) ... is a lightweight POJO based remoting and messaging library - based on the Spring Framework's remoting libraries which extends it to support JMS. -
+ You may also wish to investigate the support provided by the Lingo project, which (to quote + the homepage blurb) + ... is a lightweight POJO based remoting and messaging + library based on the Spring Framework's remoting libraries which + extends it to support JMS. + +
Auto-detection is not implemented for remote interfaces - The main reason why auto-detection of implemented interfaces does not occur for - remote interfaces is to avoid opening too many doors to remote callers. The target - object might implement internal callback interfaces like InitializingBean or - DisposableBean which one would not want to expose to callers. - - Offering a proxy with all interfaces implemented by the target usually does not - matter in the local case. But when exporting a remote service, you should expose - a specific service interface, with specific operations intended for remote usage. - Besides internal callback interfaces, the target might implement multiple business - interfaces, with just one of them intended for remote exposure. For these reasons, - we require such a service interface to be specified. - - This is a trade-off between configuration convenience and the risk of accidental - exposure of internal methods. Always specifying a service interface is not too much - effort, and puts you on the safe side regarding controlled exposure of specific methods. - + + The main reason why auto-detection of implemented interfaces does + not occur for remote interfaces is to avoid opening too many doors to + remote callers. The target object might implement internal callback + interfaces like InitializingBean or + DisposableBean which one would not want to + expose to callers. + + Offering a proxy with all interfaces implemented by the target + usually does not matter in the local case. But when exporting a remote + service, you should expose a specific service interface, with specific + operations intended for remote usage. Besides internal callback + interfaces, the target might implement multiple business interfaces, with + just one of them intended for remote exposure. For these reasons, we + require such a service interface to be + specified. + + This is a trade-off between configuration convenience and the risk + of accidental exposure of internal methods. Always specifying a service + interface is not too much effort, and puts you on the safe side regarding + controlled exposure of specific methods.
Considerations when choosing a technology - Each and every technology presented here has its drawbacks. You should carefully - consider you needs, the services your exposing and the objects you'll be sending - over the wire when choosing a technology. - - When using RMI, it's not possible to access the objects through the HTTP protocol, - unless you're tunneling the RMI traffic. RMI is a fairly heavy-weight protocol - in that it support full-object serialization which is important when using a - complex data model that needs serialization over the wire. However, RMI-JRMP - is tied to Java clients: It is a Java-to-Java remoting solution. - - Spring's HTTP invoker is a good choice if you need HTTP-based remoting but also - rely on Java serialization. It shares the basic infrastructure with RMI invokers, - just using HTTP as transport. Note that HTTP invokers are not only limited to - Java-to-Java remoting but also to Spring on both the client and server side. - (The latter also applies to Spring's RMI invoker for non-RMI interfaces.) - - Hessian and/or Burlap might provide significant value when operating in a - heterogeneous environment, because they explicitly allow for non-Java clients. - However, non-Java support is still limited. Known issues include the serialization - of Hibernate objects in combination with lazily-initialized collections. If you - have such a data model, consider using RMI or HTTP invokers instead of Hessian. - - JMS can be useful for providing clusters of services and allowing the JMS broker - to take care of load balancing, discovery and auto-failover. - By default: Java serialization is used when using JMS remoting but - the JMS provider could use a different mechanism for the wire formatting, - such as XStream to allow servers to be implemented in other technologies. - - Last but not least, EJB has an advantage over RMI in that it supports standard - role-based authentication and authorization and remote transaction propagation. - It is possible to get RMI invokers or HTTP invokers to support security context - propagation as well, although this is not provided by core Spring: There are - just appropriate hooks for plugging in third-party or custom solutions here. - -
-
+ Each and every technology presented here has its drawbacks. You + should carefully consider you needs, the services your exposing and the + objects you'll be sending over the wire when choosing a technology. + + When using RMI, it's not possible to access the objects through the + HTTP protocol, unless you're tunneling the RMI traffic. RMI is a fairly + heavy-weight protocol in that it support full-object serialization which + is important when using a complex data model that needs serialization over + the wire. However, RMI-JRMP is tied to Java clients: It is a Java-to-Java + remoting solution. + + Spring's HTTP invoker is a good choice if you need HTTP-based + remoting but also rely on Java serialization. It shares the basic + infrastructure with RMI invokers, just using HTTP as transport. Note that + HTTP invokers are not only limited to Java-to-Java remoting but also to + Spring on both the client and server side. (The latter also applies to + Spring's RMI invoker for non-RMI interfaces.) + + Hessian and/or Burlap might provide significant value when operating + in a heterogeneous environment, because they explicitly allow for non-Java + clients. However, non-Java support is still limited. Known issues include + the serialization of Hibernate objects in combination with + lazily-initialized collections. If you have such a data model, consider + using RMI or HTTP invokers instead of Hessian. + + JMS can be useful for providing clusters of services and allowing + the JMS broker to take care of load balancing, discovery and + auto-failover. By default: Java serialization is used when using JMS + remoting but the JMS provider could use a different mechanism for the wire + formatting, such as XStream to allow servers to be implemented in other + technologies. + + Last but not least, EJB has an advantage over RMI in that it + supports standard role-based authentication and authorization and remote + transaction propagation. It is possible to get RMI invokers or HTTP + invokers to support security context propagation as well, although this is + not provided by core Spring: There are just appropriate hooks for plugging + in third-party or custom solutions here. + + \ No newline at end of file