`

dubbo源码解析(1)

    博客分类:
  • java
阅读更多

Dubbo代码解析

 

    dubbo发布服务端的源码解析。

dubbo发布服务不需要集成重量级的web服务器,直接提供了com.alibaba.dubbo.container.Main进行

启动发布。

if (args == null || args.length == 0) {

                String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName());

                args = Constants.COMMA_SPLIT_PATTERN.split(config);

            }

开始判断main函数的传入参数,在args参数为空的情况下,从部署环境中取得dubbo.container属性,

dubbo提供了configUtils的dubbo环境配置的访问工具类。

下面就是configUtils的取得属性的配置的顺序

 

        String value = System.getProperty(key);

        if (value != null && value.length() > 0) {

            return value;

        }

        Properties properties = getProperties();

        return replaceProperty(properties.getProperty(key, defaultValue), (Map)properties);

先是从取得系统属性,如果取得有效配置值则直接采用,否则去构造配置对象,从配置对象中取得配置值,

 

 

下面是构造配置对象的代码:

private static volatile Properties PROPERTIES;

    

    public static Properties getProperties() {

        if (PROPERTIES == null) {

            synchronized (ConfigUtils.class) {

                if (PROPERTIES == null) {

                    String path = System.getProperty(Constants.DUBBO_PROPERTIES_KEY);

                    if (path == null || path.length() == 0) {

                        path = System.getenv(Constants.DUBBO_PROPERTIES_KEY);

                        if (path == null || path.length() == 0) {

                            path = Constants.DEFAULT_DUBBO_PROPERTIES;

                        }

                    }

                    PROPERTIES = ConfigUtils.loadProperties(path, falsetrue);

                }

            }

        }

        return PROPERTIES;

}

采用懒加载的模式,进行构造,为了保证这段代码能在多线程下执行,运用了严格加锁的机制。先是通过寻求系统属性值dubbo.properties.file,如果存在,直接加载以此作为路径加载文件。没有设置的话就采用默认的配置文件dubbo.properties。然后就会通过先直接搜索文件系统,类路径等方式,来取得系统的配置。当然整个配置文件默认的可以没有,而且只有一个文件才会起作用。

然后从属性环境中读取到dubbo.container值,得到需要以命名方式加载哪些container

 final List<Container> containers = new ArrayList<Container>();

            for (int i = 0; i < args.length; i ++) {

                containers.add(loader.getExtension(args[i]));

            }

 

Container是接口。

dubbo中有很多被spi注释的接口。这些都是具有很强扩展能力的地方。

@SPI("spring")

public interface Container {

    

    /**

     * start.

     */

    void start();

    

    /**

     * stop.

     */

    void stop();

 

}

每个spi注解的实现类都是有扩展点加载器(ExtensionLoader)进行加载,

main类中,直接定义了一个静态变量:

 private static final ExtensionLoader<Container> loader = ExtensionLoader.getExtensionLoader(Container.class);

在加载Main类的时候,就会以Container类为参数直接加载。

下面看看getExtensionLoader函数。

在这个函数中先做Container中做有效性验证,而且判断是否被spi注解注释。进一步确认了扩展点加载器只能加载被spi注解的类。

ExtensionLoader类中存在

  private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();

spi接口类和对应的加载器一一对应起来,同时提供懒加载的缓存作用。

下面是extensionloader的简单类图:

其中extensionFactory是扩展点是一个工厂类,因为扩展点实现如果依赖其他的类的话,只要,在里面依赖的对象遵从javabean方式,那么dubbo就会在环境对象池中(这里主要是spring容器以及扩展点工厂中取得依赖的对象)。

 objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());

ExtensionFactory本身就是spi扩展点类,所以它也需要ExtensionLoader进行加载。

ExtensionLoader这里用了一种变异的单例模式,因为ExtensionLoader对于每个扩展点只有一个。

ExtensionFactory的扩展实现,是通过这个spi接口对应的ExtensionLoader的对应的getAdaptiveExtension得到。

getAdaptiveExtension这个方法中,先是看是否已经创建,有直接返回,

没有的话

采用同步锁的方式去调用createAdaptiveExtension创建这个转接器对象。

下面是createAdaptiveExtension的调用序列图:

 

就是在createAdaptiveExtension中如果发现扩展点的实现类没有被加载,就会调用getExtensionClasses从三个目录中去
META-INF/dubbo/internal/META-INF/dubbo/META-INF/services/中去加载接口全称命名的配置文件。

配置文件记录的就是实现类以及该类对应的注册名。(当然也可以不提供注册名,dubbo会直接按照通过注解Extension命名,以及直接使用简单类名

加载配置文件方法loadFile中,对于每个扩展点的实现类,他都会查看这个实现类是否被Adaptive标注。当然这个函数中有些原则性的错误检测,比喻一个扩展点只能只有一个Adaptive扩展点。

其实对于一个扩展点,声明为Adaptive的往往是其他实现的集成。

所以一个扩展点在dubbo中为默认存在三种实现,Adaptivewrapped,以及normal实现。主要提供特定功能,主要是normal实现,当然wrapped的可以做响应过滤权限验证等类似aop的切面功能。Adaptive则某种意义上是集成。

 

对于扩展点实现类还支持Activate注解,这样就指明了这个扩展实现被激活的加载条件。

如果存在直接被Adaptive注解的类,这直接使用这个类。如果没有的话就动态创建java文件然后利用java编译器去运行时编译产生这个类。

最后创建完extension实现后,在方法injectExtension中实现依赖注入。

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics