1、Dubbo服务调用动态选择版本
问题说明
Dubbo是阿里巴巴SOA服务化治理方案的核心框架,致力于高性能和透明化的远程服务调用方案和服务治理方案。官方文档见:http://alibaba.github.io/dubbo-doc-static/Home-zh.htm。Dubbo可以和Spring无缝集成,示例如下:
1. 服务提供端
Provider.xml
2、bbo:registry address="zookeeper://132.228.12.40:2181" />
3、ype.Service;
import com.telecom.dubbo.intf.IHelloService;
@Service("helloService")
public class HelloServiceImpl implements IHelloService{
@Override
public String sayHello(String name) {
return "Hello "+name;
}
}
2. 客户端调用
Consumer.xml
4、onent-scan base-package="com.telecom.**" />
6、provider。整个发布过程需要不重启web应用实现无缝切换,客户端在xml文件中指定版本号就显得不够,dubbo需要支持客户端自行实现版本选择规则,根据规则决定调用相应版本的provider。
本文描述了如何重载dubbo的部分代码实现客户端版本规则。
实现思路
通过分析dubbo 2.5.3 的源码, 7、ceBean.getVersion() 来获取配置文件中指定的远程服务的版本号。
该类是工厂类,实现 org.springframework.beans.factory.FactoryBean,第64行代码
public Object getObject() throws Exception {
return get();
}
返回IHelloService的代理对象,调用该对象的sayHello方法即可调用远程dubbo服务,远程服务的版本号由ReferenceBean的version属性决定。
本文的实现方法是重载 ReferenceBean 的get() 8、方法,使用javassist技术构造一个新的代理,根据用户自定义的规则来调用相应版本的dubbo服务。
实现方法
重写ReferenceBean
package com.telecom.dubbo.extend;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.context.ApplicationContext;
import com.alibaba.dubbo.config.ReferenceCo 9、nfig;
import com.alibaba.dubbo.config.annotation.Reference;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
/**
* 自定义的referencebean,该类会创建动态代理,运行时根据上下文的版本号选择远程服务
* @author wuchangzheng
*
* @param 10、public class ReferenceBean 11、icationContext applicationContext;
private transient ReferenceBean self_=this;
private transient ConcurrentHashMap 12、})
public void setApplicationContext(ApplicationContext applicationContext){
super.setApplicationContext(applicationContext);
this.applicationContext=applicationContext;
}
@SuppressWarnings({ "all"})
public void afterPropertiesSet() throws Exception{
super.afterPropertiesSet();
13、 try{
versionDesider=applicationContext.getBean(IVersionDesider.class);//从上下文中查找IVersionDesider实现,该实现代表用户自定义版本规则
}catch(Exception ex){
versionDesider = null;
}
proxy=getVersionDecideProxy();//创建代理对象
}
/**
*
* @return
* @throws ClassNotFoundException
* @throws Insta 14、ntiationException
* @throws IllegalAccessException
*/
@SuppressWarnings({ "all"})
private T getVersionDecideProxy() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
Class[] interf 15、aces={Class.forName(this.getInterface())};
proxyFactory.setInterfaces(interfaces);
// 创建代理类型的Class
Class 16、 {
@Override
public T invoke(Object self, Method thisMethod,
Method proceed, Object[] args) throws Throwable {
T target = null;
String version=DEFAULT_VERSION;
if (versionDesider!=null){
version 17、versionDesider.desideVersion(self_);
}
if (version==null) version=DEFAULT_VERSION;
ReferenceConfig config =null;
synchronized(self_){
config=versionMap.get(version);
if (config==null){
config=(ReferenceConfig)self_.clone( 18、);
config.setVersion(version);
config.setCheck(false);//
versionMap.put(version, config);
}
}
target = (T)config.get();
T retObj = (T)thisMethod.invoke(target, args);
return retObj;
19、
}
});
return proxy;
}
public Object getObject() throws Exception {
return proxy;
}
}
重载dubbo命名空间解析器
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use 20、this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
21、 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.telecom.dubbo.extend;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
i 22、mport mon.Version;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ConsumerConfig;
import com.alibaba.dubbo.config.ModuleConfig;
import com.alibaba.dubbo.config.MonitorConfig;
import com.alibaba.dubbo.config.ProtocolConfig;
import com.alibaba.dubbo.config.Pro 23、viderConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.config.spring.AnnotationBean;
import com.telecom.dubbo.extend.ReferenceBean;
import com.alibaba.dubbo.config.spring.ServiceBean;
/**
* DubboNamespaceHandler
*
* @author william.liangf
* @export
*/ 24、
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerB 25、eanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, tr 26、ue));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionP 27、arser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotati 28、on", new DubboBeanDefinitionParser(AnnotationBean.class, true));
}
}
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the Li 29、cense at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See 30、the License for the specific language governing permissions and
* limitations under the License.
*/
package com.telecom.dubbo.extend;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.ut 31、il.regex.Pattern;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframew 32、ork.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionPa 33、rser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import mon.Constants;
import mon.extension.ExtensionLoader;
import mon.logger.Logger;
import mon.logger.Logg 34、erFactory;
import mon.utils.ReflectUtils;
import mon.utils.StringUtils;
import com.alibaba.dubbo.config.ArgumentConfig;
import com.alibaba.dubbo.config.ConsumerConfig;
import com.alibaba.dubbo.config.MethodConfig;
import com.alibaba.dubbo.config.MonitorConfig;
import com.alibaba.dubbo.config. 35、ProtocolConfig;
import com.alibaba.dubbo.config.ProviderConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.telecom.dubbo.extend.ReferenceBean;
import com.alibaba.dubbo.config.spring.ServiceBean;
import com.alibaba.dubbo.rpc.Protocol;
/**
* AbstractBeanDefinitionParser
*
36、
* @author william.liangf
* @export
*/
public class DubboBeanDefinitionParser implements BeanDefinitionParser {
private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);
private final Class> beanClass;
private final boolean requi 37、red;
public DubboBeanDefinitionParser(Class> beanClass, boolean required) {
this.beanClass = beanClass;
this.required = required;
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
return parse(element, parserContext, beanCla 38、ss, required);
}
@SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element, ParserContext parserContext, Class> beanClass, boolean required) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(b 39、eanClass);
beanDefinition.setLazyInit(false);
String id = element.getAttribute("id");
if ((id == null || id.length() == 0) && required) {
String generatedBeanName = element.getAttribute("name");
if (generatedBeanName == null || generatedBeanName.length( 40、) == 0) {
if (ProtocolConfig.class.equals(beanClass)) {
generatedBeanName = "dubbo";
} else {
generatedBeanName = element.getAttribute("interface");
}
}
if (generatedBeanName == null || generatedBeanNam 41、e.length() == 0) {
generatedBeanName = beanClass.getName();
}
id = generatedBeanName;
int counter = 2;
while(parserContext.getRegistry().containsBeanDefinition(id)) {
id = generatedBeanName + (counter ++);
}
42、 }
if (id != null && id.length() > 0) {
if (parserContext.getRegistry().containsBeanDefinition(id)) {
throw new IllegalStateException("Duplicate spring bean id " + id);
}
parserContext.getRegistry().registerBeanDefinition(id, beanDefini 43、tion);
beanDefinition.getPropertyValues().addPropertyValue("id", id);
}
if (ProtocolConfig.class.equals(beanClass)) {
for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
BeanDefinition definition = parserContext.getR 44、egistry().getBeanDefinition(name);
PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
if (property != null) {
Object value = property.getValue();
if (value instanceof ProtocolConfig && id.e 45、quals(((ProtocolConfig) value).getName())) {
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
}
}
}
} else if (ServiceBean.class.equals(beanClass)) {
String cla 46、ssName = element.getAttribute("class");
if(className != null && className.length() > 0) {
RootBeanDefinition classDefinition = new RootBeanDefinition();
classDefinition.setBeanClass(ReflectUtils.forName(className));
classDefinition.setL 47、azyInit(false);
parseProperties(element.getChildNodes(), classDefinition);
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
}
} else if (ProviderConfig.class.equals(beanClass)) 48、{
parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
} else if (ConsumerConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefiniti 49、on);
}
Set
©2010-2025 宁波自信网络信息技术有限公司 版权所有
客服电话:4009-655-100 投诉/维权电话:18658249818