欢迎访问我的个人博客休息的风
对于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服务。销毁时进行引用销毁,服务反暴露。