2 快速入门实战指南

Dubbo 2.7 快速入门实战指南

学习目标

学完本章后,你能够:

  • 独立搭建第一个Dubbo直连式调用项目(Provider + Consumer)
  • 配置ZooKeeper注册中心并实现服务的自动注册与发现
  • 将Dubbo服务集成到Spring MVC Web工程中
  • 部署和使用Dubbo Admin管理控制台进行服务治理
  • 理解Main类启动与Spring容器启动的区别及适用场景

1. 第一个Dubbo应用------直连模式

直连模式(Point-to-Point)是学习Dubbo最简方式:Consumer通过硬编码的URL直接连接Provider,不依赖任何注册中心。虽然生产环境不会这样使用,但它是理解Dubbo工作原理的最佳起点。

1.1 项目结构与模块划分

bash 复制代码
dubbo-quickstart/
├── dubbo-api/                    # 公共接口模块
│   ├── pom.xml
│   └── src/main/java/
│       └── com/example/dubbo/api/
│           └── GreetingService.java
├── dubbo-provider/               # 服务提供者模块
│   ├── pom.xml
│   └── src/main/
│       ├── java/com/example/dubbo/provider/
│       │   ├── GreetingServiceImpl.java
│       │   └── ProviderApplication.java
│       └── resources/
│           └── spring-provider.xml
└── dubbo-consumer/               # 服务消费者模块
    ├── pom.xml
    └── src/main/
        ├── java/com/example/dubbo/consumer/
        │   └── ConsumerApplication.java
        └── resources/
            └── spring-consumer.xml

1.2 公共API模块

java 复制代码
package com.example.dubbo.api;

/**
 * 远程服务接口定义
 * 
 * 设计原则:
 * 1. 接口定义在独立的模块中,Provider和Consumer共同依赖
 * 2. 接口即契约------只要接口不变,双方可以独立演化
 * 3. 方法参数和返回值必须实现Serializable接口(跨JVM传输需要序列化)
 */
public interface GreetingService {
    
    /**
     * 发送问候消息
     * @param name 用户名
     * @return 问候语
     */
    String sayHello(String name);
    
    /**
     * 获取服务版本信息
     * @return 版本标识
     */
    String getVersion();
}
xml 复制代码
<!-- dubbo-api/pom.xml -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example.dubbo</groupId>
    <artifactId>dubbo-api</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project>

1.3 服务提供者实现

java 复制代码
package com.example.dubbo.provider;

import com.example.dubbo.api.GreetingService;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 远程服务接口的具体实现
 * 
 * 注意:这是一个普通的Java类,不需要任何Dubbo特有的注解或继承
 * 所有Dubbo相关的配置都在XML配置文件中完成
 */
public class GreetingServiceImpl implements GreetingService {
    
    /** 当前提供者节点的标识 */
    private final String nodeId;
    
    public GreetingServiceImpl(String nodeId) {
        this.nodeId = nodeId;
    }
    
    @Override
    public String sayHello(String name) {
        String timestamp = LocalDateTime.now()
            .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        
        // 在控制台打印日志,便于观察调用情况
        System.out.printf("[%s] 节点 %s 收到请求,参数 name=%s%n", 
            timestamp, nodeId, name);
        
        // 模拟业务处理耗时
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        return String.format("你好 %s!由节点[%s]于 %s 响应", 
            name, nodeId, timestamp);
    }
    
    @Override
    public String getVersion() {
        return "Dubbo 2.7.0 Provider - Node " + nodeId;
    }
}

Spring配置文件------服务暴露核心配置

xml 复制代码
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- ========== 1. 应用标识 ========== -->
    <!-- 每个Dubbo应用必须有唯一的名称,用于在注册中心中标识自己 -->
    <dubbo:application name="dubbo-quickstart-provider"/>

    <!-- ========== 2. 注册中心配置(直连模式设置为N/A) ========== -->
    <!-- N/A 表示不使用任何注册中心,完全依靠URL直连 -->
    <dubbo:registry address="N/A"/>

    <!-- ========== 3. 服务协议与端口 ========== -->
    <!-- 指定使用dubbo协议,监听20880端口 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!-- ========== 4. 服务实现Bean ========== -->
    <!-- 这是普通的Spring Bean,由Spring容器管理其生命周期 -->
    <bean id="greetingService" class="com.example.dubbo.provider.GreetingServiceImpl">
        <constructor-arg value="Node-01"/>
    </bean>

    <!-- ========== 5. 服务暴露(最关键的配置) ========== -->
    <!-- interface: 暴露的服务接口全限定名 -->
    <!-- ref: 引用的Spring Bean,即服务实现类 -->
    <dubbo:service interface="com.example.dubbo.api.GreetingService" 
                   ref="greetingService"/>
</beans>

Provider启动类

java 复制代码
package com.example.dubbo.provider;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;

/**
 * 服务提供者入口------基于Spring容器启动
 * 
 * 执行流程:
 * 1. 加载Spring配置文件,初始化IoC容器
 * 2. 创建GreetingServiceImpl实例
 * 3. Dubbo检测到<dubbo:service>标签,自动暴露服务
 * 4. 开启Netty端口监听(20880),等待消费者连接
 */
public class ProviderApplication {
    
    public static void main(String[] args) throws IOException {
        System.out.println("========== Dubbo Provider 启动中 ==========");
        
        // 1. 创建Spring容器并加载Dubbo配置
        ClassPathXmlApplicationContext context = 
            new ClassPathXmlApplicationContext("spring-provider.xml");
        
        // 2. 启动Spring容器(触发Dubbo服务暴露)
        context.start();
        
        System.out.println("========== Dubbo Provider 启动完成 ==========");
        System.out.println("服务已暴露在: dubbo://localhost:20880");
        System.out.println("按任意键停止服务...");
        
        // 3. 阻塞主线程,保持服务持续运行
        System.in.read();
        
        // 4. 优雅关闭
        context.close();
        System.out.println("========== Dubbo Provider 已停止 ==========");
    }
}

1.4 服务消费者实现

Spring配置文件

xml 复制代码
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 应用标识 -->
    <dubbo:application name="dubbo-quickstart-consumer"/>

    <!-- 不使用注册中心 -->
    <dubbo:registry address="N/A"/>

    <!-- ========== 服务引用------直连模式的核心 ========== -->
    <!-- id: 在Spring容器中的Bean名称,通过它获取代理对象 -->
    <!-- interface: 要调用的远程服务接口 -->
    <!-- url: 直连地址,格式为 dubbo://主机:端口 -->
    <dubbo:reference id="greetingService" 
                     interface="com.example.dubbo.api.GreetingService"
                     url="dubbo://localhost:20880"/>
</beans>

Consumer启动类

java 复制代码
package com.example.dubbo.consumer;

import com.example.dubbo.api.GreetingService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 服务消费者入口
 * 
 * 执行流程:
 * 1. 加载Spring配置,初始化IoC容器
 * 2. Dubbo根据<dubbo:reference>配置创建远程代理对象
 * 3. 从Spring容器获取代理Bean
 * 4. 调用代理方法时,Dubbo自动完成网络通信、序列化等底层操作
 */
public class ConsumerApplication {
    
    public static void main(String[] args) {
        // 1. 初始化Spring容器
        ApplicationContext context = 
            new ClassPathXmlApplicationContext("spring-consumer.xml");
        
        // 2. 获取远程服务代理对象
        // 注意:这里获取到的是Dubbo生成的动态代理,而非真正的实现类
        GreetingService service = (GreetingService) context.getBean("greetingService");
        
        // 3. 发起远程调用
        // 对开发者来说,完全透明------就像调用本地方法一样
        System.out.println("===== 发起第一次远程调用 =====");
        String result1 = service.sayHello("张三");
        System.out.println("响应结果: " + result1);
        
        System.out.println("\n===== 发起第二次远程调用 =====");
        String result2 = service.sayHello("李四");
        System.out.println("响应结果: " + result2);
        
        System.out.println("\n===== 获取服务版本 =====");
        String version = service.getVersion();
        System.out.println("版本信息: " + version);
        
        // 4. 应用退出
        ((ClassPathXmlApplicationContext) context).close();
    }
}

1.5 Dubbo Main类启动方式

除了手动创建Spring容器,Dubbo还提供了更轻量的Main类启动方式:

java 复制代码
package com.example.dubbo.provider;

import org.apache.dubbo.container.Main;

/**
 * 使用Dubbo Main类启动------更简洁的方式
 * 
 * 要求:
 * 1. Spring配置文件必须放在 classpath:META-INF/spring/ 目录下
 * 2. 文件名随意,建议使用 spring-*.xml 模式
 * 3. 无需手动创建Spring容器,Main类自动加载
 * 
 * 适用场景:
 * - 纯Java应用(非Web环境)的服务提供者
 * - 测试和演示项目
 * - 不需要完整Spring容器功能的轻量级部署
 */
public class ProviderMainApplication {
    
    public static void main(String[] args) {
        // 一行代码启动Dubbo服务
        // Main内部会自动:
        // 1. 扫描 META-INF/spring/ 下的所有Spring配置文件
        // 2. 初始化Spring容器
        // 3. 暴露所有<dubbo:service>标签定义的服务
        // 4. 注册JVM关闭钩子,确保优雅停机
        Main.main(args);
    }
}
java 复制代码
/**
 * Dubbo Main类启动原理简析
 * 帮助理解Main类的内部工作机制
 */
public class DubboMainPrinciple {
    
    /**
     * Dubbo Main类的核心逻辑简化版
     * 展示其如何自动发现并加载Spring容器
     */
    public static class SimplifiedMain {
        
        private static final String SPRING_CONFIG_LOCATION = 
            "META-INF/spring/";
        
        private final List<SpringContainer> containers = new ArrayList<>();
        
        public void start() {
            // 1. 扫描META-INF/spring/目录下所有xml文件
            List<String> configFiles = scanSpringConfigs(SPRING_CONFIG_LOCATION);
            
            // 2. 为每个配置文件创建Spring容器
            for (String configFile : configFiles) {
                SpringContainer container = new SpringContainer(configFile);
                container.start();
                containers.add(container);
            }
            
            // 3. 注册关闭钩子
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                for (SpringContainer container : containers) {
                    container.stop();
                }
            }));
        }
        
        private List<String> scanSpringConfigs(String location) {
            // 实际实现使用类路径扫描,此处简化
            return Collections.singletonList(
                "META-INF/spring/spring-provider.xml");
        }
    }
    
    static class SpringContainer {
        private final ClassPathXmlApplicationContext context;
        
        SpringContainer(String configLocation) {
            this.context = new ClassPathXmlApplicationContext(configLocation);
        }
        
        void start() { context.start(); }
        void stop() { context.close(); }
    }
}

2. ZooKeeper注册中心集成

直连模式虽然简单,但生产环境必须使用注册中心。ZooKeeper是Dubbo最常用的注册中心。

2.1 ZooKeeper注册中心架构

bash 复制代码
┌─────────────────────────────────────────────────────────┐
│                   ZooKeeper 注册中心                       │
│                                                         │
│  /dubbo                                                │
│  ├── /com.example.dubbo.api.GreetingService            │
│  │   ├── /providers                                    │
│  │   │   ├── dubbo://192.168.1.10:20880/...   [临时节点] │
│  │   │   ├── dubbo://192.168.1.11:20880/...   [临时节点] │
│  │   │   └── dubbo://192.168.1.12:20880/...   [临时节点] │
│  │   ├── /consumers                                    │
│  │   │   └── consumer://192.168.1.20/...      [临时节点] │
│  │   ├── /routers                                      │
│  │   │   └── ...                           [持久节点]   │
│  │   └── /configurators                                │
│  │       └── ...                           [持久节点]   │
│  └── /com.example.dubbo.api.OrderService               │
│      └── ...                                           │
└─────────────────────────────────────────────────────────┘

2.2 Provider配置改造

xml 复制代码
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application name="greeting-provider"/>

    <!-- ========== ZooKeeper注册中心配置 ========== -->
    
    <!-- 方式一:最简配置(单机ZK) -->
    <!-- <dubbo:registry address="zookeeper://127.0.0.1:2181"/> -->
    
    <!-- 方式二:完整协议+地址写法(推荐,语义更清晰) -->
    <dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"/>
    
    <!-- 方式三:ZK集群配置(生产环境推荐) -->
    <!-- <dubbo:registry address="zookeeper://10.0.0.1:2181?backup=10.0.0.2:2181,10.0.0.3:2181"/> -->
    
    <!-- 方式四:集群配置的另一种写法 -->
    <!-- <dubbo:registry protocol="zookeeper" address="10.0.0.1:2181,10.0.0.2:2181,10.0.0.3:2181"/> -->

    <dubbo:protocol name="dubbo" port="20880"/>

    <bean id="greetingService" 
          class="com.example.dubbo.provider.GreetingServiceImpl">
        <constructor-arg value="ZK-Node-01"/>
    </bean>

    <!-- 注意:不再需要url属性,地址由注册中心自动管理 -->
    <dubbo:service interface="com.example.dubbo.api.GreetingService" 
                   ref="greetingService"/>
</beans>

2.3 Consumer配置改造

xml 复制代码
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <dubbo:application name="greeting-consumer"/>

    <!-- 与Provider使用同一个注册中心 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!-- ========== 关键变化 ========== -->
    <!-- 不再指定url属性,Dubbo会自动从注册中心发现Provider地址 -->
    <dubbo:reference id="greetingService"
                     interface="com.example.dubbo.api.GreetingService"/>
</beans>

2.4 日志配置与端口冲突解决

properties 复制代码
# log4j.properties ------ 放置于 src/main/resources
# 通过日志可以观察到Dubbo的内部运行细节

# 控制台输出配置
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%d{HH:mm:ss}] %-5p %c{1}:%L - %m%n

# 根日志级别:info可以看到关键信息,debug可以看到详细调用链
log4j.rootLogger=info,console

# Dubbo核心日志(调试时建议debug级别)
log4j.logger.org.apache.dubbo=info
properties 复制代码
# dubbo.properties ------ 放置于 src/main/resources
# 解决同一台机器上多个Dubbo应用的端口冲突

# QOS(Quality of Service)端口
# 当Provider和Consumer在同一主机时,需为Consumer设置不同的QOS端口
dubbo.application.qos.port=33333
java 复制代码
/**
 * QOS端口冲突解决方案汇总
 */
public class QosPortResolution {
    
    /**
     * 方案一:dubbo.properties文件(推荐)
     * 在classpath下创建dubbo.properties,内容:
     * dubbo.application.qos.port=33333
     */
    
    /**
     * 方案二:Spring XML配置
     * <dubbo:application name="my-app">
     *     <dubbo:parameter key="qos.port" value="33333"/>
     * </dubbo:application>
     */
    
    /**
     * 方案三:JVM启动参数
     * -Ddubbo.application.qos.port=33333
     */
    
    /**
     * 方案四:完全禁用QOS(不推荐,会失去Telnet调试能力)
     * -Ddubbo.application.qos.enable=false
     */
}

3. Web工程集成Dubbo

3.1 Provider Web工程

xml 复制代码
<!-- web.xml ------ 核心配置 -->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    
    <display-name>Dubbo Provider Web</display-name>
    
    <!-- ========== 关键配置:指定Spring配置文件路径 ========== -->
    <!-- 通配符 spring-*.xml 可以加载所有匹配的配置文件 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-*.xml</param-value>
    </context-param>
    
    <!-- ========== Spring根容器监听器 ========== -->
    <!-- ContextLoaderListener 会创建Spring的根WebApplicationContext -->
    <!-- Dubbo的服务暴露正是发生在这个根容器初始化过程中 -->
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    
</web-app>

3.2 Consumer Web工程

java 复制代码
package com.example.dubbo.web.controller;

import com.example.dubbo.api.GreetingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * Spring MVC控制器------调用远程Dubbo服务
 * 
 * 关键点:
 * 1. 使用@Autowired注入远程Dubbo服务代理(就像注入本地Bean一样)
 * 2. Controller不需要感知底层是Dubbo调用还是本地调用
 * 3. 这就是透明化远程调用的价值所在
 */
@Controller
@RequestMapping("/greeting")
public class GreetingController {
    
    /**
     * 注入远程Dubbo服务代理
     * 这个Bean由<dubbo:reference>标签在Spring容器中创建
     */
    @Autowired
    private GreetingService greetingService;
    
    /**
     * GET /greeting/say?name=xxx
     * 前端发起请求 → Controller → Dubbo RPC → Provider → 返回结果
     */
    @GetMapping("/say")
    @ResponseBody
    public Map<String, Object> sayHello(@RequestParam String name) {
        long startTime = System.currentTimeMillis();
        
        // 调用远程服务------对Controller完全透明
        String result = greetingService.sayHello(name);
        
        long elapsed = System.currentTimeMillis() - startTime;
        
        Map<String, Object> response = new HashMap<>();
        response.put("success", true);
        response.put("data", result);
        response.put("elapsedMs", elapsed);
        return response;
    }
    
    /**
     * GET /greeting/version
     * 获取远端服务的版本信息
     */
    @GetMapping("/version")
    @ResponseBody
    public Map<String, Object> getVersion() {
        String version = greetingService.getVersion();
        
        Map<String, Object> response = new HashMap<>();
        response.put("success", true);
        response.put("version", version);
        return response;
    }
}
xml 复制代码
<!-- spring-consumer.xml ------ 整合Spring MVC + Dubbo -->
<?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:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- Dubbo消费者配置 -->
    <dubbo:application name="greeting-consumer-web"/>
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
    <dubbo:reference id="greetingService" 
                     interface="com.example.dubbo.api.GreetingService"/>

    <!-- Spring MVC配置 -->
    <mvc:annotation-driven/>
    <context:component-scan base-package="com.example.dubbo.web.controller"/>
    
</beans>
xml 复制代码
<!-- web.xml ------ 消费者Web工程配置 -->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         version="3.1">
    
    <display-name>Dubbo Consumer Web</display-name>
    
    <!-- 字符编码过滤器 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- Spring MVC中央调度器 -->
    <!-- 注意:DispatcherServlet创建的是子容器,Dubbo的Bean在根容器中 -->
    <!-- 通过contextConfigLocation可以让DispatcherServlet也加载Dubbo配置 -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-*.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
</web-app>

3.3 Root容器与Servlet容器的关系

java 复制代码
/**
 * Spring容器层级关系详解
 * 
 * 在Web环境中,Spring存在两层容器:
 * 1. Root WebApplicationContext(父容器)
 *    - 由 ContextLoaderListener 创建
 *    - 通常管理Service、DAO、Dubbo等业务Bean
 * 
 * 2. Servlet WebApplicationContext(子容器)
 *    - 由 DispatcherServlet 创建
 *    - 通常管理Controller、ViewResolver等Web Bean
 * 
 * 子容器可以访问父容器的Bean,反之则不行
 */
public class SpringContextHierarchy {
    
    /**
     * 容器层级关系示意:
     * 
     * Root WebApplicationContext (父)
     *   ├── greetingService (Dubbo代理)
     *   ├── dataSource
     *   └── transactionManager
     *          │
     *          │ 子容器可以访问父容器的Bean
     *          ▼
     * Servlet WebApplicationContext (子)
     *   ├── greetingController (@Autowired greetingService ✓)
     *   ├── viewResolver
     *   └── handlerMapping
     */
    
    /**
     * 重要结论:
     * 如果Dubbo引用配置在DispatcherServlet的配置文件中(子容器),
     * 那么Controller可以正常注入。
     * 
     * 如果Dubbo引用配置在ContextLoaderListener的配置文件中(父容器),
     * Controller同样可以注入(因为子容器能访问父容器Bean)。
     * 
     * 推荐做法:将Dubbo相关配置放在根容器中,Web配置放在子容器中。
     */
}

4. Dubbo Admin管理控制台

4.1 部署与配置

Dubbo Admin是官方提供的Web管理界面,用于服务治理、路由规则配置、权重调整等操作。

yaml 复制代码
# application.properties ------ Dubbo Admin配置
# 位于 dubbo-admin-server/src/main/resources/

# 服务端口
server.port=8080

# ========== 注册中心配置 ==========
# Dubbo 2.7版本专用配置方式
dubbo.registry.address=zookeeper://127.0.0.1:2181

# ========== 配置中心(可与注册中心共用ZK) ==========
dubbo.config-center.address=zookeeper://127.0.0.1:2181

# ========== 元数据中心 ==========
dubbo.metadata-report.address=zookeeper://127.0.0.1:2181

# ========== 管理员账号 ==========
# 默认账号密码均为 root
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest

4.2 核心功能导航

javascript 复制代码
Dubbo Admin 功能菜单
├── 服务查询
│   ├── 按应用名查询
│   ├── 按服务名查询
│   └── 查看服务提供者/消费者列表
├── 服务治理
│   ├── 路由规则(条件路由)
│   ├── 动态配置(参数覆盖)
│   ├── 权重调整
│   ├── 负载均衡策略切换
│   └── 服务禁用/启用
├── 服务测试
│   ├── 接口方法在线调用
│   └── 参数JSON编辑
├── 服务统计
│   ├── 调用次数统计
│   ├── 平均耗时
│   └── 并发数监控
└── 元数据管理
    ├── 接口元数据查看
    └── 方法签名浏览

4.3 Maven打包与启动

bash 复制代码
# 1. 克隆源码
git clone https://github.com/apache/dubbo-admin.git
cd dubbo-admin

# 2. Maven打包(跳过测试)
mvn clean package -DskipTests

# 3. 找到打包产物
# 位于 dubbo-admin-distribution/target/dubbo-admin-0.1.jar

# 4. 启动(确保ZK已启动)
java -jar dubbo-admin-0.1.jar

# 5. 浏览器访问
# http://localhost:8080
# 默认账号/密码:root/root

本章总结

通过本章的实战演练,你已经掌握了Dubbo从简单到复杂的完整使用链路:

  1. 直连模式:理解Dubbo的基本工作原理------Provider暴露服务,Consumer通过动态代理调用
  2. 注册中心模式:掌握ZK作为注册中心的配置方式,理解临时节点与Watcher机制
  3. Web集成:了解Spring容器层级关系,掌握Dubbo在Web环境中的配置方式
  4. 管理控制台:学会使用Dubbo Admin进行可视化的服务治理

关键要点

  • 服务接口需独立为API模块,Provider和Consumer共同依赖
  • ZK注册中心使用临时节点存储Provider地址,Provider断开后节点自动删除
  • 同一主机运行多个Dubbo应用时需配置不同的QOS端口
相关推荐
日月云棠1 小时前
3 Dubbo 2.7 高级配置:检查控制、版本策略与协议选择
java·后端
砍材农夫1 小时前
物联网 基于netty构建mqtt协议规范(主题通配符订阅)
java·前端·javascript·物联网·netty
掉鱼的猫1 小时前
用 Solon AI 从零构建 MCP 工具服务:让 AI Agent 拥有真实世界的能力
java·llm·mcp
日月云棠1 小时前
1 分布式架构演进与Dubbo框架入门
java·后端
彩票管理中心秘书长1 小时前
智能体状态指示:何时思考、何时调用工具、何时出错
前端·后端·程序员
彩票管理中心秘书长1 小时前
React + TypeScript拆解一整套“AI 变现代码流程”
前端·后端·程序员
ohh61 小时前
从零打通 super-xiaoe:工单自动排查与评论闭环
后端
_日拱一卒1 小时前
LeetCode:114二叉树展开为链表
java·开发语言·算法