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

来源:互联网 发布:手机淘宝6.3.2 旧版本 编辑:程序博客网 时间:2024/06/05 06:27

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

对于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的一个类图情况。(图片有点小,请点击新的页签进行查看

核心类就是最底层的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服务。销毁时进行引用销毁,服务反暴露。



阅读全文
0 0
原创粉丝点击