Spring集成第三方組件-JSF

一、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è)。


image.png
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
image.png

在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é))。

image.png
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

image.png
 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
image.png

從類圖可看出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ò)程。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容