dubbo 源码学习笔记 (四) —— 配置模块

欢迎访问我的个人博客休息的风

对于dubbo的配置,采用的是spring的一个解析配置文件的机制。与spring是连接的,也是解析成BeanDefinition,让spring管理生成对象放入spring容器中。(具体从spring加载xml转换为beanDefinition的过程可以去看我的另一篇博客spring 源码学习笔记(一)—— spring ioc 之加载XML转换为BeanDefinition)dubbo对于配置的xml的解析在DubboNamespaceHandler这个类里定义,具体的解析过程在DubboBeanDefinitionParser这个类里执行。DubboBeanDefinitionParser.parse这个方法里,会对所有的配置文件的属性进行解析,将解析的结果存放到BeanDefinition对象中。由于这个parse方法对所有的配置,如<dubbo:application  />、<dubbo:service />等都在parse方法里面解析,没有一 一区分。所以这个方法有将近200行的代码。所有的配置文件都与ApplicationConfig、ServiceConfig等数据结构对应。也就是说,这个转换过程为XML文件->BeanDefinition->XXXConfig对象。

具体的解析过程如下:

private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
    RootBeanDefinition beanDefinition = new RootBeanDefinition();
    beanDefinition.setBeanClass(beanClass);
    beanDefinition.setLazyInit(false);
    //解析id的过程
    String id = element.getAttribute("id");
    if ((id == null || id.length() == 0) && required) {
        String generatedBeanName = element.getAttribute("name");
        if (generatedBeanName == null || generatedBeanName.length() == 0) {
            if (ProtocolConfig.class.equals(beanClass)) {
                generatedBeanName = "dubbo";
            } else {
                generatedBeanName = element.getAttribute("interface");
            }
        }
       //省略代码。。。
    }
    if (id != null && id.length() > 0) {
        if (parserContext.getRegistry().containsBeanDefinition(id)) {
            throw new IllegalStateException("Duplicate spring bean id " + id);
        }
        parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
        beanDefinition.getPropertyValues().addPropertyValue("id", id);
    }
    //对<dubbo:protocol>的处理
    if (ProtocolConfig.class.equals(beanClass)) {
        for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
            BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
            PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
            if (property != null) {
                Object value = property.getValue();
                if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
                    definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
                }
            }
        }
        //对<dubbo:service>的处理
    } else if (ServiceBean.class.equals(beanClass)) {
        String className = element.getAttribute("class");
        if (className != null && className.length() > 0) {
            RootBeanDefinition classDefinition = new RootBeanDefinition();
            classDefinition.setBeanClass(ReflectUtils.forName(className));
            classDefinition.setLazyInit(false);
            parseProperties(element.getChildNodes(), classDefinition);
            beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
        }
        //对<dubbo:provider>的处理
    } else if (ProviderConfig.class.equals(beanClass)) {
        parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
    } else if (ConsumerConfig.class.equals(beanClass)) {//对<dubbo:consumer>的处理
        parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
    }
    Set<String> props = new HashSet<String>();
    ManagedMap parameters = null;
    //对set值的解析过程
    for (Method setter : beanClass.getMethods()) {
        String name = setter.getName();
        if (name.length() > 3 && name.startsWith("set")
                && Modifier.isPublic(setter.getModifiers())
                && setter.getParameterTypes().length == 1) {
            //省略一大段代码
            //对每个属性值的解析过程
            
        }
    }
    //解析parameters的过程
    NamedNodeMap attributes = element.getAttributes();
    int len = attributes.getLength();
    for (int i = 0; i < len; i++) {
        //省略代码。。。
    }
    if (parameters != null) {
        beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
    }
    return beanDefinition;
}
也不难理解,就是分别对xml里面的配置信息转换到BeanDefinition里面一对一对的属性。每个配置文件分别对每个配置的属性值进行解析,最后都形成一个BeanDefinition。之后再由spring去生成对应的XXXConfig对象,放到spring容器中。

再来看下整个XXXConfig的一个类图情况。(图片有点小,请点击新的页签进行查看

dubbo 源码学习笔记 (四) —— 配置模块

核心类就是最底层的ServiceBean、ReferenceBean、AnnotationBean这三个类。接下来我们分别做个介绍。


ServiceBean实现了ApplicationContextAware、BeanNameAware接口,在springioc的过程中,会对applicationContext、beanName调用相应的set方法进行依赖注入赋值。实现InitializingBean、DisposableBean,就是在spring容器初始化对象和销毁对象时,做一些自定义的操作。

@SuppressWarnings({"unchecked", "deprecation"})
public void afterPropertiesSet() throws Exception {
    //设置配置属性的值
    //省略代码。。。
    if (!isDelay()) {
        //dubbo服务暴露的入口
        export();
    }
}

而实现了ApplicationListener,则是接当前类做为一个事件监听器,在spring发布一个事件时,能做相应的处理。在setApplicationContext里有把这个监听器注册到spring中的操作。

public void onApplicationEvent(ApplicationEvent event) {
    if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
        if (isDelay() && !isExported() && !isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            //dubbo服务暴露的入口
            export();
        }
    }
}

public void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
    SpringExtensionFactory.addApplicationContext(applicationContext);
    if (applicationContext != null) {
        SPRING_CONTEXT = applicationContext;
        try {
            //在这里注册监听到applicationContext中
            Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); // 兼容Spring2.0.1
            method.invoke(applicationContext, new Object[]{this});
            supportedApplicationListener = true;
        } catch (Throwable t) {
            if (applicationContext instanceof AbstractApplicationContext) {
                try {
                    //在这里注册监听到applicationContext中
                    Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); // 兼容Spring2.0.1
                    if (!method.isAccessible()) {
                        method.setAccessible(true);
                    }
                    method.invoke(applicationContext, new Object[]{this});
                    supportedApplicationListener = true;
                } catch (Throwable t2) {
                }
            }
        }
    }
}

这样,ServiceBean就具体自定义初始化、销毁、设置applicationContext、beanName值和ApplicationListener事件监听的功能。


ReferenceBean实现了ApplicationContextAware, InitializingBean, DisposableBean这三个接口,也就是有设置applicationContext值、自定义初始化、销毁的功能。

public void afterPropertiesSet() throws Exception {
   //省略很多代码
    //相关属性值的设置
    Boolean b = isInit();
    if (b == null && getConsumer() != null) {
        b = getConsumer().isInit();
    }
    if (b != null && b.booleanValue()) {
        //dubbo引用服务的入口
        getObject();
    }
}

其中,实现FactoryBean,因实例化该bean过程比较复杂,通过实现该接口定制实例化bean的逻辑。也就是,这里的getObject方法,是dubbo方法引用的入口。

public Object getObject() throws Exception {
    //dubbo引用服务的入口,调用ReferenceConfig的get()方法
    return get();
}

AnnotationBean实现了DisposableBean接口,在销毁对象时,对服务进行反暴露,对引用进行销毁;实现了ApplicationContextAware,能设置applicationContext的值;实现了BeanFactoryPostProcessor接口,可以修改bean的配置信息;

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
        throws BeansException {
    if (annotationPackage == null || annotationPackage.length() == 0) {
        return;
    }
    if (beanFactory instanceof BeanDefinitionRegistry) {
        try {
            // init scanner
            Class<?> scannerClass = ReflectUtils.forName("org.springframework.context.annotation.ClassPathBeanDefinitionScanner");
            Object scanner = scannerClass.getConstructor(new Class<?>[]{BeanDefinitionRegistry.class, boolean.class}).newInstance(new Object[]{(BeanDefinitionRegistry) beanFactory, true});
            // add filter
            Class<?> filterClass = ReflectUtils.forName("org.springframework.core.type.filter.AnnotationTypeFilter");
            Object filter = filterClass.getConstructor(Class.class).newInstance(Service.class);
            Method addIncludeFilter = scannerClass.getMethod("addIncludeFilter", ReflectUtils.forName("org.springframework.core.type.filter.TypeFilter"));
            addIncludeFilter.invoke(scanner, filter);
            // scan packages
            String[] packages = Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);
            Method scan = scannerClass.getMethod("scan", new Class<?>[]{String[].class});
            scan.invoke(scanner, new Object[]{packages});
        } catch (Throwable e) {
            // spring 2.0
        }
    }
}

而实现了BeanPostProcessor接口,能在初始化bean时增加前后置操作。前置操作引用dubbo的服务,后置操作暴露dubbo服务

public Object postProcessBeforeInitialization(Object bean, String beanName)
        throws BeansException {
    if (!isMatchPackage(bean)) {
        return bean;
    }
    //省略代码。。。
                Reference reference = method.getAnnotation(Reference.class);
                if (reference != null) {
                    //dubbo引用服务入口,处理在set方法上面@Reference的注解
                    Object value = refer(reference, method.getParameterTypes()[0]);
                    if (value != null) {
                        method.invoke(bean, new Object[]{value});
                    }
                }
            } //省略代码。。。
        }
    }
    Field[] fields = bean.getClass().getDeclaredFields();
    for (Field field : fields) {
        try {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            Reference reference = field.getAnnotation(Reference.class);
            if (reference != null) {
                //dubbo引用服务入口,处理类成员变量上的@Reference注解
                Object value = refer(reference, field.getType());
                if (value != null) {
                    field.set(bean, value);
                }
            }
        } //省略代码。。。
    return bean;
}

public Object postProcessAfterInitialization(Object bean, String beanName)
        throws BeansException {
    if (!isMatchPackage(bean)) {
        return bean;
    }
    Service service = bean.getClass().getAnnotation(Service.class);
    //省略代码。。。。
    //相关配置信息的处理
        serviceConfigs.add(serviceConfig);
        //暴露dubbo服务入口
        serviceConfig.export();
    }
    return bean;
}

这三个bean由spring容器接管,也是dubbo与spring结合的交接处。在ServiceBean初始化(afterPropertiesSet)会调用export方法进行dubbo服务暴露;在ReferenceBean.getObject时,会调用init方法进行dubbo服务引用。AnnotationBean与注解配置相对应,在初始化的前后置操作,前置引用dubbo服务,后置暴露dubbo服务。销毁时进行引用销毁,服务反暴露。