Reference Library
%SPRING%/dist/com.springsource.org.aopalliance-1.0.0.jar%SPRING%/dist/org.springframework.aop-3.0.2.RELEASE.jar
%SPRING%/dist/org.springframework.asm-3.0.4.RELEASE.jar
%SPRING%/dist/org.springframework.beans-3.0.2.RELEASE.jar
%SPRING%/dist/org.springframework.context-3.0.4.RELEASE.jar
%SPRING%/dist/org.springframework.core-3.0.2.RELEASE.jar
%SPRING%/dist/org.springframework.expression-3.0.4.RELEASE.jar
%SPRING%/dist/org.springframework.transaction-3.0.2.RELEASE.jar
%SPRING%/dist/org.springframework.web.servlet-3.0.2.RELEASE
%SPRING%/dist/org.springframework.web-3.0.4.RELEASE.jar
%SPRING_DEP%/org.apache.commons/com.springsource.org.apache.commons.logging/1.1.1/com.springsource.org.apache.commons.logging-1.1.1.jar
%SPRING_DEP%/com.caucho/com.springsource.com.caucho/3.2.1/com.springsource.com.caucho-3.2.1.jar
%SPRING_DEP%/javax.servlet/com.springsource.javax.servlet/2.5.0/com.springsource.javax.servlet-2.5.0.jar
Wiring up the DispatcherServlet for Hessian
<?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_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>springhessian</display-name>
<servlet>
<servlet-name>hessianServices</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hessianServices</servlet-name>
<url-pattern>/remote/* </url-pattern>
</servlet-mapping>
</web-app>
Using Spring's DispatcherServlet principles, as known from Spring Web MVC usage, you can easily wire up such a servlet exposing your services.
Exposing your beans by using the HessianServiceExporter
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.spring.hessian.test" />
<bean id="acctService" class="com.spring.hessian.test.impl.AccountInfoImpl" />
<bean name="/acctService"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="acctService" />
<property name="serviceInterface" value="com.spring.hessian.test.IAccountInfo" />
</bean>
</beans>
Above configuration should be stored in WEB-INF/hessianServices-servlet.xml
Take note the configuration file name must be hessianServices-servlet.xml.
According to spring manual, the file name is remoting-servlet.xml, I tried it but it could not work.
>>> After several try, found the naming rule is <servlet name defined in web.xml>-servlet.xml.
For example, I defined a servlet named hessianServices, so the configure file will be hessianServices-servlet.xml
Source Code
// interface
package com.spring.hessian.test;
import com.spring.hessian.test.bean.AccountInfo;
public interface IAccountInfo {
public void createAccount(AccountInfo accountInfo);
public boolean changeEmail(int accountId, String newEmail);
public void deleteAccount(int accountId);
}
// implement class
package com.spring.hessian.test.impl;
import org.springframework.stereotype.Service;
import com.spring.hessian.test.IAccountInfo;
import com.spring.hessian.test.bean.AccountInfo;
@Service
public class AccountInfoImpl implements IAccountInfo {
@Override
public boolean changeEmail(int accountId, String newEmail) {
System.out.println("Here is the logic to change email.");
return false;
}
@Override
public void createAccount(AccountInfo accountInfo) {
System.out
.println("Here is the logic to create account with account info = "
+ accountInfo.toString());
}
@Override
public void deleteAccount(int accountId) {
System.out.println("Here is the logic to delete account with ID = "
+ accountId);
}
}
// domain class
package com.spring.hessian.test.bean;
import java.io.Serializable;
public class AccountInfo implements Serializable {
private static final long serialVersionUID = 5308953586718817188L;
private int accountId;
private String userName;
private String password;
private String email;
public AccountInfo() {
super();
}
public AccountInfo(int accountId, String userName, String password,
String email) {
super();
this.accountId = accountId;
this.userName = userName;
this.password = password;
this.email = email;
}
public int getAccountId() {
return accountId;
}
public void setAccountId(int accountId) {
this.accountId = accountId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String toString() {
return "AccountInfo:[id]=" + this.accountId + ",[userName]="
+ this.userName + ",[pwd]=" + this.password + ",[email]="
+ this.email;
}
}
// Junit test
package com.spring.hessian.test;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.caucho.hessian.client.HessianProxyFactory;
import com.spring.hessian.test.bean.AccountInfo;
public class HessianTester {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
}
@Test
public void test() throws Exception {
String url = "http://localhost:8080/springhessian/remote/acctService";
HessianProxyFactory factory = new HessianProxyFactory();
IAccountInfo accountInfo = (IAccountInfo) factory.create(
IAccountInfo.class, url);
AccountInfo account = new AccountInfo(125, "myName", "myPwd",
"abc@email.com");
accountInfo.createAccount(account);
accountInfo.changeEmail(126, "def@email.com");
accountInfo.deleteAccount(129);
}
}
Here is the logic to create account with account info = AccountInfo:[id]=125,[userName]=myName,[pwd]=myPwd,[email]=abc@email.com
Here is the logic to change email.
Here is the logic to delete account with ID = 129
未解决的问题
以上代码和配置在tomcat中一切正常,但是移到weblogic v10.3下,当调用第一个远程方法后总会碰到空指针异常
<Oct 29, 2010 1:42:20 PM SGT> <Error> <Kernel> <BEA-000802> <ExecuteRequest failed
java.lang.NullPointerException.
java.lang.NullPointerException
at weblogic.utils.http.HttpChunkInputStream.initChunk(HttpChunkInputStream.java:66)
at weblogic.utils.http.HttpChunkInputStream.skip(HttpChunkInputStream.java:197)
at weblogic.utils.http.HttpChunkInputStream.skipAllChunk(HttpChunkInputStream.java:371)
at weblogic.servlet.internal.ServletInputStreamImpl.ensureChunkedConsumed(ServletInputStreamImpl.java:30)
at weblogic.servlet.internal.ServletRequestImpl.skipUnreadBody(ServletRequestImpl.java:192)
Truncated. see log file for complete stacktrace
>
到现在仍没找到原因,不得已还是采用hessian的配置方式
<servlet>
<servlet-name>HessianServlet</servlet-name>
<servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
<init-param>
<param-name>home-class</param-name>
<param-value>com.spring.hessian.test.impl.AccountInfoImpl</param-value>
</init-param>
<init-param>
<param-name>home-api</param-name>
<param-value>com.spring.hessian.test.IAccountInfo</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HessianServlet</servlet-name>
<url-pattern>/remote2</url-pattern>
</servlet-mapping>
客户端改用这个URL "http://<host>:<port>/hessian/remote2" 在weblogic下可得正确结果。
如果采用hessian的配置方式,以下依赖包就不再需要了
%SPRING%/dist/org.springframework.web.servlet-3.0.2.RELEASE
%SPRING%/dist/org.springframework.web-3.0.4.RELEASE.jar
以下配置文件不再需要
WEB-INF/hessianServices-servlet.xml
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_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>springhessian</display-name>
<servlet>
<servlet-name>HessianServlet</servlet-name>
<servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>
<init-param>
<param-name>home-class</param-name>
<param-value>com.spring.hessian.test.impl.AccountInfoImpl</param-value>
</init-param>
<init-param>
<param-name>home-api</param-name>
<param-value>com.spring.hessian.test.IAccountInfo</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HessianServlet</servlet-name>
<url-pattern>/remote2</url-pattern>
</servlet-mapping>
</web-app>
WEB-INF/classes 需要spring的配置文件,内容为:
<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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.spring.hessian.test" />
</beans>
为了部属到weblogic,还需要配置文件WEB-INF/weblogic.xml, 其内容为:
<?xml version='1.0' encoding='UTF-8'?>
<weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/weblogic-web-app"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/ns/weblogic/weblogic-web-app http://www.bea.com/ns/weblogic/weblogic-web-app/1.0/weblogic-web-app.xsd">
<!-- share session in clustering env. -->
<session-descriptor>
<persistent-store-type>replicated_if_clustered</persistent-store-type>
<sharing-enabled>true</sharing-enabled>
</session-descriptor>
<!-- load customized library files first -->
<container-descriptor>
<prefer-web-inf-classes>true</prefer-web-inf-classes>
</container-descriptor>
<!-- set root context -->
<context-root>/hessian</context-root>
</weblogic-web-app>