一、JSF介紹
jsf是京東內(nèi)部自研使用的RPC框架,同dubbo,目前已開(kāi)源至github—joyrpc。本文從spring的角度去看是如何集成jsf的。
二、Spring在配置文件支持自定義namespace
通過(guò)閱讀源碼畫(huà)出如下流程圖,從中可看出在解析XML時(shí)會(huì)調(diào)用BeanDefinitionParserDelegate來(lái)解析自定義的namespace,并根據(jù)其指定的NamespaceHandler實(shí)例,調(diào)用parse方法完成beanDefinition注冊(cè)。

public class BeanDefinitionParserDelegate {
/**
* Parse a custom element (outside of the default namespace).
* @param ele the element to parse
* @param containingBd the containing bean definition (if any)
* @return the resulting bean definition
*/
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
三、JSF通過(guò)自定義namespace注冊(cè)bean
1. jsf-comsumer.xml常規(guī)配置
在Sping的bean配置文件中增加jsf的schema信息后,聲明兩個(gè)jsf的bean:注冊(cè)中心和一個(gè)示例消費(fèi)者。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jsf="http://jsf.jd.com/schema/jsf"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://jsf.jd.com/schema/jsf http://jsf.jd.com/schema/jsf/jsf.xsd">
<!-- 注冊(cè)中心 -->
<jsf:registry id="jsfRegistry" protocol="jsfRegistry" index="i.jsf.jd.com" />
<!-- 服務(wù)調(diào)用者配置-->
<jsf:consumer id="demoConsumer" interface="pers.jsf.demo.IDemoConsumer" protocol="jsf" alias="demo" />
</beans>
2. 找到j(luò)sf的schema對(duì)應(yīng)的handler

在jsf-1.6.9的依賴中找到j(luò)sf集成spring的兩個(gè)文件:spring.schemas和spring.handlers(可類比參考joyrpc/joyrpc-spring/src/main/resources/META-INF目錄,只是schema有些差異)
1)spring.schemas
聲明xml中jsf相關(guān)配置的語(yǔ)法,可用于讓IDE自動(dòng)提示和校驗(yàn)語(yǔ)法。
http\://jsf.jd.com/schema/jsf/jsf.xsd=META-INF/jsf.xsd
2)spring.handlers
聲明xml中jsf命名空間對(duì)應(yīng)的NamespaceHandler實(shí)例。
http\://jsf.jd.com/schema/jsf=com.jd.jsf.gd.config.spring.JSFNamespaceHandler
3. JSFNamespaceHandler
JSFNamespaceHandler是spring的NamespaceHanlder的子類,用來(lái)處理命名空間下聲明的各個(gè)標(biāo)簽。在pase方法里調(diào)用了init方法中注冊(cè)的針對(duì)不同標(biāo)簽的BeanDefinitionParser(目的是把bean定義解析注冊(cè)邏輯分離到JSFBeanDefinitionParser,單一職責(zé))。

public class JSFNamespaceHandler extends NamespaceHandlerSupport {
private final Map<String, BeanDefinitionParser> parsers = new HashMap<String, BeanDefinitionParser>();
public void init() {
this.registerBeanDefinitionParser("provider", new JSFBeanDefinitionParser(ProviderBean.class, true));
this.registerBeanDefinitionParser("consumer", new JSFBeanDefinitionParser(ConsumerBean.class, true));
this.registerBeanDefinitionParser("consumerGroup", new JSFBeanDefinitionParser(ConsumerGroupBean.class, true));
this.registerBeanDefinitionParser("server", new JSFBeanDefinitionParser(ServerBean.class, true));
this.registerBeanDefinitionParser("registry", new JSFBeanDefinitionParser(RegistryConfig.class, true));
this.registerBeanDefinitionParser("annotation", new JSFBeanDefinitionParser(AnnotationBean.class, true));
this.registerBeanDefinitionParser("parameter", new JSFParameterDefinitionParser(ParameterConfig.class));
this.registerBeanDefinitionParser("filter", new JSFBeanDefinitionParser(FilterBean.class, true));
this.registerBeanDefinitionParser("connStrategy", new JSFBeanDefinitionParser(ConnStrategyBean.class, true));
}
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return findParserForElement(element, parserContext).parse(element, parserContext);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element);
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
}
4. JSFBeanDefinitionParser
JSFBeanDefinitionParser是spring的BeanDefinitionParser的子類,用來(lái)根據(jù)xml中配置的參數(shù),把某個(gè)jsf標(biāo)簽解析為一個(gè)spring bean。由于類代碼較長(zhǎng),取其中關(guān)鍵代碼,可參考joyrpc-AbstractBeanDefinitionParser.java

public class JSFBeanDefinitionParser implements BeanDefinitionParser {
private static final Logger logger = LoggerFactory.getLogger(JSFBeanDefinitionParser.class);
private final Class<?> beanClass;
private final boolean required;
public JSFBeanDefinitionParser(Class<?> beanClass, boolean required) {
this.beanClass = beanClass;
this.required = required;
}
public BeanDefinition parse(Element element, ParserContext parserContext) {
return this.parse(element, parserContext, this.beanClass, this.required);
}
private BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean requireId) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
/**
* 從element取屬性填充到beanDefinition中,調(diào)用方法:
* beanDefinition.getPropertyValues().addPropertyValue(property, value);
* 忽略此處邏輯
*/
String id = element.getAttribute("id");
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
return beanDefinition;
}
}
由源碼可見(jiàn)在創(chuàng)建RootBeanDefinition時(shí)設(shè)置的類是JSFNamespaceHandler中傳入的,此處我們?nèi)onsumerBean進(jìn)行觀察。
5. ConsumerBean

從類圖可看出ConsumerBean是一個(gè)FactoryBean,在其getObject方法里,調(diào)用了JSF的獲取Consumer實(shí)例的API,并返回實(shí)例。
public class ConsumerBean<T> extends ConsumerConfig<T> implements InitializingBean, FactoryBean, ApplicationContextAware, DisposableBean, BeanNameAware {
private static final long serialVersionUID = 6835324481364430812L;
private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerBean.class);
private ApplicationContext applicationContext;
private transient String beanName;
private transient T object;
private transient Class objectType;
protected ConsumerBean() {
}
public T getObject() throws Exception {
this.object = CommonUtils.isUnitTestMode() ? null : this.refer();
return this.object;
}
...
}
6. 小結(jié)
spring通過(guò)聲明自定義namespace對(duì)應(yīng)的NamespaceHandler子類,來(lái)處理xml中jsf標(biāo)簽的解析和注冊(cè)邏輯。且最終注冊(cè)的beanDefinition是一個(gè)FactoryBean,在其getObject里進(jìn)行具體bean實(shí)例的生成。
四、總結(jié)
第三方組件要集成進(jìn)入spring,把類交給spring容器進(jìn)行聲明周期管理,一般都會(huì)采取FactoryBean實(shí)現(xiàn)。通過(guò)FactoryBean可以獲取足夠的靈活性,第三方組件可以用一個(gè)公共的邏輯對(duì)組件內(nèi)的類完成注入Spring的過(guò)程。