淘宝HSF通信框架,集成spring 启动流程分析

     刚入职新公司,公司内部通信框架用的是淘宝的HSF,用法大概是在xml配置好一个接口,以及其他等待信息之类的。。注入即可,我就没看明白他这是咋回事。我猜应该是有注册中心,从注册中心拉取消费者实例然后去调用。

配置大概就是这么用的:

<hsf:consumer id="accountCompanyService" interface="com.service.AccountCompanyService"
                  group="${spring.hsf.account.group}" version="${spring.hsf.version}" clientTimeout="5000000"/>

但是具体怎么做的?怎么加载到spring的bean工厂?怎么就知道要调用那个服务?怎么找到对方的IP:PORT的?

且由源码分析一下:

首先这是个spring boot项目:把启动类的代码拷过来记录一下,就明白了、

@MapperScan(basePackages="com.dajia.estatepayment.mapper")
@EnableScheduling
public class ProviderApplicationMain extends ApplicationMainParent {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(ProviderApplicationMain.class);
        springApplication.addListeners( new ApplicationReadyListener() );
        springApplication.addListeners( new ApplicationFailedListener() );
        springApplication.run(args);
    }

然后他继承了一个父类:

@Configuration
@SpringBootApplication
@EnableAutoConfiguration(
    exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, DataSourceAutoConfiguration.class}
)
@ImportResource({"classpath*:spring/spring-*.xml"})
public abstract class ApplicationMainParent {
    public ApplicationMainParent() {
    }
}

差不多意思就是把spring-*.xml 外部配置都加载进来,

以及声明了基础扫描包,排除一些自动配置类,排除的这几个我怀疑是重写了,因此排除spirng默认的自动配置类

因为spring启动所有bean的装填都要经过

 

那我改从哪下手?

如果需要和Spring整合,肯定会重写自己的初始化类,那么去hsf提供的源码中找找有关于spring的东西 , 我发现hsf和spring整合依赖几个bean,在package com.taobao.hsf.app.spring.util包下有三各类

HSFSpringConsumerBean
HSFSpringProviderBean
HSFSpringRegistryBean

看名字也知道了,那么先从consumer,全局搜索一下,看哪里使用到了?

发现有两个地方用到了

1.

public class HSFBeanDefinitionParser implements BeanDefinitionParser {
    private final Class clazz;

    public HSFBeanDefinitionParser(Class clazz) {
        this.clazz = clazz;
    }

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        if (clazz == HSFSpringProviderBean.class) {
            return parseProvider(element, parserContext);
        } else if (clazz == HSFSpringConsumerBean.class) {
            return parseConsumer(element, parserContext);
        }  else if (clazz == HSFSpringRegistryBean.class) {
            return parseRegistry(element, parserContext);
        }else {
            throw new BeanDefinitionValidationException("Unknown class to definition " + clazz.getName());
        }
    }

2.

package com.taobao.hsf.app.spring.schema;

import com.taobao.hsf.app.spring.util.HSFSpringConsumerBean;
import com.taobao.hsf.app.spring.util.HSFSpringProviderBean;
import com.taobao.hsf.app.spring.util.HSFSpringRegistryBean;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 * @author xiaofei.wxf
 * @since 2015-02-03
 */
public class HSFNameSpaceHandler extends NamespaceHandlerSupport {
    public void init() {
    	registerBeanDefinitionParser("registry",new HSFBeanDefinitionParser(HSFSpringRegistryBean.class));
        registerBeanDefinitionParser("provider",new HSFBeanDefinitionParser(HSFSpringProviderBean.class));
        registerBeanDefinitionParser("consumer",new HSFBeanDefinitionParser(HSFSpringConsumerBean.class));
    }
}

好,那就打个断点,启动项目,注意hsf需要淘宝封装的tomcat 启动

 

2.1项目启动,断点走到了public class HSFNameSpaceHandler extends NamespaceHandlerSupport {

这个类继承了NamespaceHandlerSupport 走入这个底层我猜就是解析XML并将其转化为java的一个过程,不是我研究的重点,详细我没看

然后进去三个registerBeanDefinitionParser方法看看

 static final Map<String, FieldDefenition> providerFieldDefMap = new HashMap<String, FieldDefenition>();

    static {
        providerFieldDefMap.put("interface", new FieldDefenition("serviceInterface", true, false));
        providerFieldDefMap.put("timeout", new FieldDefenition("clientTimeout", false, false));
        providerFieldDefMap.put("version", new FieldDefenition("serviceVersion", false, false));
        providerFieldDefMap.put("group", new FieldDefenition("serviceGroup", false, false));
        providerFieldDefMap.put("tenantID", new FieldDefenition("tenantID", false, false));
        providerFieldDefMap.put("envID", new FieldDefenition("envID", false, false));
        providerFieldDefMap.put("ref", new FieldDefenition(true));
        providerFieldDefMap.put("id", new FieldDefenition(true));
    }

他初始了一个map,fieldDef这个对象,他初始了定了provider的所有的属性,以及是否必须填写

一路走,发现到最后,这个方式的实现是这样:

registerBeanDefinitionParser("registry",new HSFBeanDefinitionParser(HSFSpringRegistryBean.class));
实现:
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
   this.parsers.put(elementName, parser);
}

parsers 是一个map。。。

 

让他全走完,这是啥事也没做啊

然后就是provider,consumer,registry 的定义对象放入了parsers中.... 只不过定义对象中多了几个属性map。。。

2.2

然后继续下去就是还读XML》。。

大概是读到一个指定的xml就调用我们自己写的parse方法。

重点来了,重点是来看我们的解析方法的实现

包名:package com.taobao.hsf.app.spring.schema

类名: HSFBeanDefinitionParser implements BeanDefinitionParser

先把解析实现贴上:

  public BeanDefinition parse(Element element, ParserContext parserContext) {
        if (clazz == HSFSpringProviderBean.class) {
            return parseProvider(element, parserContext);
        } else if (clazz == HSFSpringConsumerBean.class) {
            return parseConsumer(element, parserContext);
        }  else if (clazz == HSFSpringRegistryBean.class) {
            return parseRegistry(element, parserContext);
        }else {
            throw new BeanDefinitionValidationException("Unknown class to definition " + clazz.getName());
        }
    }

 

三个if,判断你属于provider,consumer。,还是register。不同的bean返回不同的实现体

我们是consumer,走进去看看

代码先贴上,这一段看起来挺吓人,不过很简单,都是if

public BeanDefinition parseConsumer(Element element, ParserContext parserContext) {
        RootBeanDefinition beanDef = new RootBeanDefinition();
        beanDef.setBeanClass(clazz);
        beanDef.setLazyInit(false);

        //props
        parseAttr(element, beanDef, consumerFieldDefMap);

        String callbackInvokerRef = element.getAttribute("callbackInvoker");
        if (!callbackInvokerRef.isEmpty()) {
            beanDef.getPropertyValues().addPropertyValue("callbackInvoker", new RuntimeBeanReference(callbackInvokerRef));
        }

        List<MethodSpecial> list = new ArrayList<MethodSpecial>();
        List<String> asyncallMethods = new ArrayList<String>();
        NodeList methodSpecials = element.getChildNodes();
        for (int i = 0; i < methodSpecials.getLength(); i++) {
            Node item = methodSpecials.item(i);
            if (item instanceof Element) {
                String localName = item.getLocalName();
                if (localName.equals("asyncallMethods")) {
                    //asyncallMethods
                    NodeList asyncallMethodsList = item.getChildNodes();
                    for (int j = 0; j < asyncallMethodsList.getLength(); j++) {
                        Node asyncallMethod = asyncallMethodsList.item(j);
                        if (!(asyncallMethod instanceof Element)) {
                            continue;
                        }
                        String name = ((Element) asyncallMethod).getAttribute("name");
                        String type = ((Element) asyncallMethod).getAttribute("type");
                        if (name.isEmpty() || type.isEmpty()) {
                            continue;
                        }
                        String listener = ((Element) asyncallMethod).getAttribute("listener");
                        StringBuilder sb = new StringBuilder();
                        sb.append("name:").append(name).append(";type:").append(type);
                        if (type.equals("callback")) {
                            sb.append(";listener:").append(listener);
                        }
                        asyncallMethods.add(sb.toString());
                    }
                } else if (localName.equals("methodSpecials")) {
                    //methodSpecials
                    NodeList methodSpecialList = item.getChildNodes();
                    for (int j = 0; j < methodSpecialList.getLength(); j++) {
                        Node methodSpecial = methodSpecialList.item(j);
                        if (methodSpecial instanceof Element) {
                            String timeout = ((Element) methodSpecial).getAttribute("timeout");
                            String name = ((Element) methodSpecial).getAttribute("name");
                            String retries = ((Element) methodSpecial).getAttribute("retries");
                            MethodSpecial ms = new MethodSpecial();
                            ms.setClientTimeout(Long.valueOf(timeout));
                            ms.setMethodName(name);
                            if (!retries.isEmpty()) {
                                ms.setRetries(Integer.valueOf(retries));
                            }
                            list.add(ms);
                        }
                    }
                }
            }
        }
        if (list.size() > 0) {
            beanDef.getPropertyValues().addPropertyValue("methodSpecials", list.toArray());
        }
        if (asyncallMethods.size() > 0) {
            beanDef.getPropertyValues().addPropertyValue("asyncallMethods", asyncallMethods);
        }

        String id = getId(parserContext, element.getAttribute("id"));
        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDef, id);
        BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
        return beanDef;
    }

 

分析一下这一段代码:

RootBeanDefinition beanDef = new RootBeanDefinition();

1.先创建一个bean定义对象

2.设置是否懒加载,bean的class

3.然后解析bean的属性(最重要)

4.获取回调的执行方法,如果不为空,就设置上

5.创建一个方法属性的list

6.创建一个异步方法的集合

7.获取子节点

8.若子节点不为空,进行子节点的一些操作,,,因为我们这子节点都是空的,因此没看,这方法实现最大的一段跳过了

9.获取bean的id

10.根据ID,定义对象 创建一个BeanDefinitionHolder

11.BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());

注册bean进spring容器

 

返回bean定义对象

结束...

细看3.和11.

3.解析属性:

  private void parseAttr(Element element, RootBeanDefinition beanDef, Map<String, FieldDefenition> fieldDefMap) {
        //props
        NamedNodeMap attrMap = element.getAttributes();
        for (int i = 0; i < attrMap.getLength(); i++) {
            Attr attr = (Attr) attrMap.item(i);
            String name = attr.getName();
            if(null == name || name.isEmpty()) {
                continue;
            }
            FieldDefenition fieldDefenition = fieldDefMap.get(name);
            if(null == fieldDefenition) {
                setProperty(beanDef, element, name, name, false);
            } else {
                if(fieldDefenition.isDiscard()) {
                    continue;
                }
                setProperty(beanDef, element, name, fieldDefenition.getPropName(), fieldDefenition.isRequred());
            }
        }
    }

其实很简单,获取该元素的所i有NameNode

namenode:是你在xml中配置的那些id啊,time啊  之类的属性

如果属性值的NameNode不是空,获取到该属性的值,如果为空,那么从第一步觉得没啥用的那个类的属性定义Map中获取到这个属性定义对象,并且给他赋值

赋值的实现也比较简单:

 private void setProperty(RootBeanDefinition beanDef, Element element, String attrName, String propertyName, boolean required) {
        String attr = element.getAttribute(attrName);
        if (required) {
            checkAttr(attrName, attr);
        }
        if (attr != null && !attr.isEmpty()) {
            beanDef.getPropertyValues().addPropertyValue(propertyName, attr);
        }
    }

获取到这个nameNode的值,检查是否是必须的 如果是必须的那么就检查属性,如果不是必须的那么就直接设置,结束。

 

子节点之类的都是空,异步方法什么的都是空的,如果不是  直接给这个bean定义对象赋值相应属性即可

然后就是创建BeanDefinitionHolder 也比较简单,就是校验一下你传的ID,bean定义对象是否为空。

 

然后重点

11.将bean放入spring的容器中

该方法两个参数,刚刚这个holder对象,还一个就是解析容器中获取BeanDefinitionRegistry

到这里就是spring的工作流程了,而不是我们自己定义的流程了;

注册的源码看一下:

public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		// Register bean definition under primary name.
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

也很简单:

注册主名称

如果有别名注册别名

 

好,看下怎么注册的:”

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

两个参数:

beanName,bean定义对象

看源码,挺长

@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition oldBeanDefinition;

		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(oldBeanDefinition)) {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
	}

1.显示检查参数是否合法

2.Validate this bean definition.

-----进入spring创建bean的流程

3.获取旧的bean定义对象-不存在,如果存在,

   3.1bean是否可以被覆盖?抛异常

   3.2旧的bean和新的bean权重比较,打印日志。。

   3.3旧bean和新bean是否相等。打印日志

   3.4 放入bean的定义map

4.bean是否在创建?

    4.1创建bean

    4.2先把bean定义对象放入这个beanDefinitionMap

  5.后续让spring实例化这些bean去吧......

  第一次写,有点乱,并且也没有下载spring源码到本地。注释都没法写 还在下面一行一行的写。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值