industry0 2014-12-08
评:
上次把webservice客户端接口,用注解注入到别的bean里,结果报错了。当时一直没有找到原因,现在回想,有可能是当时代码环境的问题,spring和cxf的配置都有些混乱
最近在搭建一个培训的框架,开发环境很纯净,上次那个问题没有再发生了。因此也简化了一下,重新总结一下。不过由于上次那个问题,最终也没找到原因,所以不敢保证这次也一定是正确的,只能说,在以下环境是OK的:
tomcat7.0.29
spring-framework-3.1.0
cxf-2.6.1
neethi-3.0.2
wsdl4j-1.6.2
xmlschema-core-2.0.2
首先是web.xml
Xml代码收藏代码
<?xmlversion="1.0"encoding="UTF-8"?>
<web-appxmlns: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/javaeehttp://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID"version="3.0">
<display-name>DevelopFramework</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
</web-app>
这里因为没有集成spring-mvc,所以web.xml就很简单
然后是spring的配置文件
Xml代码收藏代码
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<importresource="classpath:META-INF/cxf/cxf.xml"/>
<context:component-scanbase-package="com.huawei.inoc.framework"/>
<jaxws:endpointid="helloWorld"implementor="#helloWorldWebserviceImpl"address="/HelloWorld"/>
<jaxws:clientid="client"
serviceclass="com.huawei.inoc.dummy.webservice.IDemoSupport"
address="http://localhost:8080/Dummy/webservice/getDate"/>
</beans>
这里是简化后的配置,仅包含必要的配置信息
这里分别配置了一个webservice的客户端,和一个webservice的服务端
这里要注意的是,jaxws:endpoint里的implementor,不能直接写xxx.xxx.ClassName,因为这里的实现类,自身也是一个bean,如果直接写的话,里面的依赖关系就没有了,要用#beanName的语法
jaxws:client里的serviceClass,写的是接口的完整类名,address是目标endpoint的地址
接下来是要发布的webservice接口代码
Java代码收藏代码
@WebService
publicinterfaceHelloWorldWebservice{
StringsayHello(Stringname);
}
就是一个普通的接口声明,只是要加上@WebService注解
最后是webservice实现类代码
Java代码收藏代码
@Controller
publicclassHelloWorldWebserviceImplimplementsHelloWorldWebservice{
@Autowired
privateITestServiceservice;
@Autowired
privateIDemoSupportsupport;
@Override
publicStringsayHello(Stringname){
service.doSomething();
System.out.println(support.getDate());
return"hello"+name;
}
}
实现类更加简单,只需要继承刚才声明的接口就可以了,不需要额外的注解
这里用到了@Controller和@Autowired注解,只是为了演示把实现类自身声明为springbean,并把下层的业务bean,和webserviceclient的bean注入进来
启动tomcat后,webservice就发布成功了,并且ITestService和IDemoSupport都是注入成功的
[点击查看原始大小图片]
用soapui调用一下,控制台打出如下信息:
doSomething()
WedAug1517:12:50CST2012
说明此时业务bean和clientbean都是注入成功的。上次死活就不行,估计确实是代码环境的原因,现在也没法还原现场了,成为悬案
另外写了一个Servlet,看看当前的ApplicationContext里究竟注册了哪些bean
Java代码收藏代码
protectedvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)throwsServletException,IOException{
ApplicationContextcontext=WebApplicationContextUtils
.getWebApplicationContext(request.getServletContext());
String[]beanNames=context.getBeanDefinitionNames();
for(StringbeanName:beanNames){
System.out.println(beanName);
}
}
执行之后,控制台打出bean信息:
cxf
org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor
org.apache.cxf.bus.spring.Jsr250BeanPostProcessor
org.apache.cxf.bus.spring.BusExtensionPostProcessor
testService
helloWorldWebserviceImpl
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.internalPersistenceAnnotationProcessor
propertyConfigurer
dataSource
sessionFactory
helloWorld
client.proxyFactory
client
org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor#0
前4个都是cxf.xml里注册的
testService是业务bean
helloWorldWebserviceImpl是webservice实现类的bean,注意这个只是一个普通的springbean,还没有被发布为webservice,下面的helloWorld才是
helloWorld,就是<jaxws:endpoint>那行生成的bean,实际的webservice
client,是<jaxws:client>那行生成的bean。这个类是cxf生成的代理类,但是实现了webservice服务端接口。代码不可见,但是可以像普通的springbean一样注入到别的bean里
Java代码收藏代码
ObjectclientProxyFactory=context.getBean("client");
System.out
.println("client:"+clientProxyFactory.getClass().getName());
System.out.println(clientProxyFactoryinstanceofIDemoSupport);
执行以后,输出是:
client:$Proxy42
true
如果跟进去调试,可以看得更清楚一点:
client.proxyFactory应该是cxf生成的一个内部bean,beandefinition是abstract的,如果尝试用getBean()方法获取,会抛出异常
Java代码收藏代码
ObjectclientProxyFactory=context.getBean("client.proxyFactory");
org.springframework.beans.factory.BeanIsAbstractException:Errorcreatingbeanwithname'client.proxyFactory':Beandefinitionisabstract
的错误。geronimo-servlet_2.5_spec-1.2.jar (or Sun's Servlet jar). <?xml version="1.0" encoding="UTF-8"?>