一、JSF介绍
jsf是京东内部自研使用的RPC框架,同dubbo,目前已开源至github—joyrpc。本文从spring的角度去看是如何集成jsf的。
二、Spring在配置文件支持自定义namespace
通过阅读源码画出如下流程图,从中可看出在解析XML时会调用BeanDefinitionParserDelegate来解析自定义的namespace,并根据其指定的NamespaceHandler实例,调用parse方法完成beanDefinition注册。
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通过自定义namespace注册bean
1. jsf-comsumer.xml常规配置
在Sping的bean配置文件中增加jsf的schema信息后,声明两个jsf的bean:注册中心和一个示例消费者。
2. 找到jsf的schema对应的handler
在jsf-1.6.9的依赖中找到jsf集成spring的两个文件:spring.schemas和spring.handlers(可类比参考joyrpc/joyrpc-spring/src/main/resources/META-INF目录,只是schema有些差异)
1)spring.schemas
声明xml中jsf相关配置的语法,可用于让IDE自动提示和校验语法。
http\://jsf.jd.com/schema/jsf/jsf.xsd=META-INF/jsf.xsd
2)spring.handlers
声明xml中jsf命名空间对应的NamespaceHandler实例。
http\://jsf.jd.com/schema/jsf=com.jd.jsf.gd.config.spring.JSFNamespaceHandler
3. JSFNamespaceHandler
JSFNamespaceHandler是spring的NamespaceHanlder的子类,用来处理命名空间下声明的各个标签。在pase方法里调用了init方法中注册的针对不同标签的BeanDefinitionParser(目的是把bean定义解析注册逻辑分离到JSFBeanDefinitionParser,单一职责)。
public class JSFNamespaceHandler extends NamespaceHandlerSupport {
private final Map parsers = new HashMap();
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的子类,用来根据xml中配置的参数,把某个jsf标签解析为一个spring bean。由于类代码较长,取其中关键代码,可参考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中,调用方法:
* beanDefinition.getPropertyValues().addPropertyValue(property, value);
* 忽略此处逻辑
*/
String id = element.getAttribute("id");
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
return beanDefinition;
}
}
由源码可见在创建RootBeanDefinition时设置的类是JSFNamespaceHandler中传入的,此处我们取ConsumerBean进行观察。
5. ConsumerBean
从类图可看出ConsumerBean是一个FactoryBean,在其getObject方法里,调用了JSF的获取Consumer实例的API,并返回实例。
public class ConsumerBean extends ConsumerConfig 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. 小结
spring通过声明自定义namespace对应的NamespaceHandler子类,来处理xml中jsf标签的解析和注册逻辑。且最终注册的beanDefinition是一个FactoryBean,在其getObject里进行具体bean实例的生成。
四、总结
第三方组件要集成进入spring,把类交给spring容器进行声明周期管理,一般都会采取FactoryBean实现。通过FactoryBean可以获取足够的灵活性,第三方组件可以用一个公共的逻辑对组件内的类完成注入Spring的过程。