Spring 4 的部分我就不多說了,請自行配置 jar 檔,這裡我用
jaxws-ri-2.2.10.zip 跟
jaxws-spring-1.9.jar 進行配置。
AccountService.java
- package test.jaxws.webservice;
-
- import javax.jws.WebMethod;
- import javax.jws.WebService;
-
- @WebService
- public interface AccountService {
-
- @WebMethod
- void insertAccount(String acc);
-
- @WebMethod
- String[] getAccounts(String role);
- }
package test.jaxws.webservice;
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
public interface AccountService {
@WebMethod
void insertAccount(String acc);
@WebMethod
String[] getAccounts(String role);
}
先來定義一個 interface,這主要是給 Client 用的。
AccountServiceImpl.java
- package test.jaxws.webservice;
-
- import javax.jws.WebMethod;
- import javax.jws.WebService;
- import org.springframework.stereotype.Component;
-
- @Component
- @WebService(serviceName="AccountService")
- public class AccountServiceImpl implements AccountService {
-
- @Override
- @WebMethod
- public void insertAccount(String acc) {
- }
-
- @Override
- @WebMethod
- public String[] getAccounts(String role) {
- return new String[] {"tom", "jax"};
- }
- }
package test.jaxws.webservice;
import javax.jws.WebMethod;
import javax.jws.WebService;
import org.springframework.stereotype.Component;
@Component
@WebService(serviceName="AccountService")
public class AccountServiceImpl implements AccountService {
@Override
@WebMethod
public void insertAccount(String acc) {
}
@Override
@WebMethod
public String[] getAccounts(String role) {
return new String[] {"tom", "jax"};
}
}
接者是 Web Service 的主體,@Component 是為了讓 Spring component-scan 自動建立 Bean,@WebService 則是用定義要 Exporting 到 JAX-WS 的 serviceName,由於是透過 Spring 去管理 bean 所以可以用 @Autowired 引用其他資源。
JaxWsRtServletServiceExporter.java
- package test.jaxws.webservice;
-
- import java.util.Arrays;
- import java.util.LinkedHashSet;
- import java.util.Set;
- import javax.jws.WebService;
- import javax.xml.ws.WebServiceProvider;
-
- import org.jvnet.jax_ws_commons.spring.SpringService;
- import org.springframework.beans.factory.BeanFactory;
- import org.springframework.beans.factory.BeanFactoryAware;
- import org.springframework.beans.factory.CannotLoadBeanClassException;
- import org.springframework.beans.factory.InitializingBean;
- import org.springframework.beans.factory.ListableBeanFactory;
- import org.springframework.beans.factory.config.ConfigurableBeanFactory;
- import org.springframework.beans.factory.config.SingletonBeanRegistry;
- import com.sun.xml.ws.transport.http.servlet.SpringBinding;
-
- public class JaxWsRtServletServiceExporter implements BeanFactoryAware, InitializingBean {
-
- private ListableBeanFactory beanFactory;
- private String basePath;
-
- public void setBasePath(String basePath) {
- this.basePath = basePath;
- }
-
- @Override
- public void setBeanFactory(BeanFactory beanFactory) {
- if (!(beanFactory instanceof ListableBeanFactory)) {
- throw new IllegalStateException(getClass().getSimpleName() + " requires a ListableBeanFactory");
- }
- this.beanFactory = (ListableBeanFactory) beanFactory;
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- if (this.beanFactory instanceof SingletonBeanRegistry == false) { return; }
-
- SpringService service = new SpringService();
-
- Set<String> beanNames = new LinkedHashSet<String>(this.beanFactory.getBeanDefinitionCount());
- beanNames.addAll(Arrays.asList(this.beanFactory.getBeanDefinitionNames()));
-
- if (this.beanFactory instanceof ConfigurableBeanFactory) {
- beanNames.addAll(Arrays.asList(((ConfigurableBeanFactory) this.beanFactory).getSingletonNames()));
- }
-
- SingletonBeanRegistry factory = (SingletonBeanRegistry)this.beanFactory;
-
- for (String beanName : beanNames) {
- try {
- Class<?> type = this.beanFactory.getType(beanName);
- if (type == null || type.isInterface()) { continue; }
-
- WebService wsAnnotation = type.getAnnotation(WebService.class);
- WebServiceProvider wsProviderAnnotation = type.getAnnotation(WebServiceProvider.class);
- if (wsAnnotation == null && wsProviderAnnotation == null) { continue; }
-
-
- String serviceName;
- if (wsAnnotation != null) {
- serviceName = wsAnnotation.serviceName();
- } else {
- serviceName = wsProviderAnnotation.serviceName();
- }
-
- service.setImpl(type);
- service.setBean(this.beanFactory.getBean(beanName));
-
- SpringBinding springBinding = new SpringBinding();
- springBinding.setBeanName(serviceName + "Binding");
- springBinding.setUrl(this.basePath + "/" + serviceName);
- springBinding.setService(service.getObject());
-
- factory.registerSingleton(serviceName + "Binding", springBinding);
- }
- catch (CannotLoadBeanClassException ex) {
-
- }
- }
- }
- }
package test.jaxws.webservice;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.jws.WebService;
import javax.xml.ws.WebServiceProvider;
import org.jvnet.jax_ws_commons.spring.SpringService;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.CannotLoadBeanClassException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.SingletonBeanRegistry;
import com.sun.xml.ws.transport.http.servlet.SpringBinding;
public class JaxWsRtServletServiceExporter implements BeanFactoryAware, InitializingBean {
private ListableBeanFactory beanFactory;
private String basePath;
public void setBasePath(String basePath) {
this.basePath = basePath;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
if (!(beanFactory instanceof ListableBeanFactory)) {
throw new IllegalStateException(getClass().getSimpleName() + " requires a ListableBeanFactory");
}
this.beanFactory = (ListableBeanFactory) beanFactory;
}
@Override
public void afterPropertiesSet() throws Exception {
if (this.beanFactory instanceof SingletonBeanRegistry == false) { return; }
SpringService service = new SpringService();
Set<String> beanNames = new LinkedHashSet<String>(this.beanFactory.getBeanDefinitionCount());
beanNames.addAll(Arrays.asList(this.beanFactory.getBeanDefinitionNames()));
if (this.beanFactory instanceof ConfigurableBeanFactory) {
beanNames.addAll(Arrays.asList(((ConfigurableBeanFactory) this.beanFactory).getSingletonNames()));
}
SingletonBeanRegistry factory = (SingletonBeanRegistry)this.beanFactory;
for (String beanName : beanNames) {
try {
Class<?> type = this.beanFactory.getType(beanName);
if (type == null || type.isInterface()) { continue; }
WebService wsAnnotation = type.getAnnotation(WebService.class);
WebServiceProvider wsProviderAnnotation = type.getAnnotation(WebServiceProvider.class);
if (wsAnnotation == null && wsProviderAnnotation == null) { continue; }
String serviceName;
if (wsAnnotation != null) {
serviceName = wsAnnotation.serviceName();
} else {
serviceName = wsProviderAnnotation.serviceName();
}
service.setImpl(type);
service.setBean(this.beanFactory.getBean(beanName));
SpringBinding springBinding = new SpringBinding();
springBinding.setBeanName(serviceName + "Binding");
springBinding.setUrl(this.basePath + "/" + serviceName);
springBinding.setService(service.getObject());
factory.registerSingleton(serviceName + "Binding", springBinding);
}
catch (CannotLoadBeanClassException ex) {
// ignore beans where the class is not resolvable
}
}
}
}
為了可以自動 Exporting Service 到 JaxWs RI Servlet 需要建立一個 Exporter,這裡將具有 @WebService 或 @WebServiceProvider 的 Bean 包裝成 SpringBinding 再註冊到 Spring BeanFactory 裡,這樣 WSSpringServlet 就會取到這邊註冊 SpringBinding Bean 進行 Exporting。
web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- version="3.0"
- >
- <display-name>test-jaxws-rt</display-name>
-
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/jaxws.xml</param-value>
- </context-param>
-
- <context-param>
- <param-name>webAppRootKey</param-name>
- <param-value>test-jaxws-rt.root</param-value>
- </context-param>
-
- <servlet>
- <servlet-name>dispatcher</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>/WEB-INF/dispatcher.xml</param-value>
- </init-param>
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>dispatcher</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
-
- <servlet>
- <servlet-name>jaxws-servlet</servlet-name>
- <servlet-class>com.sun.xml.ws.transport.http.servlet.WSSpringServlet</servlet-class>
- <load-on-startup>2</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>jaxws-servlet</servlet-name>
- <url-pattern>/service/*</url-pattern>
- </servlet-mapping>
- </web-app>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
>
<display-name>test-jaxws-rt</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/jaxws.xml</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>test-jaxws-rt.root</param-value>
</context-param>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jaxws-servlet</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSSpringServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jaxws-servlet</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
</web-app>
在 web.xml 同時註冊兩個 servlet,分別是 Spring MVC 的 DispatcherServlet 跟 JAX-WS 的 WSSpringServlet,這邊主要是透過 ContextLoaderListener 去啟用全域的 ApplicationContext 去管理所有的 Bean。
jaxws.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-4.0.xsd"
- >
- <context:component-scan base-package="test.jaxws.webservice" />
-
- <bean id="jaxWsRtServletServiceExporter" class="test.jaxws.webservice.JaxWsRtServletServiceExporter">
- <property name="basePath" value="/service"/>
- </bean>
- </beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"
>
<context:component-scan base-package="test.jaxws.webservice" />
<bean id="jaxWsRtServletServiceExporter" class="test.jaxws.webservice.JaxWsRtServletServiceExporter">
<property name="basePath" value="/service"/>
</bean>
</beans>
jaxws.xml 是給 ContextLoaderListener 的設定,這裡用 component-scan 去找出 test.jaxws.webservice 下有 @Component 的 Bean,以及用 JaxWsRtServletServiceExporter 去轉換所有的 @WebService 到 SpringBinding。
dispatcher.xml
- <?xml version="1.0" encoding="utf-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-4.0.xsd"
- >
- <context:component-scan base-package="test.jaxws.controller" />
-
- <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/WEB-INF/views/" />
- <property name="suffix" value=".jsp" />
- </bean>
-
- <bean id="accountWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean" scope="request">
- <property name="serviceInterface" value="test.jaxws.webservice.AccountService"/>
- <property name="wsdlDocumentUrl" value="http://localhost:8090/test-jaxws-rt/service/AccountService?wsdl"/>
- <property name="namespaceUri" value="http://webservice.jaxws.test/"/>
- <property name="serviceName" value="AccountService"/>
- <property name="portName" value="AccountServiceImplPort"/>
- </bean>
- </beans>
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"
>
<context:component-scan base-package="test.jaxws.controller" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="accountWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean" scope="request">
<property name="serviceInterface" value="test.jaxws.webservice.AccountService"/>
<property name="wsdlDocumentUrl" value="http://localhost:8090/test-jaxws-rt/service/AccountService?wsdl"/>
<property name="namespaceUri" value="http://webservice.jaxws.test/"/>
<property name="serviceName" value="AccountService"/>
<property name="portName" value="AccountServiceImplPort"/>
</bean>
</beans>
在這裡用 JaxWsPortProxyFactoryBean 去建立 WebService Client,因為是同一個 Web Content 所以用 scope="request" 延遲建立。
HomeController.java
- package test.jaxws.controller;
-
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.context.WebApplicationContext;
- import org.springframework.web.servlet.ModelAndView;
-
- import test.jaxws.webservice.AccountService;
-
- @Controller
- public class HomeController {
-
- @Autowired
- private WebApplicationContext appContent;
-
- @RequestMapping("/")
- public ModelAndView index() {
- AccountService service = appContent.getBean("accountWebService", AccountService.class);
- String[] users = service.getAccounts("user");
-
- ModelAndView model = new ModelAndView("index");
- model.addObject("users", users);
-
- return model;
- }
- }
package test.jaxws.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.ModelAndView;
import test.jaxws.webservice.AccountService;
@Controller
public class HomeController {
@Autowired
private WebApplicationContext appContent;
@RequestMapping("/")
public ModelAndView index() {
AccountService service = appContent.getBean("accountWebService", AccountService.class);
String[] users = service.getAccounts("user");
ModelAndView model = new ModelAndView("index");
model.addObject("users", users);
return model;
}
}
接下來就是連接的 Client,這邊用 WebApplicationContext 延遲取得 AccountService,在 http://localhost:8080/test-jaxws-rt/service/AccountService 就可以看到 service 的主頁面。
參考資料:
JAX-WS + Spring integration example
22. Remoting and web services using Spring
0 回應:
張貼留言