Hessian 是 Caucho 开源的一个 RPC 框架,其通讯效率高于 WebService 和 Java 自带的序列化。
Hessian 协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。
Dubbo 的 Hessian 协议可以和原生 Hessian 服务互操作,即:
Hessian分服务端和客户端,都要导入依赖
<!-- 集成hessian-->
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
接口服务类HelloHessianService.java
public interface HelloHessianService {
String hello(String name);
}
接口服务实现类HelloHessianServiceImpl.java
@Service
public class HelloHessianServiceImpl implements HelloHessianService {
@Override
public String hello(String name) {
return "Hello Hessian " + name;
}
}
发布服务的方法有很多,这里只介绍主流的三种
此方法存在弊端:当服务量很多时,需要写大量这样的代码块
@Configuration
public class HessianConfig {
@Autowired
private HelloHessianService helloHessianService;
//发布服务
@Bean(name = "/helloHessianService")
public HessianServiceExporter hessianServer() {
HessianServiceExporter exporter = new HessianServiceExporter();
exporter.setService(helloHessianService);
exporter.setServiceInterface(HelloHessianService.class);
return exporter;
}
}
此方法还没来得及测试,不过应该是可行的
首先,编写hessian-server.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="helloHessianService" class="com.hessian.service.impl.HelloHessianServiceImpl" />
<bean name="/helloHessianService" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="helloHessianService" />
<property name="serviceInterface" value="com.hessian.service.HelloHessianService " />
</bean>
</beans>
Spring-boot启动类加载配置文件
/**
* 启动程序
*
* @author xxx
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@ImportResource(locations = {"classpath:hessian-service.xml"})
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
}
先声明HessianService.java注解类(此注解类包含了Spring的@Service注解)
import org.springframework.stereotype.Service;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface HessianService {
String value() default "";
}
把原先用@Service注解的接口服务实现类的@Service注解换成我们重新定义的@HessianService注解
@HessianService
public class HelloHessianServiceImpl implements HelloHessianService {
...
...
}
使用spring的BeanFactoryPostProcessor机制,添加扫描类HessianServiceScanner.java,扫描@HessianService注解并暴露hessian服务
import cn.datahh.common.annotation.HessianService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.remoting.caucho.HessianServiceExporter;
import org.springframework.stereotype.Component;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Hessian服务扫描器
*
* @author xxx
* @create 2022-08-30 17:53
*/
@Slf4j
@Component
public class HessianServiceScanner implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Set<String> beanDefinitions = new LinkedHashSet<>();
String[] beanNames = beanFactory.getBeanNamesForAnnotation(HessianService.class);
for (String beanName : beanNames) {
String className = beanFactory.getBeanDefinition(beanName).getBeanClassName();
Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new BeanInitializationException(e.getMessage(), e);
}
String hessianServiceBeanName = "/" + beanName.replace("Impl", "");
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(HessianServiceExporter.class);
builder.addPropertyReference("service", beanName);
builder.addPropertyValue("serviceInterface", clazz.getInterfaces()[0].getName());
((BeanDefinitionRegistry) beanFactory).registerBeanDefinition(hessianServiceBeanName, builder.getBeanDefinition());
beanDefinitions.add(hessianServiceBeanName);
}
log.info("--------------加载Hessian服务---------------------->");
if (beanDefinitions.isEmpty()) {
System.out.println(this.getClass().getName()+": not service be scanned");
} else {
for (String beanName : beanDefinitions) {
System.out.println(this.getClass().getName() + ": " + beanName);
}
}
log.info("==============初始化Hessian服务:" + (beanDefinitions.isEmpty() ? 0 : beanDefinitions.size()) + " 个==============>");
}
}
至此,服务端发布服务完成。
客户端注入bean就可以使用,可以更加灵活的封装,这里只是作简单的使用
方法也有很多,介绍三种
Spring-boot启动类添加bean,业务代码直接使用注入的bean即可
/**
* 启动程序
*
* @author xxx
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
@Bean
public HessianProxyFactoryBean hessianClient() {
HessianProxyFactoryBean hessianProxyFactoryBean = new HessianProxyFactoryBean();
hessianProxyFactoryBean.setServiceUrl("http://localhost:8080/helloHessianService");
hessianProxyFactoryBean.setServiceInterface(HelloHessianService.class);
return hessianProxyFactoryBean;
}
}
配置好Bean后,编写TestController.java,自动装载刚刚配置的Bean,直接引入使用
@RestController
public class TestController {
@Autowired
private HelloHessianService helloHessianService;
@RequestMapping("/test")
public String test() {
return helloHessianService.hello("小明");
}
}
直接用代理请求服务,跟方法一大同小异,写一个测试类TestHessian.java
/**
* description
*
* @author xxx
* @create 2022-09-02 13:45
*/
public class TestHessian {
/**
* 获取服务端对象
* @param clazz 实体对象泛型
* @param url 服务端url地址
* @param <T>
* @return 服务对象
*/
public static <T> T getHessianService(Class<T> clazz,String url) throws Exception {
// 代理工厂
HessianProxyFactory factory = new HessianProxyFactory();
return (T)factory.create(clazz,url);
}
@Test
//创建测试类方法
public void test() throws Exception {
String url = "http://localhost:8080/helloHessianService";
HelloHessianService helloHessianService = getHessianService(HelloHessianService.class, url);
String result = helloHessianService.hello("小明");
System.out.println(result);
}
首先,编写hessian-client.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="helloHessianService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceInterface" value="com.hessian.service.HelloHessianService" />
<property name="serviceUrl" value="http://localhost:8080/helloHessianService" />
<property name="overloadEnabled" value="true" />
</bean>
</beans>
Spring-boot启动类加载配置文件
/**
* 启动程序
*
* @author xxx
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@ImportResource(locations = {"classpath:hessian-client.xml"})
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
}
使用与方法一同样,TestController.java,自动装载刚刚配置的Bean,直接引入使用
@RestController
public class TestController {
@Autowired
private HelloHessianService helloHessianService;
@RequestMapping("/test")
public String test() {
return helloHessianService.hello("小明");
}
}
结束。