maven配置:略
服务端
HessianServiceExporterController.java
/**
* web.xml中不需要额外的servlet.
* 对于hessian调用的理解,实际上就是http请求,然后在请求头加了特殊的Header,
* 请求体的内容使用hessian协议序列化和反序列化。
* spring提供了HessianServiceExporter,封装了协议处理的部分,
* 我们只需要注入service和serviceInterface即可。
* 所以实现将hessian调用简化的逻辑是,
* 接收/hessian/**请求,根据请求的uri获取对应的HessianServiceExporter。
* 每一个HessianServiceExporter封装一个service。
* 将service的name和uri也对应起来(使用了HessianService注解的service),
* 那么我们只需要提供service,就可以将多个service暴露为hessian服务了。
*
*/
@Controller
@RequestMapping("/hessian")
public class HessianServiceExporterController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private Map<String, HessianServiceExporter> uri2Exporter = new HashMap<>();
private Map<String, Object> beanName2Service;
@PostConstruct
public void init() throws ClassNotFoundException {
ApplicationContext appContext = AppContextHolder.getApplicationContext();
WebApplicationContext webappContext = AppContextHolder.getWebApplicationContext();
beanName2Service = appContext.getBeansWithAnnotation(HessianService.class);
beanName2Service.putAll(webappContext.getBeansWithAnnotation(HessianService.class));
logger.info("beanName2Service:"+beanName2Service.toString());
String contextPath = webappContext.getServletContext().getContextPath();
for (String beanname : beanName2Service.keySet()) {
Object service = beanName2Service.get(beanname);
Class<?> serviceInterface = findServiceInterface(service);
HessianServiceExporter exporter = new HessianServiceExporter();
exporter.setService(service);
exporter.setServiceInterface(serviceInterface);
exporter.prepare();
uri2Exporter.put(contextPath+"/hessian/"+beanname, exporter);
}
logger.info("uri2Exporter:"+uri2Exporter.toString());
}
private Class<?> findServiceInterface(Object service) throws ClassNotFoundException{
Class<?> serviceClazz = service.getClass();
String serviceClassName = serviceClazz.getName();
if (serviceClassName.contains("$")) {
serviceClazz = Class.forName(serviceClassName.substring(0, serviceClassName.indexOf("$")));
}
Class<?>[] interfaces = serviceClazz.getInterfaces();
if (interfaces == null || interfaces.length != 1) {
throw new RuntimeException("service must implements one and only one interfaces!");
}
Class<?> serviceInterface = interfaces[0];
return serviceInterface;
}
@RequestMapping("/**")
public Object replay(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException, ClassNotFoundException {
String uri = request.getRequestURI();
// 根据uri获取exporter,每个exporter包含一个服务。
HessianServiceExporter exporter = uri2Exporter.get(uri);
if(exporter==null){
throw new RuntimeException("hessian exporter not found for uri: "+uri);
}
exporter.handleRequest(request, response);
return null;
}
}
HessianService.java
@Target({ java.lang.annotation.ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HessianService {
}
AppContextHolder.java
@Component
public class AppContextHolder implements ApplicationContextAware{
private static WebApplicationContext webApplicationContext;
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContext parent = applicationContext.getParent();
if(parent==null){
AppContextHolder.applicationContext = applicationContext;
}else{
AppContextHolder.applicationContext = parent;
AppContextHolder.webApplicationContext = (WebApplicationContext) applicationContext;
}
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
public static WebApplicationContext getWebApplicationContext(){
return webApplicationContext;
}
}
对于service,需要实现一个接口,并且添加@HessianService注解,即可被当成hessian服务。
客户端
public class JobTest {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Test
public void test() throws MalformedURLException {
HessianProxyFactory factory = new HessianProxyFactory();
MyJob api = (MyJob) factory.create(MyJob.class, "http://127.0.0.1:8081/jyd-interface-mock/hessian/myJob");
JSONObject res = api.test("abc");
System.out.println(res);
logger.info("" + res);
}
}
客户端(动态注册bean到applicationContext)
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.remoting.caucho.HessianProxyFactoryBean;
import org.springframework.stereotype.Component;
/**
* 动态添加bean
*/
@Component
public class HessianClient implements BeanDefinitionRegistryPostProcessor {
//@Override
public void postProcessBeanDefinitionRegistryDemo(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
//spring会自动在webApplicationContext注册MyJob的动态代理实现。
//代理的InvocationHandler里面会获取hessianProxy,发送hessian请求。
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(HessianProxyFactoryBean.class);
builder.addPropertyValue("serviceUrl", "http://localhost:8081/jyd-interface-mock/hessian/myJob");
builder.addPropertyValue("serviceInterface", MyJob.class);
beanDefinitionRegistry.registerBeanDefinition("hessianProxyFactoryBean-myJob", builder.getRawBeanDefinition());
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
//spring会自动在webApplicationContext注册MyJob的动态代理实现。
//代理的InvocationHandler里面会获取hessianProxy,发送hessian请求。
HessianServiceBuilder hsb = new HessianServiceBuilder();
hsb.setBeanDefinitionRegistry(beanDefinitionRegistry);
hsb.setHost("localhost");
hsb.setPort(8081);
hsb.setRootPath("/jyd-interface-mock/hessian/");
//注册服务
hsb.registryHessianService("myJob",MyJob.class);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//noop
}
}
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.remoting.caucho.HessianProxyFactoryBean;
import utils.PathUtil;
public class HessianServiceBuilder {
private String host = "127.0.0.1";
private int port = 80;
private String rootPath = "/hessian";
private BeanDefinitionRegistry beanDefinitionRegistry;
public void setBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) {
this.beanDefinitionRegistry = beanDefinitionRegistry;
}
public void registryHessianService(String serviceName, Class<?> serviceInterface) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(HessianProxyFactoryBean.class);
String serviceUrl = "http://"+PathUtil.concat(host, ":",port+"",rootPath,serviceName);
builder.addPropertyValue("serviceUrl", serviceUrl);
builder.addPropertyValue("serviceInterface", serviceInterface);
beanDefinitionRegistry.registerBeanDefinition(genBeanName(serviceName), builder.getRawBeanDefinition());
}
private String genBeanName(String hessianService) {
return "hessianProxyFactory-" + hessianService;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getRootPath() {
return rootPath;
}
public void setRootPath(String rootPath) {
this.rootPath = rootPath;
}
}