spring整合hessian简化rpc调用

3 篇文章 0 订阅
2 篇文章 0 订阅

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;
	}
	
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值