刚入职新公司,公司内部通信框架用的是淘宝的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源码到本地。注释都没法写 还在下面一行一行的写。