【Dubbo】Spring融合

2018-06-14  本文已影响0人  半个橙子

Dubbo和Spring结合使用了大量的自定义标签。dubbo正是通过这些标签和Spring融合在一起,实现了服务暴露、服务引用、协议声明、注册中心配置等功能。

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <!-- provider's application name, used for tracing dependency relationship -->
    <dubbo:application name="demo-provider"/>
    <!--<dubbo:monitor protocol="registry"></dubbo:monitor>-->
    <!-- use multicast registry center to export service -->
    <!--<dubbo:registry address="multicast://224.5.6.7:1234"/>-->
    <!--订阅并注册在zk上-->
    <dubbo:registry id="vmZk" protocol="zookeeper" address="192.168.0.100:2181" check="false" />

    <!-- use dubbo protocol to export service on port 20880 -->
    <!--配置线程模式-->
    <dubbo:protocol id="dubbo1" name="dubbo" port="20881" dispatcher="execution" threadpool="cached" threads="5"/>
    <dubbo:protocol id="dubbo2" name="dubbo" port="20882" dispatcher="execution" threadpool="cached" threads="5"/>
    <!-- service implementation, as same as regular local bean -->
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/>

    <!-- declare the service interface to be exported -->
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" protocol="dubbo1" registry="vmZk"/>

</beans>

dubbo的命名空间为xmlns:dubbo="http://code.alibabatech.com/schema/dubbo",点击这个链接就可以找到dubbo.xsd,同目录下还有spring.handlers、spring.schemas。

spring.handlers
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

通过spring.handlers的内容可以发现dubbo的命名空间处理类为DubboNamespaceHandler,在DubboNamespaceHandler中注册的了很多解析器,它们都实现了BeanDefinitionParser接口。当spring容器解析到对应的标签时就会回调BeanDefinitionParser.parse交给用户处理。
spring自定义标签

package com.alibaba.dubbo.config.spring.schema;
/**
 * DubboNamespaceHandler
 *
 * @export
 */
public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }
}

<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />
可以配置的属性

    <xsd:element name="service" type="serviceType">
        <xsd:annotation> 
            <xsd:documentation><![CDATA[ Export service config ]]></xsd:documentation> 
        </xsd:annotation>
    </xsd:element>
<xsd:complexType name="serviceType">
        <xsd:complexContent>
            <xsd:extension base="abstractServiceType">
                <xsd:choice minOccurs="0" maxOccurs="unbounded">
                    <xsd:element ref="method" minOccurs="0" maxOccurs="unbounded" />
                    <xsd:element ref="parameter" minOccurs="0" maxOccurs="unbounded" />
                    <xsd:element ref="beans:property" minOccurs="0" maxOccurs="unbounded" />
                </xsd:choice>
                <xsd:attribute name="interface" type="xsd:token" use="required">
                    <xsd:annotation>
                        <xsd:documentation><![CDATA[ Defines the interface to advertise for this service in the service registry. ]]></xsd:documentation>
                        <xsd:appinfo>
                            <tool:annotation>
                                <tool:expected-type type="java.lang.Class"/>
                            </tool:annotation>
                        </xsd:appinfo>
                    </xsd:annotation>
                </xsd:attribute>
                <xsd:attribute name="ref" type="xsd:string" use="optional">
                    <xsd:annotation>
                        <xsd:documentation><![CDATA[ The service implementation instance bean id. ]]></xsd:documentation>
                    </xsd:annotation>
                </xsd:attribute>

启动方式一

直接启动spring容器,读取dubbo的配置

public class Provider {
    public static void main(String[] args) throws Exception {
        //Prevent to get IPV6 address,this way only work in debug mode
        //But you can pass use -Djava.net.preferIPv4Stack=true,then it work well whether in debug mode or not
        System.setProperty("java.net.preferIPv4Stack", "true");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
        context.start();
        System.in.read(); // press any key to exit
    }
}

启动方式二

dubbo提供了容器类读取配置文件来启动spring容器,然后在spring容器启动后spring自动加载applicationContext.xml,并解析dubbo标签生成dubbo各种需要的类,并在服务关闭时候关闭spring 容器

dubbo.container=log4j,spring
package com.alibaba.dubbo.demo.provider;
import com.alibaba.dubbo.container.Main;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Provider {
    public static void main(String[] args) throws Exception {
        Main.main(args);
    }
}
  public static final String CONTAINER_KEY = "dubbo.container";
 public static void main(String[] args) {
        try {
            if (args == null || args.length == 0) {
            //读取配置文件
                String config = ConfigUtils.getProperty(CONTAINER_KEY, loader.getDefaultExtensionName());
                args = Constants.COMMA_SPLIT_PATTERN.split(config);
            }
            final List<Container> containers = new ArrayList<Container>();
            for (int i = 0; i < args.length; i ++) {
                //获取扩展点实例log4j,spring-SpringContainer.class
                containers.add(loader.getExtension(args[i]));
            }
            logger.info("Use container type(" + Arrays.toString(args) + ") to run dubbo serivce.");
            
            if ("true".equals(System.getProperty(SHUTDOWN_HOOK_KEY))) {
                Runtime.getRuntime().addShutdownHook(new Thread() {
                    public void run() {
                        for (Container container : containers) {
                            try {
                                    //停止容器
                                container.stop();
                                logger.info("Dubbo " + container.getClass().getSimpleName() + " stopped!");
                            } catch (Throwable t) {
                                logger.error(t.getMessage(), t);
                            }
                            synchronized (Main.class) {
                                    //停止主线程
                                running = false;
                                Main.class.notify();
                            }
                        }
                    }
                });
            }
            
            for (Container container : containers) {
              //启动容器
                container.start();
                logger.info("Dubbo " + container.getClass().getSimpleName() + " started!");
            }
            System.out.println(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]").format(new Date()) + " Dubbo service server started!");
        } catch (RuntimeException e) {
            e.printStackTrace();
            logger.error(e.getMessage(), e);
            System.exit(1);
        }
        synchronized (Main.class) {
            while (running) {
                try {
                    //主线程等待,程序进程不会退出
                    Main.class.wait();
                } catch (Throwable e) {
                }
            }
        }
    }
    ......
}
public class SpringContainer implements Container {
    public static final String SPRING_CONFIG = "dubbo.spring.config";
    public static final String DEFAULT_SPRING_CONFIG = "classpath*:META-INF/spring/*.xml";
    private static final Logger logger = LoggerFactory.getLogger(SpringContainer.class);
    static ClassPathXmlApplicationContext context;
    public static ClassPathXmlApplicationContext getContext() {
        return context;
    }
    public void start() {
        String configPath = ConfigUtils.getProperty(SPRING_CONFIG);
        if (configPath == null || configPath.length() == 0) {
            configPath = DEFAULT_SPRING_CONFIG;
        }
        context = new ClassPathXmlApplicationContext(configPath.split("[,\\s]+"));
        context.start();
    }
    public void stop() {
        try {
            if (context != null) {
                context.stop();
                context.close();
                context = null;
            }
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读