前言
现在SpringCloud Alibaba 十分热门, dubbo作为阿里的招牌微服务相关的框架,自然整合进入了SpringCloud了. 我找了下官网发现如下的maven依赖.
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
我引入项目中看下dubbo和springcloud是如何整合的.
我的项目的注册中心使用的是阿里的nacos.
项目结构
看下截图
spring的spi机制就是通过 spring.factories
文件来加载starter模块中的类的, 从截图中可以看到的配置类如下:
EnableAutoConfiguration
配置类如下
com.alibaba.cloud.dubbo.autoconfigure.DubboMetadataAutoConfiguration
com.alibaba.cloud.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationNonWebApplicationAutoConfiguration
com.alibaba.cloud.dubbo.autoconfigure.DubboLoadBalancedRestTemplateAutoConfiguration
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceAutoConfiguration
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration
com.alibaba.cloud.dubbo.actuate.DubboMetadataEndpointAutoConfiguration
上面都是dubbo配置相关的类, 我们通过类名先从重要的配置类(看源码要先抓重点)看起
DubboServiceAutoConfiguration 类
- 从类的头部加载
DubboCloudProperties
配置类, 这个类中的源码很简单就是定义下加载的服务的范围, 默认是全部的. - 如果没有DubboGenericServiceFactory 则创建一个DubboGenericServiceFactory的bean. 这个从类名就可以知道是创建Dubbo的服务的工厂类, 内部机制不在这里详解
- 引入一堆的请求参数, 请求变量,请求头等等的Resolver类, 不详解了
可以看到DubboServiceAutoConfiguration类就是引入一些配置和重要的类, 很简单, 我们接着看下个配置类
DubboServiceDiscoveryAutoConfiguration
从类名就可以看到这个是与服务发现相关的配置, 必然会与注册中心相关;
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration
- 从类头看到生效条件必须是
org.springframework.cloud.client.discovery.DiscoveryClient
类存在并且spring.cloud.discovery.enabled 配置true - 并且 在一堆 大写的变量对应的配置类之后进行配置 , 这一堆的大写变量名的配置类其实就是dubbo支持的各种配置中心类. 我使用的是Nacos配置类, 对应的变量是
NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME
, 配置类是com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration
- 在这个类的存在内部配置类
com.alibaba.cloud.dubbo.autoconfigure.DubboServiceDiscoveryAutoConfiguration.NacosConfiguration
这个类的源码如下
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(name = NACOS_DISCOVERY_AUTO_CONFIGURATION_CLASS_NAME) //表示容器中存在NacosDiscoveryAutoConfiguration的时候这个配置才会生效
class NacosConfiguration {
private final NamingService namingService;
private final NacosDiscoveryProperties nacosDiscoveryProperties;
/**
* the set of services is listening.
*/
private final Set<String> listeningServices;
/**
* 构造方法, 有参数的构造方法, 参数会从容器中取得
*/
NacosConfiguration(NacosServiceManager nacosServiceManager,
NacosDiscoveryProperties nacosDiscoveryProperties) {
this.namingService = nacosServiceManager
.getNamingService(nacosDiscoveryProperties.getNacosProperties());
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.listeningServices = new ConcurrentSkipListSet<>();
}
/**
* Nacos uses {@link EventListener} to trigger.
* {@link #dispatchServiceInstancesChangedEvent(String, Collection)} , thus
* {@link HeartbeatEvent} handle is always ignored
* @return <code>false</code> forever
*/
@Bean
public Predicate<HeartbeatEvent> heartbeatEventChangedPredicate() {
return event -> false;
}
/**
* 监听事件, 从事件名称看到是订阅的服务变更事件, 这个事件的产生地方还不知道
*/
@EventListener(SubscribedServicesChangedEvent.class)
public void onSubscribedServicesChangedEvent(SubscribedServicesChangedEvent event)
throws Exception {
// subscribe EventListener for each service
event.getNewSubscribedServices().forEach(this::subscribeEventListener);
}
/**
* 监听器, 监听注册中心中的变化
*/
private void subscribeEventListener(String serviceName) {
if (listeningServices.add(serviceName)) {
try {
String group = nacosDiscoveryProperties.getGroup();
namingService.subscribe(serviceName, group, event -> {
if (event instanceof NamingEvent) {
NamingEvent namingEvent = (NamingEvent) event;
List<ServiceInstance> serviceInstances = hostToServiceInstanceList(
namingEvent.getInstances(), serviceName);
dispatchServiceInstancesChangedEvent(serviceName,
serviceInstances);
}
});
}
catch (NacosException e) {
ReflectionUtils.rethrowRuntimeException(e);
}
}
}
}
类中都有注释, 这个类的主要作用如下:
- 通过构造参数注入 一些nacos 相关的配置信息
- 创建监听方法, 监听注册中心的变化
- 构建一个与注册中心相关的心跳监听的时间(这部分存在疑问)
DubboServiceDiscoveryAutoConfiguration类就是加载对应的配置中心的信息.
DubboServiceRegistrationAutoConfiguration 服务注册配置相关类
@Configuration(proxyBeanMethods = false)
@Import({ DubboServiceRegistrationEventPublishingAspect.class,
DubboBootstrapStartCommandLineRunner.class })
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
matchIfMissing = true)
@AutoConfigureAfter(name = { EUREKA_CLIENT_AUTO_CONFIGURATION_CLASS_NAME,
CONSUL_AUTO_SERVICE_AUTO_CONFIGURATION_CLASS_NAME,
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" },
value = { DubboMetadataAutoConfiguration.class })
public class DubboServiceRegistrationAutoConfiguration {
.......
从 这个类头可以看到, 又引入了两个bean到容器中 DubboServiceRegistrationEventPublishingAspect 和 DubboBootstrapStartCommandLineRunner;
- DubboServiceRegistrationEventPublishingAspect 是切面类, 对SpringCloud的服务注册和注销进行切面操作, 这些切面操作主要是进行事件发布;
- DubboBootstrapStartCommandLineRunner是在spring启动完成后执行的钩子方法, 在钩子方法中也是发送一个dubbo启动完成后的事件.
defaultSpringCloudRegistryConfig 默认的springcloud注册配置类, 这个方式是生成配置放入容器, 其中Address
后面的还没时间详细查看
org.springframework.context.ApplicationContextInitializer
- com.alibaba.cloud.dubbo.context.DubboServiceRegistrationApplicationContextInitializer
org.springframework.boot.env.EnvironmentPostProcessor
com.alibaba.cloud.dubbo.env.DubboNonWebApplicationEnvironmentPostProcessor