1.1. Axis2 使用POJO开发Web服务
如果考虑快速开发一个Web服务,可以创建POJO(普通现有的java对象)然后使用axis2部署到tomcat上,这种方式容易快速开发、便于整合并且易于维护。下面我们会学习到如何从Spring框架中获得一个现有的POJO,然后将其作为ARR包部署到tomcat上来发布Web服务。下面我们以pojoguidespring为示例说明。
1.1.1. 一个简单的POJO开发Web服务
1. 打开Eclipse,新建一个工程名为pojospring。
2. 将axis2.war中的axis2-web和WEB-INF文件夹复制到工程WebContent目录下。
3. 在工程下创建如下目录结构:
4. 在src下编写POJO Java类:
Weather POJO:
package sample.pojo.data;
public class Weather{ float temperature; String forecast; boolean rain; float howMuchRain;
public void setTemperature(float temp){ temperature = temp; } public float getTemperature(){ return temperature; } public void setForecast(String fore){ forecast = fore; } public String getForecast(){ return forecast; }
public void setRain(boolean r){ rain = r; }
public boolean getRain(){ return rain; } public void setHowMuchRain(float howMuch){ howMuchRain = howMuch; } public float getHowMuchRain(){ return howMuchRain; } } |
WeatherServicePOJO:
package sample.pojo.service;
import sample.pojo.data.Weather;
public class WeatherService{ Weather weather; public void setWeather(Weather weather){ this.weather = weather; } public Weather getWeather(){ return this.weather; } } |
5. 定义services.xml向Axis2描述该服务
<service name="WeatherService" scope="application"> <description> Weather POJO Service </description> <messageReceivers> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/> <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> </messageReceivers> <parameter name="ServiceClass"> sample.pojo.service.WeatherService </parameter> </service> |
服务名是WeatherService,服务作用域是application,在POJO WeatherService中有两个方法IN-ONLY和IN-OUT方法,消息接收器类型是RPC。
6. 打开Ant文件WeatherService.build.xml,进行创建POJO服务任务:
<project name="pojoguide" basedir=".." default="generate.service">
<property name="service.name" value="WeatherService" /> <property name="dest.dir" value="WebContent/WEB-INF/services" /> <property name="dest.dir.classes" value="${dest.dir}/${service.name}" /> <property name="axis2.home" value="WebContent/WEB-INF" /> <path id="build.class.path"> <fileset dir="${axis2.home}/lib"> <includename="*.jar"/> </fileset> </path> <!-- <target name="clean"> <delete dir="${dest.dir}" /> <delete dir="src" includes="sample/pojo/stub/**"/> </target> --> <target name="prepare"> <mkdir dir="${dest.dir}" /> <mkdir dir="${dest.dir.classes}" /> <mkdir dir="${dest.dir.classes}/META-INF" /> </target>
<target name="generate.service" depends="prepare"> <copy file="src/META-INF/${service.name}/services.xml"tofile="${dest.dir.classes}/META-INF/services.xml"overwrite="true"/> <javac srcdir="src" destdir="${dest.dir.classes}"includes="sample/pojo/service/**,sample/pojo/data/**"> <classpathrefid="build.class.path"/> </javac> <jar basedir="${dest.dir.classes}" destfile="${dest.dir}/${service.name}.aar"/> <!-- <copy file="${dest.dir}/${service.name}.aar" tofile="${repository.path}/services/${service.name}.aar" overwrite="true" /> --> </target> </project> |
7. 运行ant文件,在工程目录WebContent/WEB-INF/services下会生成WeatherService目录:
注意:发布服务时WeatherService.aar和WeatherService仅可有一个。
8. 将pojospring工程部署到Eclipse Tomcat下并启动,访问如下链接查看已发布的服务描述文件WSDL:
http://localhost:8080/pojospring/services/WeatherService?wsdl
9. 客户端使用RPCServiceClient测试发布的Web服务。编写WeatherRPCClient客户端测试类,由于该客户端没有callback,所以采用阻塞模式:(注意该客户端仅用于测试,如果与服务端分离开发的话可以使用客户端开发技术来开发,比如,动态调用接口-DII)
package sample.pojo.rpcclient;
import javax.xml.namespace.QName;
import org.apache.axis2.AxisFault; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.rpc.client.RPCServiceClient;
import sample.pojo.data.Weather;
public class WeatherRPCClient {
public static void main(String[] args1) throws AxisFault { RPCServiceClient serviceClient = new RPCServiceClient(); Options options = serviceClient.getOptions(); EndpointReference targetEPR = new EndpointReference( "http://localhost:8080/pojospring/services/WeatherService"); options.setTo(targetEPR); // Setting the weather QName opSetWeather = new QName("http://service.pojo.sample", "setWeather"); Weather w = new Weather(); w.setTemperature((float) 39.3); w.setForecast("Cloudy with showers"); w.setRain(true); w.setHowMuchRain((float) 4.5); Object[] opSetWeatherArgs = new Object[] { w }; serviceClient.invokeRobust(opSetWeather, opSetWeatherArgs); // Getting the weather QName opGetWeather = new QName("http://service.pojo.sample", "getWeather"); Object[] opGetWeatherArgs = new Object[] {}; Class[] returnTypes = new Class[] { Weather.class }; Object[] response = serviceClient.invokeBlocking(opGetWeather, opGetWeatherArgs, returnTypes); Weather result = (Weather) response[0]; if (result == null) { System.out.println("Weather didn't initialize!"); return; } // Displaying the result System.out.println("Temperature : " + result.getTemperature()); System.out.println("Forecast : " + result.getForecast()); System.out.println("Rain : " + result.getRain()); System.out.println("How much rain (in inches) : " + result.getHowMuchRain()); } } |
10. 运行以上代码,控制台输出:
log4j:WARN No appenders could be found for logger (org.apache.axis2.context.AbstractContext). log4j:WARN Please initialize the log4j system properly. Temperature : 39.3 Forecast : Cloudy with showers Rain : true How much rain (in inches) : 4.5 |
11. 下面使用Spring整合POJO。
1.1.2. 使用Spring POJO开发Web服务
1. 以上我们看到创建一个POJO服务很简单,但是这种方式有一定的限制,比如无法对Service进行初始化,这时我们需要在Service可用前手动初始化值。下面我们使用Spring避免这种缺陷。
2. 在工程lib下导入spring.jar等jar包。
3. 编写SpringInit.java,该类用于初始化Spring application Context
package sample.pojo.service;
import org.apache.axiom.om.OMElement; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.OperationContext; import org.apache.axis2.context.ServiceContext; import org.apache.axis2.description.AxisService; import org.apache.axis2.engine.ServiceLifeCycle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringInit implements ServiceLifeCycle { private static Log logger = LogFactory.getLog(SpringInit.class); // The web service public OMElement springInit(OMElement ignore) { returnnull; } public void init(ServiceContext serviceContext) { } public void setOperationContext(OperationContext arg0) { } public void destroy(ServiceContext arg0) { } /** * this will be called during thedeployement time of the service. * irrespective of the service scope this method will be called */ public void startUp(ConfigurationContext ignore, AxisService service) { ClassLoader classLoader = service.getClassLoader(); ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml" },false); appCtx.setClassLoader(classLoader); appCtx.refresh(); if (logger.isDebugEnabled()) { logger.debug("\n\nstartUp() set spring classloader via axisService.getClassLoader() ... "); } } /** * this will be called during thedeployement time of the service. * irrespective of the service scope this method will be called */ public void shutDown(ConfigurationContext ignore, AxisService service) { } }
|
4. 定义services.xml
<serviceGroup> <servicename="SpringInit"class="sample.pojo.service.SpringInit"> <description> This web service initializes Spring. </description> <parametername="ServiceClass">sample.pojo.service.SpringInit</parameter> <parametername="ServiceTCCL">composite</parameter> <parametername="load-on-startup">true</parameter> <operationname="springInit"> <messageReceiverclass="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> </operation> </service> <servicename="WeatherSpringService"> <description> Weather Spring POJO Axis2 AAR deployment </description> <parametername="ServiceClass">sample.pojo.service.WeatherService</parameter> <parametername="ServiceObjectSupplier"> org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier </parameter> <parametername="SpringBeanName">weatherSpringService</parameter> <messageReceivers> <messageReceivermep="http://www.w3.org/2004/08/wsdl/in-only" class="org.apache.axis2.rpc.receivers.RPCInOnlyMessageReceiver"/> <messageReceivermep="http://www.w3.org/2004/08/wsdl/in-out" class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/> </messageReceivers> </service> </serviceGroup> |
Server.xml文件定义了两个service描述,ServiceTCCL属性确保Spring的类加载器能应用到该Service,load-on-startup属性(必须)保证Spring application context启动创建时加载该Service,ServiceObjectSupplier通知Axis该Service由Spring容器负责创建、和初始化。
5. 在src下创建applicationContext.xml文件并添加如下配置:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEbeansPUBLIC"-//SPRING//DTD BEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">
<beans> <beanid="applicationContext" class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder"/> <beanid="weatherSpringService"class="sample.pojo.service.WeatherService"> <propertyname="weather"ref="weatherBean"/> </bean> <beanid="weatherBean"class="sample.pojo.data.Weather"> <propertyname="temperature"value="89.9"/> <propertyname="forecast"value="Sunny"/> <propertyname="rain"value="false"/> <propertyname="howMuchRain"value="0.2"/> </bean> </beans> |
6. SpringInit.java的startUp方法:
public void startUp(ConfigurationContext ignore, AxisService service) { ClassLoader classLoader = service.getClassLoader(); ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext( new String[] {"applicationContext.xml" },false); appCtx.setClassLoader(classLoader); appCtx.refresh(); if (logger.isDebugEnabled()) { logger.debug("\n\nstartUp() set spring classloader via axisService.getClassLoader() ... "); } } |
当Service发布时会先执行该方法。该方法首先获得service和Spring的类加载器,然后使用applicationContext.xml创建applicationContext,将Spring的类加载器设置为service的加载器,刷新applicationContext,现在我们的Spring开始为service服务了。
7. 打开Ant文件SpringWeatherService.build.xml,进行创建POJO服务任务:
<project name="pojoguide" basedir=".." default="generate.service">
<property name="service.name" value="SpringWeatherService" /> <property name="dest.dir" value="WebContent/WEB-INF/services" /> <property name="dest.dir.classes" value="${dest.dir}/${service.name}" /> <property name="axis2.home" value="WebContent/WEB-INF" />
<path id="build.class.path"> <fileset dir="${axis2.home}/lib"> <includename="*.jar"/> </fileset> </path> <target name="prepare"> <mkdir dir="${dest.dir}" /> <mkdir dir="${dest.dir.classes}" /> <mkdir dir="${dest.dir.classes}/META-INF" /> </target> <target name="generate.service" depends="prepare"> <copy file="src/META-INF/${service.name}/services.xml"tofile="${dest.dir.classes}/META-INF/services.xml"overwrite="true"/> <copy file="src/applicationContext.xml" tofile="${dest.dir.classes}/applicationContext.xml"overwrite="true"/> <javac srcdir="src" destdir="${dest.dir.classes}"includes="sample/pojo/service/**,sample/pojo/data/**"> <classpathrefid="build.class.path"/> </javac> <jar basedir="${dest.dir.classes}" destfile="${dest.dir}/${service.name}.aar"/> <!-- <copy file="${dest.dir}/${service.name}.aar" tofile="${repository.path}/services/${service.name}.aar" overwrite="true" /> --> </target> </project> |
8. 编写WeatherSpringRPCClient客户端测试类:
package sample.pojo.rpcclient; import javax.xml.namespace.QName; import org.apache.axis2.AxisFault; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.rpc.client.RPCServiceClient; import sample.pojo.data.Weather;
public class WeatherSpringRPCClient { public static void main(String[] args1) throws AxisFault { RPCServiceClient serviceClient = new RPCServiceClient(); Options options = serviceClient.getOptions(); EndpointReference targetEPR = new EndpointReference( "http://localhost:8080/pojospring/services/WeatherSpringService"); options.setTo(targetEPR); // Get the weather (no setting, the Spring Framework has already // initialized it for us) QName opGetWeather = new QName("http://service.pojo.sample", "getWeather"); Object[] opGetWeatherArgs = new Object[] {}; Class[] returnTypes = new Class[] { Weather.class }; Object[] response = serviceClient.invokeBlocking(opGetWeather, opGetWeatherArgs, returnTypes); Weather result = (Weather) response[0]; // display results if (result == null) { System.out.println("Weather didn't initialize!"); } else { System.out.println("Temperature : " + result.getTemperature()); System.out.println("Forecast : " + result.getForecast()); System.out.println("Rain : " + result.getRain()); System.out.println("How much rain (in inches) : " + result.getHowMuchRain()); } } } |
9. 运行以上代码,控制台输出:
log4j:WARN No appenders could be found for logger (org.apache.axis2.context.AbstractContext). log4j:WARN Please initialize the log4j system properly. Temperature : 89.9 Forecast : Sunny Rain : false How much rain (in inches) : 0.2 |
可见,Weather对象的初始化已经由Spring框架在启动时为我们做完了。
资源
以上代码在工程pojospring.rar