1. 程式人生 > >spring整合hessian簡化rpc呼叫

spring整合hessian簡化rpc呼叫

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