Category 世界杯开户

为什么会这么说呢

因为你的代码改动是最少的,只增加了两个依赖却可以让你的项目从HSF框架轻松转移到Dubbo框架。

经历

阿里巴巴集团业务广泛,涵盖多个领域。在电商领域,拥有淘宝、天猫等核心平台,提供丰富的商品选择和便捷的购物体验。金融领域,通过蚂蚁集团布局支付、贷款、理财等,支付宝成为主流移动支付工具。云计算与大数据方面,阿里云提供全面的云计算服务,助力企业数字化转型。物流领域,菜鸟网络整合物流资源,提升物流效率。此外,阿里巴巴还积极布局新零售、智慧零售,推动线上线下融合,并致力于国际化战略,拓展全球市场。这些业务共同构成了阿里巴巴庞大的商业生态系统。

普通人平常接触更多的则是购物,秉持着“让天下没有难做的生意”这一核心理念,成功引领了全中国普通小商家迈入全新的销售模式。而其旗下的淘宝平台,更是让全国人民享受到了足不出户便能尽收天下好物的极致便利。

作为一个程序员,我对于阿里云平台有着更为深入的了解。阿里云平台作为阿里巴巴集团旗下的云计算服务提供商,凭借其强大的技术实力和丰富的产品线,为广大企业和开发者提供了稳定、安全、高效的云计算解决方案。无论是弹性计算、存储与CDN、数据库、网络与安全,还是大数据、人工智能等领域,阿里云平台都展现出了其卓越的技术实力和市场竞争力。

2017年下半年我开始接触淘宝团队打造的HSF框架,作为项目的分布式框架,有太多的东西需要学习。不过,好在有同事的帮助下,很快了解了此框架是如何在项目中配置的,慢慢地对其源码也产生了好奇。在好奇心的作用下,利用开发工具可以下载源码的功能试图下载源码,可惜的是下载不下来,经过多次百度查询得知HSF框架属于私有框架。

刚开始接触HSF框架的时候正处于公司从Dubbo转换HSF的结尾期,大概是一开始使用Dubbo框架后来公司接入阿里私有云后就切换到了HSF框架,当我接手的时候已经就是HSF框架了,只不过新项目的时候偶尔还能看到Dubbo的影子(应该是之前的项目模板遗留下来的)。

算是从今年开始,看到公司内部有开始迁移分布式框架的动向,发现改动原始代码的代价有点高,再加上本人喜欢研究源码,本着能不动原来的代码尽量就不动原来的代码的原则,准备将HSF框架无缝对接到Dubbo框架。

动手

由于HSF框架的封闭性,从现有的框架代码上动手就有些难搞了,幸好阿里云官方已经实现了HSF、Dubbo注册中心双注册的实现方案,再加上这块实现方案是公开的,源码可以找到,因此,在改造的路上就借鉴了双注册的部分逻辑。

方向

随着SpringBoot的火爆以及公司内部封装了基于HSF的SpringBoot框架,因此,此次改动的目标是基于内部封装的框架由HSF无缝迁移到Dubbo。

SpringBoot版HSF叫做PandoraBoot,基于注解的形式完成HSF注册和消费,因此,着手点首先要从@HSFProvider和@HSFConsumer两个注解开始。

1. @HSFProvider

入口文件HSFProviderAnnotationRegistrar,由于实现了ImportBeanDefinitionRegistrar接口,启动项目会通过registerBeanDefinitions方法注册bean,具体逻辑如下:

HSFProvider HSFProvider = (HSFProvider)AnnotationUtils.findAnnotation(targetClass, HSFProvider.class);

// 省略部分代码...

HSFProviderBeanDefinitionBuilder builder = (new HSFProviderBeanDefinitionBuilder(targetBeanName, HSFProvider)).clazz(targetClass).properties(HSFProperties);

BeanDefinition beanDefinition = builder.build(registry);

if (beanDefinition != null) {

if (registry.containsBeanDefinition(beanName)) {

throw new BeanDefinitionValidationException("BeanDefinition with the same beanName already existed, please check your config! beanName:" + beanName);

}

registry.registerBeanDefinition(beanName, beanDefinition);

// 省略部分代码...

}

通过HSFProviderBeanDefinitionBuilder构建BeanDefinition,其build方法通过BeanDefinitionBuilder注册HSFSpringProviderBean。

这块改造逻辑借鉴了Dubbo的处理思路,通过@DubboService注解查找到ServiceAnnotationPostProcessorbean后置处理类,postProcessBeanFactory方法处理逻辑如下:

BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);

// 查找通过@DubboService注解的类并获取属性

Map annotationAttributes = getServiceAnnotationAttributes(beanDefinition);

if (annotationAttributes != null) {

// 注册BeanDefinition

processAnnotatedBeanDefinition(

beanName, (AnnotatedBeanDefinition) beanDefinition, annotationAttributes);

}

private void processAnnotatedBeanDefinition(

String refServiceBeanName,

AnnotatedBeanDefinition refServiceBeanDefinition,

Map attributes) {

Map serviceAnnotationAttributes = new LinkedHashMap<>(attributes);

// 省略部分代码...

// 构建AbstractBeanDefinition,其实就是对BeanDefinition的构建

AbstractBeanDefinition serviceBeanDefinition =

buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, refServiceBeanName);

// set id

serviceBeanDefinition.getPropertyValues().add(Constants.ID, serviceBeanName);

// 注册BeanDefinition

registerServiceBeanDefinition(serviceBeanName, serviceBeanDefinition, serviceInterface);

}

了解到Dubbo的注册过程,实际改造过程中也是通过实现BeanDefinitionRegistryPostProcessor接口完成BeanDefinition的构建与注册,其逻辑如下:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

String[] beanNames = beanFactory.getBeanDefinitionNames();

for (String beanName : beanNames) {

BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);

// 消费者

if (isHsfConsumerBean(beanDefinition)) {

// 省略部分代码...

}

// 提供者

else if (isHsfProviderBean(beanDefinition)) {

// 注册Dubbo bean

HsfProviderDubboService.registerBeanDefinition(beanName, this.applicationContext, beanDefinition, this.environment, registry);

if (this.registry.getBeanDefinition(beanName) != null) {

// 为了清除hsf注册中心注册实例

this.registry.removeBeanDefinition(beanName);

}

}

// 省略部分代码...

}

}

public static void registerBeanDefinition(String beanName, ApplicationContext applicationContext, BeanDefinition providerBeanDefinition, Environment environment, BeanDefinitionRegistry registry) {

BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(providerBeanDefinition, beanName);

// 具体注册逻辑

processScannedBeanDefinition(beanDefinitionHolder, applicationContext.getClassLoader(), environment, registry);

}

private static void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, ClassLoader classLoader, Environment environment, BeanDefinitionRegistry registry) {

// The attributes of @Service annotation

Map serviceAnnotationAttributes =

ReferenceBeanSupport.convertPropertyValues(beanDefinitionHolder.getBeanDefinition().getPropertyValues());

Map dubboAttributes = new HashMap<>(serviceAnnotationAttributes.size());

cleanAttribute(serviceAnnotationAttributes, dubboAttributes, "serviceInterface", "interfaceClass");

cleanAttribute(serviceAnnotationAttributes, dubboAttributes, "serviceGroup", "group");

cleanAttribute(serviceAnnotationAttributes, dubboAttributes, "serviceVersion", "version");

BeanDefinition beanDefinition = registry.getBeanDefinition(serviceAnnotationAttributes.get("target").toString());

Class beanClass = resolveClass(beanDefinition, classLoader);

String serviceInterface = resolveInterfaceName(dubboAttributes, beanClass);

String annotatedServiceBeanName = serviceAnnotationAttributes.get("target").toString();

// ServiceBean Bean name

String beanName = generateServiceBeanName(dubboAttributes, serviceInterface, environment);

// 构建BeanDefinition

AbstractBeanDefinition serviceBeanDefinition =

buildServiceBeanDefinition(dubboAttributes, serviceInterface, annotatedServiceBeanName, environment);

// 注册,由于代码逻辑简单就不再展示了

// 核心代码:registry.registerBeanDefinition(serviceBeanName, serviceBeanDefinition)

registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface, registry);

}

2. 展示

3. @HSFConsumer

入口文件HsfConsumerPostProcessor,由于实现了BeanFactoryPostProcessor接口,启动项目会通过postProcessBeanFactory方法注册bean,消费者逻辑与Dubbo类似,具体逻辑如下:

private void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory, BeanDefinitionRegistry registry) {

final HsfProperties properties = HsfPropertiesUtils.buildHsfProperties(this.environment);

new HashMap();

String[] var5 = beanFactory.getBeanDefinitionNames();

int var6 = var5.length;

for(int var7 = 0; var7 < var6; ++var7) {

String beanName = var5[var7];

BeanDefinition definition = beanFactory.getBeanDefinition(beanName);

String beanClassName = definition.getBeanClassName();

if (beanClassName != null) {

Class clazz = ClassUtils.resolveClassName(definition.getBeanClassName(), this.classLoader);

ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {

public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {

// 解析@HSFConsumer属性

HsfConsumerPostProcessor.this.parseElement(field, properties);

}

});

}

}

// 省略部分代码...

while(var12.hasNext()) {

String beanName = (String)var12.next();

if (this.context.containsBean(beanName)) {

throw new IllegalArgumentException("[HSF Starter] Spring context already has a bean named " + beanName + ", please change @HSFConsumer field name.");

}

// 注册bean

registry.registerBeanDefinition(beanName, (BeanDefinition)this.beanDefinitions.get(beanName));

}

}

private void parseElement(Field field, HsfProperties properties) {

// 获取注解属性

HSFConsumer annotation = (HSFConsumer)AnnotationUtils.getAnnotation(field, HSFConsumer.class);

if (annotation != null) {

HsfConsumerBeanDefinitionBuilder beanDefinitionBuilder = new HsfConsumerBeanDefinitionBuilder(field.getType(), annotation);

beanDefinitionBuilder.context(this.context).beanFactory(this.beanFactory).properties(properties);

// 构建BeanDefinition,解析注解属性

BeanDefinition beanDefinition = beanDefinitionBuilder.build();

if (this.checkFieldNameDuplicate4FirstTime(field.getName(), beanDefinition)) {

logger.error("registered HSFConsumerBean with duplicate fieldName:{} in spring context.", field.getName());

}

this.beanDefinitions.put(field.getName(), beanDefinition);

}

}

通过HsfConsumerBeanDefinitionBuilder解析@HSFConsumer属性,随后通过build方法并构建BeanDefinition。

从上文注册@DubboService的过程可以发现,postProcessBeanFactory方法预留了处理Hsf消费者的逻辑,

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

String[] beanNames = beanFactory.getBeanDefinitionNames();

for (String beanName : beanNames) {

BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);

// 消费者

if (isHsfConsumerBean(beanDefinition)) {

try {

// 构建BeanDefinition

BeanDefinition consumerDefinition =

HsfConsumerDubboService.registerBeanDefinition(beanName, this.applicationContext, this.referenceBeanManager, beanDefinition);

if (this.registry.getBeanDefinition(beanName) != null) {

// 为了清除hsf注册中心注册实例

this.registry.removeBeanDefinition(beanName);

}

// 构建bean

this.registry.registerBeanDefinition(beanName, consumerDefinition);

} catch (ClassNotFoundException e) {

throw new RuntimeException(e);

}

} else if (isHsfProviderBean(beanDefinition)) {

// 服务提供者逻辑...

}

if (isAnnotatedReferenceBean(beanDefinition)) {

}

}

}

public static BeanDefinition registerBeanDefinition(String beanName, ApplicationContext applicationContext,

ReferenceBeanManager referenceBeanManager, BeanDefinition consumerBeanDefinition)

throws ClassNotFoundException {

MutablePropertyValues mutablePropertyValues = consumerBeanDefinition.getPropertyValues();

Map propertyAttributes = ReferenceBeanSupport.convertPropertyValues(mutablePropertyValues);

// check reference key

String referenceKey = ReferenceBeanSupport.generateReferenceKey(propertyAttributes, applicationContext);

Object propertyValue = propertyAttributes.get("id");

String referenceBeanName = beanName;

if (propertyValue != null) {

referenceBeanName = propertyValue.toString();

}

Map attributes = new HashMap<>();

attributes.put(ReferenceAttributes.ID, referenceBeanName);

// 将hsf属性转换为dubbo属性

resolveDubboAttributes(propertyAttributes, attributes);

// Register the reference bean definition to the beanFactory

RootBeanDefinition beanDefinition = new RootBeanDefinition();

beanDefinition.setBeanClassName(ReferenceBean.class.getName());

beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, referenceBeanName);

// set attribute instead of property values

beanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);

String interfaceName = attributes.get("interface").toString();

Class interfaceClass = Class.forName(interfaceName);

beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);

beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);

// create decorated definition for reference bean, Avoid being instantiated when getting the beanType of ReferenceBean

// see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()

GenericBeanDefinition targetDefinition = new GenericBeanDefinition();

targetDefinition.setBeanClass(interfaceClass);

beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, referenceBeanName + "_decorated"));

// signal object type since Spring 5.2

beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);

referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);

logger.info("Register dubbo reference bean: " + referenceBeanName + " = " + referenceKey);

return beanDefinition;

}

4. 展示

最终效果

结语

这次改动不仅仅只是适配SpringBoot框架,SpringMvc其实也是适配的,上述UserDemoService服务是通过注解注入的服务,而RoleDemoService服务是由xml配置提供的服务。

最终源码有时间会公开提供下,或者私信也可以。

top
Copyright © 2088 世界杯四强_世界杯裁判 - tylwn.com All Rights Reserved.
友情链接