dubbo 框架强大在于完美的和Spring进行了整合,由于现在大部分的java程序都建立在Spring框架上,所以一种java rpc框架能否方便java coder去开发和使用,关键点在于该rpc框架能否提供类似于Spring的配置管理。dubbo 无疑在配置项管理上无疑是十分强大的。下面来详细讲解一下dubbo的配置。
1.dubbo配置的启动时机
dubbo的配置启动 是随着Spring的配置文件的拉起而开始运转。dubbo源代码
中的
dubbo-config 下面的dubbo-config-api和dubbo-config-spring是负责整个dubbo的Spring配置管理。 在整个外部程序Spring配置文件拉起时,Spring将会读取到dubbo-config-spring工程下的spring.handlers和spring.schemas,从而感知道了dubbo Spring配置文件的schema的存在。spring.schemas文件中配置这dubbo 的xml schema 和对应的schema 文件,内容如下:http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd。 在dubbo.xsd文件中,定义了dubbo 支持的xml标签和相应的xml validation。如下大致如下:
在加载完了dubbo spring schema,Spring将会解析spring.handlers文件中http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler。 dubbo 通过DubboNameSpaceHandler来进行dubbo Spring配置的相应解析。
2.dubbo Spring 配置的解析流程
在Spring加载进spring.handlers后,会执行com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler。DubboNamespaceHandler的源代码如下:
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
}
}
通过源码我们知道,DubboNamespaceHandler继成自Spring的
NamespaceHandlerSupport。因此不需要实现所有的解析工作,只要将自定义schema中的元素解析器注册进来就可以。在DubboBeanDefinitionParser中完成我们熟悉的<dubbo:application /> <dubbo:provider /> <dubbo:consumer />中dubbo 标签的解析工作。DubboBeanDefinitionParser的核心代码如下如下:
public class DubboBeanDefinitionParser implements BeanDefinitionParser {
private static final Logger logger = LoggerFactory.getLogger(DubboBeanDefinitionParser.class);
private final Class<?> beanClass;
private final boolean required;
public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
this.beanClass = beanClass;
this.required = required;
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
return parse(element, parserContext, beanClass, required);
}
@SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
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() == 0) {
if (ProtocolConfig.class.equals(beanClass)) {
generatedBeanName = "dubbo";
} else {
generatedBeanName = element.getAttribute("interface");
}
}
if (generatedBeanName == null || generatedBeanName.length() == 0) {
generatedBeanName = beanClass.getName();
}
id = generatedBeanName;
int counter = 2;
while(parserContext.getRegistry().containsBeanDefinition(id)) {
id = generatedBeanName + (counter ++);
}
}
if (id != null && id.length() > 0) {
if (parserContext.getRegistry().containsBeanDefinition(id)) {
throw new IllegalStateException("Duplicate spring bean id " + id);
}
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
beanDefinition.getPropertyValues().addPropertyValue("id", id);
}
if (ProtocolConfig.class.equals(beanClass)) {
for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
if (property != null) {
Object value = property.getValue();
if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
}
}
}
} else if (ServiceBean.class.equals(beanClass)) {
String className = element.getAttribute("class");
if(className != null && className.length() > 0) {
RootBeanDefinition classDefinition = new RootBeanDefinition();
classDefinition.setBeanClass(ReflectUtils.forName(className));
classDefinition.setLazyInit(false);
parseProperties(element.getChildNodes(), classDefinition);
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
}
} else if (ProviderConfig.class.equals(beanClass)) {
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, beanDefinition);
}
通过源码,我们可以看到DubboBeanDefinitionParser继成Spring的BeanDefinitionParser,通过执行parse方法,从而实现把每个dubbo自定义的spring 标签实例化成我们熟悉的spring BeanDefinition。至此,就完成了dubbo 自定义的spring 标签转化成普通的Spring bean,从而可以在工程中作为Spring bean灵活的使用和@Autowired.