热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

dubboservice注解用法_dubbo系列之springboot核心配置读取(三)

欢迎关注公众号【sharedCode】致力于主流中间件的源码分析,可以直接与我联系版本说明springbootstarter:0.1.1dubbo版本:2.6.2自动
欢迎关注公众号【sharedCode】致力于主流中间件的源码分析, 可以直接与我联系

版本说明

springboot starter : 0.1.1

dubbo版本: 2.6.2

自动配置类

@Configuration
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true, havingValue = "true")
@ConditionalOnClass(AbstractConfig.class)
public class DubboAutoConfiguration {// 单个dubbo配置绑定bean , 默认就是单个@EnableDubboConfigprotected static class SingleDubboConfigConfiguration {}/*** 多个dubbo配置绑定bean , 默认不使用。**/@ConditionalOnProperty(name = MULTIPLE_CONFIG_PROPERTY_NAME, havingValue = "true")@EnableDubboConfig(multiple = true)protected static class MultipleDubboConfigConfiguration {}/*** service类,服务提供者的BeanDefinitionRegistryPostProcessor类,用来解析* @Service注解,生成Service的BeanDefinition类,放入spring容器,供spring容器生成Bean**/@ConditionalOnProperty(name = BASE_PACKAGES_PROPERTY_NAME)@ConditionalOnClass(RelaxedPropertyResolver.class)@Beanpublic ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor(Environment environment) {RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment);Set packagesToScan = resolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());return new ServiceAnnotationBeanPostProcessor(packagesToScan);}// springboot dataBinder 机制的扩展,用来将具体的属性设置到相应的实体类里面去。@ConditionalOnClass(RelaxedDataBinder.class)@Bean@Scope(scopeName = SCOPE_PROTOTYPE)public RelaxedDubboConfigBinder relaxedDubboConfigBinder() {return new RelaxedDubboConfigBinder();}/*** 用来解析@Reference 注解,消费者引用哪些服务,通过这个注解来进行引用* 给标注这个@Reference注解的属性赋值, 和@autowired的做法类似。* */@ConditionalOnMissingBean@Bean(name = ReferenceAnnotationBeanPostProcessor.BEAN_NAME)public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() {return new ReferenceAnnotationBeanPostProcessor();}}

配置说明:

SingleDubboConfigConfiguration : 引入了单个dubbo配置绑定bean的配置 , 默认使用

// 配置如下
dubbo.application
dubbo.module
dubbo.registry
dubbo.protocol
dubbo.monitor
dubbo.provider
dubbo.consumer

MultipleDubboConfigConfiguration :多个dubbo配置绑定bean , 默认不使用。Dubbo @Service@Reference 允许 Dubbo 应用关联ApplicationConfig Bean 或者指定多个RegistryConfig Bean 等能力。换句话说,Dubbo 应用上下文中可能存在多个ApplicationConfig 等 Bean定义。

// 配置如下
dubbo.applications
dubbo.modules
dubbo.registries
dubbo.protocols
dubbo.monitors
dubbo.providers
dubbo.consumers

serviceAnnotationBeanPostProcessor :解析service类注解的类,如果在spring boot启动类上配置了@DubboComponentScan 则默认不使用。

referenceAnnotationBeanPostProcessor : 为@Reference注入对象,如果在spring boot启动类上配置了@DubboComponentScan 则默认不使用。

因为在@DubboComponentScan这个注解中引入了DubboComponentScanRegistrar这个注册类,该类中做了解析@service注解和@Reference的事情

@EnableDubboConfig

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationSelector.class) // 主要作用是这个
public @interface EnableDubboConfig {/*** It indicates whether binding to multiple Spring Beans.** @return the default value is false* @revised 2.5.9*/boolean multiple() default false;}

主要的作用就是导入了这个类DubboConfigConfigurationSelector

DubboConfigConfigurationSelector

public class DubboConfigConfigurationSelector implements ImportSelector, Ordered {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {// 获取注解上的属性,这个是通过@EnableDubboConfig导入的,所以AnnotationMetadata里面就包含了这个注解的值AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));// 是否是多配置,默认为falseboolean multiple = attributes.getBoolean("multiple");if (multiple) {return of(DubboConfigConfiguration.Multiple.class.getName());} else {// 这里就直接讲解单配置的。return of(DubboConfigConfiguration.Single.class.getName());}}private static T[] of(T... values) {return values;}@Overridepublic int getOrder() {return HIGHEST_PRECEDENCE;}}

DubboConfigConfigurationSelector这个类实现了ImportSelector 接口,该接口的selectImports方法就是返回bean的名称,供spring初始化,所以这里返回了

DubboConfigConfiguration.Single.class.getName() , spring就会初始化这个类了。

Single

DubboConfigConfiguration.Single的代码如下 , 通过@EnableDubboConfigBindings注解,导入了多个@EnableDubboConfigBinding

@EnableDubboConfigBindings({@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),@EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),@EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),@EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),@EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),@EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),@EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class)})public static class Single {}

EnableDubboConfigBindings

由上面可以看到,spring在初始化Single这个类的时候,必然会加载他上面的注解,该类的主要作用就是为了导入它上面的注解,@EnableDubboConfigBindings

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class) // 导入了这个类。
public @interface EnableDubboConfigBindings {/*** The value of {@link EnableDubboConfigBindings}** @return non-null*/EnableDubboConfigBinding[] value();}

@EnableDubboConfigBindings 注解导入了DubboConfigBindingsRegistrar这个类,该类的作用是将配置属性和dubbo的配置进行绑定。注解的value是7个子注解

@EnableDubboConfigBinding ,后面DubboConfigBindingsRegistrar解析的时候,会获取到这个7个子注解,将对应的属性和dubbo的配置类进行绑定。

DubboConfigBindingsRegistrar

public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {private ConfigurableEnvironment environment;@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 获取导入此类的注解信息,@EnableDubboConfigBindingsAnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));// 获取@EnableDubboConfigBinding 子注解AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");// 初始化DubboConfigBindingRegistrar类,该类的主要作用就是为了解析单个的@EnableDubboConfigBinding注解DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();registrar.setEnvironment(environment);for (AnnotationAttributes element : annotationAttributes) {// 循环注册,通过注解里面的信息,生成Dubbo配置的BeanDefinition,最后放入spring容器中,供spring容器实例化。registrar.registerBeanDefinitions(element, registry);}}@Overridepublic void setEnvironment(Environment environment) {Assert.isInstanceOf(ConfigurableEnvironment.class, environment);this.environment = (ConfigurableEnvironment) environment;}}

注册dubbo的配置bean

protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {//1. 从环境 中取出 响应的属性名 String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));// 2. 获取dubbo的配置类的classClass configClass = attributes.getClass("type");// 3. 获取是否是多个dubbo的配置boolean multiple = attributes.getBoolean("multiple");// 注册dubbo的配置beanregisterDubboConfigBeans(prefix, configClass, multiple, registry);}

步骤说明:

1.参数attributes就是@EnableDubboConfigBinding里面的属性,获取prefix属性值,就是获取到了:dubbo.application

例:

@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class)

2.获取dubbo的配置类的class,也就是获取到了ApplicationConfig.class

3.获取multiple的值,默认没有配置就是false

4.调用registerDubboConfigBeans方法生成dubbo的配置bean

private void registerDubboConfigBeans(String prefix,Class configClass,boolean multiple,BeanDefinitionRegistry registry) {// 根据属性名,如:dubbo.application 获取具体的属性值Map properties = getSubProperties(environment.getPropertySources(), prefix);if (CollectionUtils.isEmpty(properties)) {// 如果没有配置,则没有必要生成对应的dubbo配置bean了if (log.isDebugEnabled()) {log.debug("There is no property for binding to dubbo config class [" + configClass.getName()+ "] within prefix [" + prefix + "]");}return;}// BeanNameSet beanNames = multiple ? resolveMultipleBeanNames(properties) :Collections.singleton(resolveSingleBeanName(properties, configClass, registry));for (String beanName : beanNames) {// 生成benaregisterDubboConfigBean(beanName, configClass, registry);// 注册dubbo的DubboConfigBindingBeanPostProcessorregisterDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);}}private void registerDubboConfigBean(String beanName, Class configClass,BeanDefinitionRegistry registry) {// 生成BeanDefinitionBuilderBeanDefinitionBuilder builder = rootBeanDefinition(configClass);AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();// 通过BeanDefinitionRegistry注册dubbo的配置beanregistry.registerBeanDefinition(beanName, beanDefinition);if (log.isInfoEnabled()) {log.info("The dubbo config bean definition [name : " + beanName + ", class : " + configClass.getName() +"] has been registered.");}}

DubboConfigBindingBeanPostProcessor

这个类是在dubbo的配置类初始化完成后会执行响应的方法。用来将属性值设置到对应的属性里面去,在springboot中我们存在这种情况

first-name,firstName, FIRST_NAME , 比如我们在yaml文件中配置这样的属性,我们的java bean中的属性是firstName , 在使用@ConfigurationProperties

注解的时候我们无需担心,如果不是用springboot自身的config类来注入,那么我们自己处理这种情况就会变的非常麻烦,所以dubbo选择的是通过RelaxedDataBinder类来处理这个问题。这是spring boot的机制。

DubboConfigBindingBeanPostProcessor类实现了BeanPostProcessor,ApplicationContextAware, InitializingBean 这三个接口,下面是挑了一些重要的方法展示出来 , 每个dubbo配置类都有相应的DubboConfigBindingBeanPostProcessor

public DubboConfigBindingBeanPostProcessor(String prefix, String beanName) {Assert.notNull(prefix, "The prefix of Configuration Properties must not be null");Assert.notNull(beanName, "The name of bean must not be null");this.prefix = prefix; // 属性前缀this.beanName = beanName; // dubbo的配置类名}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {// 会在每一个bean实例化之后、初始化(如afterPropertiesSet方法)之前被调用。if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) {AbstractConfig dubboConfig = (AbstractConfig) bean;// 将属性和配置进行绑定dubboConfigBinder.bind(prefix, dubboConfig);if (log.isInfoEnabled()) {log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " +"configuration properties : " + prefix);}}return bean;}@Override
public void afterPropertiesSet() throws Exception {// DubboConfigBindingBeanPostProcessor 初始化之后就会执行if (dubboConfigBinder == null) {try {// 从容器中获取DubboConfigBinder , DubboConfigBinder的作用范围是prototype , 每次调用getbean都会新创建一个dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class);} catch (BeansException ignored) {if (log.isDebugEnabled()) {log.debug("DubboConfigBinder Bean can't be found in ApplicationContext.");}// Use Default implementationdubboConfigBinder = createDubboConfigBinder(applicationContext.getEnvironment());}}dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields);dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields);}

dubboConfigBinder的代码如下,下面主要就是调用springboot 的dataBinder机制进行属性设值了

public class RelaxedDubboConfigBinder extends AbstractDubboConfigBinder {@Overridepublic void bind(String prefix, C dubboConfig) {RelaxedDataBinder relaxedDataBinder = new RelaxedDataBinder(dubboConfig);// Set ignored*relaxedDataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields());relaxedDataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields());//从Environment中获取属性Map properties = getSubProperties(getPropertySources(), prefix);// 将属性MAP转换为MutablePropertyValuesMutablePropertyValues propertyValues = new MutablePropertyValues(properties);// 绑定relaxedDataBinder.bind(propertyValues);}
}

通过上面的源码,可以看出来,dubbo的配置是一环接着一环,很多时候一个不起眼的地方就是往下走的关键代码,他主要是通过注解的导入配置类,然后通过

BeanDefinitionRegistry生成对应的beanDefintion放入spring容器中。

本文所解析的这些源码均不涉及dubbo的核心功能,仅仅是讲了dubbo启动之后,如何获取到配置,如果进行配置装配,方便大家后续有个好的理解。

有兴趣可以看下一spring的扩展机制,dubbo中都有大量的使用到。

扩展Spring的几种方式​nobodyiam.com
8f05b0ee06b95e96d8aee5ea25f323eb.png
欢迎关注公众号【sharedCode】致力于主流中间件的源码分析, 可以直接与我联系



推荐阅读
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
author-avatar
pomngjkldjg_849_788
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有