spring提供了多种序列化方式的基于http协议的rometing服务并且在使用的接口方式,服务端使用Exporter,客户端使用FactoryBean,例如hessian的HessianExporter和HessianProxyFactoryBean。exporter有两个参数比较关键一个是serviceInterface,另外一个是service bean本身。无论是HessianExporter还是HttpInvokerExporter都需要配置这两参数,目前spring是在配置文件中进行配置:
<bean id="helloService" class="lavasoft.suths.service.HelloService"/>
<bean name="/hello" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="helloService"/>
<property name="serviceInterface" value="lavasoft.suths.service.Hello"/>
</bean>
很显然有时候配置总是烦人,并且容易出错,有没有更简单的方式,通过注解的方式来暴露服务。如用注解又该来如何做呢?我们知道spring先生成beandefinition,再初始化bean。这样我们先扫描带有注解的service并根据该service构造exporter的bean definition并且注册。还是看看代码吧
for (String basePackage : basePackages) { Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this.scopeMetadataResolver .resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String originalBeanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); // if (candidate instanceof AbstractBeanDefinition) { // postProcessBeanDefinition((AbstractBeanDefinition) // candidate, originalBeanName); // } ScannedGenericBeanDefinition bd = (ScannedGenericBeanDefinition) candidate; String beanClassName = bd.getBeanClassName(); bd.setBeanClassName(JsonRpcExporter.class.getName()); bd.setBeanClass(JsonRpcExporter.class);//如果你用的hessian或者httpinvoker请换成相应的exporter bd.getPropertyValues().add("service", applicationContext.getBean(originalBeanName)); bd.getPropertyValues().add("beanClassName", beanClassName); String[] interfaces = bd.getMetadata().getInterfaceNames(); if (interfaces == null || interfaces.length == 0) continue; // HessianServiceExporter.class.getClassLoader().getResource(name) Class interf = null;
@Override protected void registerDefaultFilters() { addIncludeFilter(new AnnotationTypeFilter(JsonRpc.class));//只扫描带有JsonRpc的注解 }
@Component("helloService")
@JsonRpc("helloService") public class HelloServiceImpl implements IHelloService {
<bean id="scanner" class="com.taofang.scanner.HessianServiceScanner">
更新
非常感谢yangpeihai 兄的关注。起因是这样,我看到yang兄在一个帖子上说道能不能用注解暴露服务,正好这阶段我这也在做这方面的事情包括json-rpc,一看到这个帖子我就急匆匆的发了这篇blog,代码这也是从jsonrpc中摘出来的。也存在一些bug,要不是yang兄说他那边调试有问题,我现在还不知道。我发的这个版本,我把exporter的beanName和它引用的service的beanname搞混了,恰巧的是我把两个名字设成一样的,这个bug才隐藏在这里。按yang兄的要求我整了一份hessian的完整。测试类在test包中的ResourceTest。
bd.getPropertyValues().add("service", applicationContext.getBean(originalBeanName));//这里应该是exporter的service的beanname,
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, "/" + beanName );//这里才是exporter的beanname,也是请求的url中的name
<property name="basePackage" value="com.taofang.service"></property> </bean