This is the 8th day of my participation in the August Text Challenge.More challenges in August
>>>> 😜😜😜 Github: 👉 github.com/black-ant CASE Backup: 👉 gitee.com/antblack/ca…
A. The preface
The scanning logic of Dubbo Reference is similar to that of DubboService
2. Scanning process
2.1 Application Cases
public class DemoServiceComponent implements DemoService {
@DubboReference
private DemoService demoService;
@Override
public String sayHello(String name) {
returndemoService.sayHello(name); }}Copy the code
2.2 Scanning of DubboReference
How does a Client create a proxy class for the @dubboReference interface
2.2.1 Reference Indicates the starting point of the scan
// The starting point of the Reference scan is DubboBootstrap, which contains this code
public DubboBootstrap start(a) {
/ /...
// Initiate Refer Services processing
referServices();
/ /...
}
private void referServices(a) {
if (cache == null) {
cache = ReferenceConfigCache.getCache();
}
// 2.2.2: The reference in configManager is scanned previously
configManager.getReferences().forEach(rc -> {
// Set the container for it, and refreshReferenceConfig<? > referenceConfig = (ReferenceConfig<? >) rc; referenceConfig.setBootstrap(this);
if(! referenceConfig.isRefreshed()) { referenceConfig.refresh(); }/ /... I don't care about the logic
});
}
Copy the code
CacheManager parameter details
2.2.2 Scanning process of References
How can References be scanned
Step 1: Spring management time creation
In this part, the corresponding class of Bean initialization, the starting point and the Reference is the ReferenceAnnotationBeanPostProcessor postProcessPropertyValues for processing
@Override
public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
prepareInjection(metadata);
// bean: DemoServiceComponent is the previous bean entity class
// beanName : demoServiceComponent
metadata.inject(bean, beanName, pvs);
return pvs;
}
Copy the code
Let’s look at the structure of metadata:
Step 2: Reflection of member variables
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
// Get the member variable, which is the @dubboReference object
Object injectedObject = getInjectedObject(attributes, bean, beanName, getInjectedType(), this);
// TODO: See later here
if (member instanceof Field) {
Field field = (Field) member;
ReflectionUtils.makeAccessible(field);
field.set(bean, injectedObject);
} else if (member instanceofMethod) { Method method = (Method) member; ReflectionUtils.makeAccessible(method); method.invoke(bean, injectedObject); }}Copy the code
Get the injected Bean here
//
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class
injectedType, AnnotatedInjectElement injectedElement) throws Exception {
// injectedElement.injectedObject -> demoService
return getBeanFactory().getBean((String) injectedElement.injectedObject);
}
Copy the code
Step 3: Main process of reference processing
The MBD obtained by the getBean createBean is the ReferenceBean
C- ReferenceBean
public void afterPropertiesSet(a) throws Exception {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// INTERFACE_CLASS -> interfaceClass ->
// INTERFACE_NAME -> interfaceName
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(getId());
this.interfaceClass = (Class<?>) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_CLASS);
this.interfaceName = (String) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_NAME);
// Constants.REFERENCE_PROPS -> referenceProps
if (beanDefinition.hasAttribute(Constants.REFERENCE_PROPS)) {
// @DubboReference annotation at java-config class @Bean method
// @DubboReference annotation at reference field or setter method
As you can see, JavaConfig classes and properties are supported, as well as Setter injection
referenceProps = (Map<String, Object>) beanDefinition.getAttribute(Constants.REFERENCE_PROPS);
} else {
// Here is how different registration types are handled
if (beanDefinition instanceof AnnotatedBeanDefinition) {
// Return ReferenceBean in java-config class @Bean method
ReferenceBeanSupport.convertReferenceProps(referenceProps, interfaceClass);
if (this.interfaceName == null) {
this.interfaceName = (String) referenceProps.get(ReferenceAttributes.INTERFACE); }}else {
// xml reference beanpropertyValues = beanDefinition.getPropertyValues(); }}// -> BEAN_NAME = "dubboReferenceBeanManager";
ReferenceBeanManager referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
referenceBeanManager.addReference(this);
}
Copy the code
Step 4: Management process of Reference
// C- ReferenceBeanManager
public void addReference(ReferenceBean referenceBean) throws Exception {
String referenceBeanName = referenceBean.getId();
PropertyResolver propertyResolver = applicationContext.getEnvironment();
String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, propertyResolver);
ReferenceBean oldReferenceBean = referenceIdMap.get(referenceBeanName);
// There is a detail here, pass! = Judge, but! = compares address references, not objects like equal
// The object address is different, which means that the Bean is created duplicate, meaning that the same instance cannot be created
if(oldReferenceBean ! =null) {
if(referenceBean ! = oldReferenceBean) { String oldReferenceKey = ReferenceBeanSupport.generateReferenceKey(oldReferenceBean, propertyResolver);throw new IllegalStateException("Found duplicated ReferenceBean with id: " + referenceBeanName +
", old: " + oldReferenceKey + ", new: " + referenceKey);
}
return;
}
// private Map<String, ReferenceBean> referenceIdMap = new ConcurrentHashMap<>();
// This is an object that points to the ReferenceBean by id/name
referenceIdMap.put(referenceBeanName, referenceBean);
//save cache, map reference key to referenceBeanName
this.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);
// if add reference after prepareReferenceBeans(), should init it immediately.
if(initialized) { initReferenceBean(referenceBean); }}Copy the code
With the ReferenceBean, the ReferenceConfig object is then created, which will later become the base configuration object for invoke
private synchronized void initReferenceBean(ReferenceBean referenceBean) throws Exception {
if(referenceBean.getReferenceConfig() ! =null) {
return;
}
// reference key -> ReferenceBean:org.apache.dubbo.demo.DemoService()
String referenceKey = ReferenceBeanSupport.generateReferenceKey(referenceBean, applicationContext.getEnvironment());
ReferenceConfig referenceConfig = referenceConfigMap.get(referenceKey);
if (referenceConfig == null) {
// Create the actual ReferenceConfig object using the ReferenceCreator
// Here we get the attributes in the annotation
Map<String, Object> referenceAttributes = ReferenceBeanSupport.getReferenceAttributes(referenceBean);
referenceConfig = ReferenceCreator.create(referenceAttributes, applicationContext)
.defaultInterfaceClass(referenceBean.getObjectType())
.build();
// If not the generated name, set the ID
if(referenceBean.getId() ! =null && !referenceBean.getId().contains("#")) {
referenceConfig.setId(referenceBean.getId());
}
// cache referenceConfig
// private Map
referenceConfigMap = new ConcurrentHashMap<>();
,>
referenceConfigMap.put(referenceKey, referenceConfig);
// register ReferenceConfig -> Step 5
DubboBootstrap.getInstance().reference(referenceConfig);
}
// associate referenceConfig to referenceBean
referenceBean.setKeyAndReferenceConfig(referenceKey, referenceConfig);
}
Copy the code
Now that the comments are complete and the process is clear, let’s look at the logic for caching
Step 5: Config Manager management
public DubboBootstrap reference(ReferenceConfig
referenceConfig) {
// Set the container
referenceConfig.setBootstrap(this);
// Use XML format, I guess it should be saved with the old version, will it be convenient to upgrade?
configManager.addReference(referenceConfig);
return this;
}
// call below
public void addReference(ReferenceConfigBase
referenceConfig)
protected <T extends AbstractConfig> T addConfig(AbstractConfig config, boolean unique) {
// omit null logic
return (T) write(() -> {
Map<String, AbstractConfig> configsMap = configsCache.computeIfAbsent(getTagName(config.getClass()), type -> newMap());
return addIfAbsent(config, configsMap, unique);
});
}
Copy the code
Step 6: Use
It is already in the Cache where it was retrieved in the first place. How is this handled?
3. Supplementary details
3.1 Creation of ReferenceBean
Here, when getBean is reflected, ReferenceBean is reflected, which is actually the relevant logic of Spring IOC
TODO: A little bit more, let’s write a chapter and see how Dubbo brings Spring to life!!
conclusion
Next we will see how a Reference object is converted to an Invoke object