Label parsing
Dubbo jar package dependencies inside, you can see two files:
spring.schemas
http\://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd
Copy the code
spring.handlers
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler <! Class to parse tags -->
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
Copy the code
DubboNamespaceHandler.java
@Override
public void init(a) {
The same is true for tag parsing below
registerBeanDefinitionParser("application".new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module".new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry".new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("config-center".new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
registerBeanDefinitionParser("metadata-report".new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
registerBeanDefinitionParser("monitor".new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("metrics".new DubboBeanDefinitionParser(MetricsConfig.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 AnnotationBeanDefinitionParser());
}
Copy the code
DubboBeanDefinitionParser.java
/** * Dubbo tag parser constructor *@paramThe type encapsulated by the beanClass tag attribute readout value *@paramRequired specifies whether the ID attribute is required */ in the current tag
public DubboBeanDefinitionParser(Class<? > beanClass,boolean required) {
this.beanClass = beanClass;
this.required = required;
}
/** * parses the specified tag *@paramElement The label element * to parse@paramParserContext Parsing context, which contains parsing information * for all other tags in the current configuration file@paramBeanClass Is a physical encapsulation of the type encapsulated by the tag attribute readout value@paramRequired specifies whether the ID attribute is a required * in the current tag@returnParse the object. That is, the Bean definition instance */ of the "logical instance" ultimately resolved by the current tag
@SuppressWarnings("unchecked")
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<? > beanClass,boolean required) {
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = 1 create and initialize the analysis object = = = = = = = = = = = = = = = =
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);// Whether to enable lazy loading
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = 2 id problem: the problem of empty and repeat = = = = = = = = = = = = = = = =
// Get the id attribute in the current tag
String id = element.getAttribute("id");
if (StringUtils.isEmpty(id) && required) {
// Get the name attribute of the current tag
String generatedBeanName = element.getAttribute("name");
if (StringUtils.isEmpty(generatedBeanName)) {
// If the current parse label is
, the name attribute value is set to dubbo
// Otherwise, take the interface property value
if (ProtocolConfig.class.equals(beanClass)) {
generatedBeanName = "dubbo";
} else {
generatedBeanName = element.getAttribute("interface"); }}// If the name attribute is still empty, the value of the name attribute is the name of the beanClass
if (StringUtils.isEmpty(generatedBeanName)) {
generatedBeanName = beanClass.getName();
}
// The name attribute must not be empty, i.e. the id attribute must not be empty
id = generatedBeanName;
int counter = 2;
// Iterate through the parse object context to determine if the generated ID is duplicated.
// If it is repeated, add a number after the name until it is not repeated
while(parserContext.getRegistry().containsBeanDefinition(id)) { id = generatedBeanName + (counter++); }}// end-if
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = 3 attribute written to parse the id = = = = = = = = = = = = = = = =
if(id ! =null && id.length() > 0) {
// If the id attribute specified by the user in the tag is repeated in the parse context, an exception is thrown
if (parserContext.getRegistry().containsBeanDefinition(id)) {
throw new IllegalStateException("Duplicate spring bean id " + id);
}
// Write the id-parsing object to the parsing context
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
// Write the id attribute to the parse object
beanDefinition.getPropertyValues().addPropertyValue("id", id);
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = 4 special processing for the specific tag = = = = = = = = = = = = = = = =
// Handle the
tag
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".newRuntimeBeanReference(id)); }}}// Process the
tag
} 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"));
}
// Handle the
tag
} else if (ProviderConfig.class.equals(beanClass)) {
// Parse
with
tags
parseNested(element, parserContext, ServiceBean.class, true."service"."provider", id, beanDefinition);
// Process the
tag
} else if (ConsumerConfig.class.equals(beanClass)) {
// Parse
with
tags
parseNested(element, parserContext, ReferenceBean.class, false."reference"."consumer", id, beanDefinition);
}
/ / = = = = = = = = = = = = = = = = = = = = = = = = = = 5 for the universality of all tags handle = = = = = = = = = = = = = = = =
Set<String> props = new HashSet<>();
ManagedMap parameters = null;
for (Method setter : beanClass.getMethods()) {
String name = setter.getName();
if (name.length() > 3 && name.startsWith("set")
&& Modifier.isPublic(setter.getModifiers())
&& setter.getParameterTypes().length == 1) { Class<? > type = setter.getParameterTypes()[0];
String beanProperty = name.substring(3.4).toLowerCase() + name.substring(4);
String property = StringUtils.camelToSplitName(beanProperty, "-");
props.add(property);
// check the setter/getter whether match
Method getter = null;
try {
getter = beanClass.getMethod("get" + name.substring(3), newClass<? > [0]);
} catch (NoSuchMethodException e) {
try {
getter = beanClass.getMethod("is" + name.substring(3), newClass<? > [0]);
} catch (NoSuchMethodException e2) {
// ignore, there is no need any log here since some class implement the interface: EnvironmentAware,
// ApplicationAware, etc. They only have setter method, otherwise will cause the error log during application start up.}}if (getter == null| |! Modifier.isPublic(getter.getModifiers()) || ! type.equals(getter.getReturnType())) {continue;
}
if ("parameters".equals(property)) {
parameters = parseParameters(element.getChildNodes(), beanDefinition);
} else if ("methods".equals(property)) {
parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);
} else if ("arguments".equals(property)) {
parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);
} else {
String value = element.getAttribute(property);
if(value ! =null) {
value = value.trim();
if (value.length() > 0) {
if ("registry".equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);
beanDefinition.getPropertyValues().addPropertyValue(beanProperty, registryConfig);
} else if ("provider".equals(property) || "registry".equals(property) || ("protocol".equals(property) && ServiceBean.class.equals(beanClass))) {
/**
* For 'provider' 'protocol' 'registry', keep literal value (should be id/name) and set the value to 'registryIds' 'providerIds' protocolIds'
* The following process should make sure each id refers to the corresponding instance, here's how to find the instance for different use cases:
* 1. Spring, check existing bean by id, see{@link ServiceBean#afterPropertiesSet()}; then try to use id to find configs defined in remote Config Center
* 2. API, directly use id to find configs defined in remote Config Center; if all config instances are defined locally, please use {@link org.apache.dubbo.config.ServiceConfig#setRegistries(List)}
*/
beanDefinition.getPropertyValues().addPropertyValue(beanProperty + "Ids", value);
} else {
Object reference;
if (isPrimitive(type)) {
if ("async".equals(property) && "false".equals(value)
|| "timeout".equals(property) && "0".equals(value)
|| "delay".equals(property) && "0".equals(value)
|| "version".equals(property) && "0.0.0".equals(value)
|| "stat".equals(property) && "1".equals(value)
|| "reliable".equals(property) && "false".equals(value)) {
// backward compatibility for the default value in old version's xsd
value = null;
}
reference = value;
} else if ("onreturn".equals(property)) {
int index = value.lastIndexOf(".");
String returnRef = value.substring(0, index);
String returnMethod = value.substring(index + 1);
reference = new RuntimeBeanReference(returnRef);
beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod", returnMethod);
} else if ("onthrow".equals(property)) {
int index = value.lastIndexOf(".");
String throwRef = value.substring(0, index);
String throwMethod = value.substring(index + 1);
reference = new RuntimeBeanReference(throwRef);
beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod", throwMethod);
} else if ("oninvoke".equals(property)) {
int index = value.lastIndexOf(".");
String invokeRef = value.substring(0, index);
String invokeRefMethod = value.substring(index + 1);
reference = new RuntimeBeanReference(invokeRef);
beanDefinition.getPropertyValues().addPropertyValue("oninvokeMethod", invokeRefMethod);
} else {
if ("ref".equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {
BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);
if(! refBean.isSingleton()) {throw new IllegalStateException("The exported service ref " + value + " must be singleton! Please set the " + value + " bean scope to singleton, eg: <bean id=\"" + value + "\" scope=\"singleton\" ... >");
}
}
reference = new RuntimeBeanReference(value);
}
beanDefinition.getPropertyValues().addPropertyValue(beanProperty, reference);
}
}
}
}
}
}
NamedNodeMap attributes = element.getAttributes();
int len = attributes.getLength();
for (int i = 0; i < len; i++) {
Node node = attributes.item(i);
String name = node.getLocalName();
if(! props.contains(name)) {if (parameters == null) {
parameters = new ManagedMap();
}
String value = node.getNodeValue();
parameters.put(name, newTypedStringValue(value, String.class)); }}if(parameters ! =null) {
beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
}
return beanDefinition;
}
Copy the code
Important interface
Invocation.java
// Encapsulates information about RPC remote calls
public interface Invocation {
* get method name. **@return method name.
* @serial* /
String getMethodName(a);
/** Parameter types (line arguments) * get parameter types@return parameter types.
* @serial* /Class<? >[] getParameterTypes();/** arguments * get arguments. **@return arguments.
* @serial* /
Object[] getArguments();
/** * attachments. **@return attachments.
* @serial* /
Map<String, String> getAttachments(a);
void setAttachment(String key, String value);
void setAttachmentIfAbsent(String key, String value);
/**
* get attachment by key.
*
* @return attachment value.
* @serial* /
String getAttachment(String key);
/**
* get attachment by key with default value.
*
* @return attachment value.
* @serial* /
String getAttachment(String key, String defaultValue);
* get the invoker in current context. **@return invoker.
* @transient* /Invoker<? > getInvoker(); }Copy the code
Invoker.java
/** If inherited from Node, the URL can be obtained through getUrl() method, that is, Invoker can be used as a parameter of the Adaptive method. * is the proxy object of the provider provider, which represents the provider in the code. In particular, when a consumer makes a remote call, it looks for Invoker through mechanisms such as service routing, load balancing, and cluster fault tolerance. You can make a remote call when you find the Invoker instance it needs *. * * /
public interface Invoker<T> extends Node {
/** * get service interface@return service interface.
*/
Class<T> getInterface(a);
/** invoke. * Executes the call and returns the result *@param invocation
* @return result
* @throws RpcException
*/
Result invoke(Invocation invocation) throws RpcException;
}
Copy the code
Exporter.java
/** * Service exposure object. It contains an important method, getInvoker(), that gets the remote invocation instance Invoker contained in the current service exposure instance, that is, the remote invocation that can be made. * /
public interface Exporter<T> {
/**
* get invoker.
*
* @return invoker
*/
Invoker<T> getInvoker(a);
/** * unexport. * * * getInvoker().destroy(); *
*/
void unexport(a);
}
Copy the code
Directory.java
// Directory contains an important method list()
// It returns a List
.
Directory can be understood as a list of invokers that provide a specific service
public interface Directory<T> extends Node {
/**
* get service type.
*
* @return service type.
*/
Class<T> getInterface(a);
/**
* list invokers.
*
* @return invokers
*/
List<Invoker<T>> list(Invocation invocation) throws RpcException;
}
Copy the code