Поговорим о механизме расширения в Spring (2) — NamespaceHandler

задняя часть JVM Spring Dubbo

Предыдущая статьяПоговорим о механизме расширения в Spring (1)болталиApplicationListener,ApplicationContextAware,BeanFactoryAwareтри механизма. Эта статья познакомитNamespaceHandlerрасширенное использование.

Я полагаю, что многие мелкие партнеры знакомы с этими категориями, в основном на основеjavaосуществленныйRPCбудут использоваться фреймворки, такие какDubbo , SOFARpcЖдать. Эта статья начинается с нескольких небольшихdemoНачните, разберитесь с основными понятиями и процессом программирования, а затем проанализируйтеSOFARpcкак используется.

NamespaceHandler

NamespaceHandlerдаSpringПредоставленный обработчик пространства имен. На картинке ниже, кроме случайного входаdemoучаствует вBridgeNameSpaceHandler, Кроме какSpringпредоставлено само собой.

Потому что здесь я только представилbeanиcontextзависимости, так что это только часть. На картинке то, что мы обычно используем, должно бытьAopNamespaceHandler.

Мы используем на основеxmlизspringПри настройке может потребоваться настроить, например,<aop:config />Такая метка, прежде чем настраивать эту метку, обычно нам нужно ввести этоaopВ пространстве имен:

<?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:aop="http://www.springframework.org/schema/aop"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd" />

Узнайте больше об АОППоговорим об АОП: представление и основные понятия, здесь не так много пояснений, дальше будет следующееПроцесс официальной документациинаписать обычайxml, окончательный эффект выглядит следующим образом:

<bridge:application id="bridgeTestApplication"
                    name="bridgeTestApplication"  
                    version="1.0" 
                    organization="bridge.glmapper.com"
                    owner="leishu@glmapper"/>

1. Определите файл xsd

оxsdГрамматические правила файла выходят за рамки этой статьи, и заинтересованные студенты могут составить свои собственные правила.google. Следующий файл очень прост, определениеelementимяapplication, соответствующийbridge:applicationсерединаapplication.attributeЭто соответствующие имена атрибутов на приведенном выше дисплее эффектов.

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:beans="http://www.springframework.org/schema/beans"
            xmlns:tool="http://www.springframework.org/schema/tool"
            xmlns="http://bridge.glmapper.com/schema/bridge"
            targetNamespace="http://bridge.glmapper.com/schema/bridge">

    <xsd:import namespace="http://www.springframework.org/schema/beans"/>

    <xsd:complexType name="applicationType">
        <xsd:attribute name="id" type="xsd:ID"/>
        <xsd:attribute name="name" type="xsd:string" use="required"/>
        <xsd:attribute name="version" type="xsd:string"/>
        <xsd:attribute name="owner" type="xsd:string"/>
        <xsd:attribute name="organization" type="xsd:string"/>
    </xsd:complexType>

    <xsd:element name="application" type="applicationType"/>
</xsd:schema>

2. Напишите обработчик пространства имен

In addition to the schema, we need a NamespaceHandler that will parse all elements of this specific namespace Spring encounters while parsing configuration files.

написано с этимNamespaceHandlerразбирать файл конфигурации.

КонкретноNamespaceHandlerбудет основываться наschemaи имя узла, чтобы найтиBeanDefinitionParser, затем поBeanDefinitionParserВыполните конкретную аналитическую работу.

SpringПредоставляется класс реализации по умолчаниюNamespaceHandlerSupportиAbstractSingleBeanDefinitionParser, проще всего наследовать эти два класса.

Здесь по наследствуNamespaceHandlerSupportЭтот абстрактный класс готов.

public class BridgeNamespaceHandler extends NamespaceHandlerSupport {
    public void init() {
        registerBeanDefinitionParser("application", 
        new ApplicationBeanDefinitionParser());
    }
}

Вот собственно просто парсер прописал, конкретныйBeanDefinitionParserбудетXMLЭлементы сопоставляются с определеннымиbeanиз.

3. Напишите BeanDefinitionParser

Здесь непосредственно через реализациюBeanDefinitionParserТо, как интерфейс определяет нашуBeanDefinitionParserКласс реализации. оAbstractSingleBeanDefinitionParserиспользуется вSPFARpcбудет задействован.

public class ApplicationBeanDefinitionParser implements BeanDefinitionParser {

    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //beanDefinition
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(ApplicationConfig.class);
        beanDefinition.setLazyInit(false);
        //解析id
        String id = element.getAttribute("id");
        beanDefinition.getPropertyValues().add("id", id);
        //解析name
        beanDefinition.getPropertyValues().add("name",
        element.getAttribute("name"));
        //解析version
        beanDefinition.getPropertyValues().add("version",
        element.getAttribute("version"));
        //owner
        beanDefinition.getPropertyValues().add("owner",
        element.getAttribute("owner"));
        //organization
        beanDefinition.getPropertyValues().add("organization",
        element.getAttribute("organization"));
    
        parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
        return beanDefinition;
    }
}

Здесь нам нужно понять, что когда мы начинаем анализировать пользовательские теги, мы передаемBeanDefinitionParserDelegate->parseCustomElementметод, как показано на следующем рисунке:

пройти черезeleэлемент получает текущийnamespaceUri, то есть вxsdпространства имен, определенные в , а затем делегироватьDefaultNamespaceResolverуточнитьhandler(BridgenamspaceHandler), 然后执行parseРазбор.

4. Настройте spring.handlers и spring.schmas

http\://bridge.glmapper.com/schema/bridge=
com.glmapper.extention.namespacehandler.BridgeNamespaceHandler

http\://bridge.glmapper.com/schema/bridge.xsd=META-INF/bridge.xsd

Настройка этого на самом деле сделатьSpringразборxmlКогда мы сможем воспринимать наш пользовательский элемент, нам нужно поместитьNamespaceHandlerиxsdРасположен в файле в каталог Meta-infspring.handlersиspring.schmasв файле. так что вspringНаши пользовательские теги используются в файле конфигурации. следующее:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:bridge="http://bridge.glmapper.com/schema/bridge"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://bridge.glmapper.com/schema/bridge
       http://bridge.glmapper.com/schema/bridge.xsd">
       
    <bridge:application id="bridgeTestApplication"
                    name="bridgeTestApplication"  
                    version="1.0" 
                    organization="bridge.glmapper.com"
                    owner="leishu@glmapper"/>
</beans>

Подтвердить, чтобы получить наш из контейнераbean:

public static void main(String[] args) {
    ApplicationContext applicationContext = new
    ClassPathXmlApplicationContext("classpath:bean.xml");
    
    ApplicationConfig applicationConfig = (ApplicationConfig)
    applicationContext.getBean("bridgeTestApplication");
    
    System.out.println("applicationConfig = "+applicationConfig);
}

Пример вывода:

applicationConfig = ApplicationConfig {
    id=bridgeTestApplication, 
    name='bridgeTestApplication', 
    version='1.0', 
    owner='leishu@glmapper', 
    organization='bridge.glmapper.com'
}

В целом, если мы хотим достичьxmlТеги, просто выполните следующие шаги:

  • 1. Определите файл xsd
  • 2. Напишите обработчик пространства имен
  • 3. Напишите BeanDefinitionParser
  • 4. Настройте spring.handlers и spring.schmas

Анализ использования в SOFARpc

SOFARpcсерединаrpc.xsdфайл интегрирован вsofaboot.xsdВ файле подробно видно:sofa-boot

xsdФайл не выложен здесь, он немного длинный

spring.handlers и spring.schmas

Первый взглядspring.handlersиspring.schmasКонфигурация:

http\://sofastack.io/schema/sofaboot=
com.alipay.sofa.infra.config.spring.namespace.handler.SofaBootNamespaceHandler

http\://sofastack.io/schema/sofaboot.xsd=
META-INF/com/alipay/sofa/infra/config/spring/namespace/schema/sofaboot.xsd

http\://sofastack.io/schema/rpc.xsd=
META-INF/com/alipay/sofa/infra/config/spring/namespace/schema/rpc.xsd

отspring.handlersоказатьсяNamespaceHandler : SofaBootNamespaceHandler.

SofaBootNamespaceHandler

Исходный код выглядит следующим образом.Здесь видно, что он не такой, как мы писали выше, будетBeanDefinitionParser. На самом деле здесь очень продумано.spiспособ загрузки конкретногоBeanDefinitionParser.

public class SofaBootNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        ServiceLoader<SofaBootTagNameSupport> serviceLoaderSofaBoot =
        ServiceLoader.load(SofaBootTagNameSupport.class);
        //SOFABoot
        for (SofaBootTagNameSupport tagNameSupport : serviceLoaderSofaBoot) {
            this.registerTagParser(tagNameSupport);
        }
    }

    private void registerTagParser(SofaBootTagNameSupport tagNameSupport) {
        if (!(tagNameSupport instanceof BeanDefinitionParser)) {
            // log
            return;
        }
        String tagName = tagNameSupport.supportTagName();
        registerBeanDefinitionParser(tagName, (BeanDefinitionParser)
        tagNameSupport);
    }
}

Здесь видно, что естьReferenceDefinitionParserиServiceDefinitionParserДва класса синтаксического анализа, соответствующие ссылке на службу и представлению службы соответственно.

Ниже сReferenceDefinitionParserНапример, сначала посмотрите на его диаграмму классов:

Аналитическая работа находится вAbstractContractDefinitionParserсделано на уроке,ReferenceDefinitionParserЯ только что выполнил специальную обработку [jvm-first, jvm service].

резюме

Эта статья прошлаNamespaceHandlerУзнали, как писать наши пользовательские теги xml, изNamespaceHandlerУгол обзора можно хорошо понятьRPCОсновная часть фреймворка основана наxmlСпособы обращения к сервису и представления идей реализации. Кроме того, анализируяSOFARpc, также понимать, что в реальных инженерных компонентах дляNamespaceHandlerрасширенное использование.

Код для этой статьи:glmapper-spring-extention