要做什么
看dubbo官网后发现有dubbo直连这种方式,简化了我们开发环境的流程,不再需要启动注册中心。于是想要应用到自己项目中去。 但是各类网站看了很多dubbo直连的案例,基本都和官网一致,一个一个service 指定 url,这样的方式不太符合我们自己项目,我想要的是所有的service 使用 dubbo://127.0.0.1:20880 url
dubbo版本:2.7.8
源码过程分析
这里先创建的一个又Spring 管理的Controller, 其中只有一个属性且被Reference 注解标识,然后我们看一下这个实力注入流程: 一、 扫描到Controller 类进行实例化 二、 populate 属性注入 在这一步 扫描到Reference注解标识的属性,开始生成代理对象
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#doGetInjectedBean
// 进行一系列解析,不过多赘述
调用referenceBean.get()
执行 org.apache.dubbo.config.ReferenceConfig#init
org.apache.dubbo.config.ReferenceConfig#checkAndUpdateSubConfigs
org.apache.dubbo.config.ReferenceConfigBase#resolveFile // 这个地方解析了dubbo文件 中配置的url
org.apache.dubbo.config.ReferenceConfig#postProcessConfig // 这里是一个可扩展点,如何扩展往下面看
//方法源码
private void postProcessConfig() {
List<ConfigPostProcessor> configPostProcessors = ExtensionLoader.getExtensionLoader(ConfigPostProcessor.class)
.getActivateExtension(URL.valueOf("configPostProcessor://"), (String[]) null);
configPostProcessors.forEach(component -> component.postProcessReferConfig(this));
}
ConfigPostProcessor 接口点进去发现是一个spi扩展接口
虽然官网没写这个接口如何扩展,我们可以仿造其他的spi扩展 以及自己debug
首先 实现ConfigPostProcessor 接口可以设置ReferenceConfig 的属性,后面会将其属性加入到一个map,之后利用map创建代理类(也在init方法中, 创建赋值给ref,前面的referenceBean.get() 返回的就是ref )
最开始的想法:
1、利用filter,每次调用前 切换invoker中的url,层数太多不太好设置
2、利用spring 的扩展,bpp 等方法,判断其中的不是reference的属性,进行修改,和上面一样
实际coding
基于ConfigPostProcessor 接口进行spi扩展
@Activate(group = {CommonConstants.CONSUMER})
public class DubboRedirectConfigPostProcessor implements ConfigPostProcessor {
```
public static final String DUBBO_URL = "dubbo://127.0.0.1:20880";
private List<String> activeProfiles;
/**
* org.apache.dubbo.config.ReferenceConfig#postProcessConfig() 调用
* @param referenceConfig
*/
public void postProcessReferConfig(ReferenceConfig referenceConfig) {
if (!activeProfiles.contains("dev")) {
// 仅在开发环境使用直连方式
return;
}
// 可以根据包名等判断 设置dubbo url等内容
System.out.println("dubbo扩展 " + referenceConfig.getServiceMetadata().getServiceType());
referenceConfig.setUrl(DUBBO_URL);
}
@Override
// dubbo 实例化此类后,从spring上下文对象中获取Environment对象作为参数执行
public void setEnvironment(Environment environment) {
this.activeProfiles = Arrays.asList(environment.getActiveProfiles());
}
}
在META-INF.dubbo下创建com.alibaba.dubbo.config.ConfigPostProcessor 的文件, 写入你的全路径实现类dubboDirect=com.config.DubboDirectConfigPostProcessor
如果你上述步骤没有问题, configPostProcessors 就成功加入了你的实现类, 可以再postProcessReferConfig 方法中实现更多的扩展
其他配置就和官网介绍一的一样了,服务提供方 在application.properties中设置
dubbo.registry.check=false
dubbo.registry.address=N/A
只在dev生效
DubboRedirectConfigPostProcessor 实现EnvironmentAware 接口,判断getActiveProfiles 环境 是否需要执行postProcessReferConfig 方法就可以了,
在dubbo中 有这样的org.apache.dubbo.config.spring.extension.SpringExtensionFactory,其中包含了spring 的上下文对象,源码中在实例化后,解析方法,解析到setEnvironment 标准命名的方法后,从上下文对象中获取 Environment 对象作为参数, 执行此方法
org.apache.dubbo.common.extension.ExtensionLoader#getExtension(java.lang.String, boolean)
org.apache.dubbo.common.extension.ExtensionLoader#createExtension
try {
String property = getSetterProperty(method);
// 从spring上下文 获取到Environment
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
// 执行set方法
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("Failed to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}