springboot 2.1.3整合dubbo 2.7.0和zookeeper 3.4.13,都是目前最新的版本

      闲暇之余,自己想搞个springboot的框架,整合dubbo时发现网上的帖子,springboot和dubbo都是比较老的版本,使用新版本创建的项目按照网上的整合老是报错,无奈之下直接去apache官网看文档说明,因为现在dubbo已入住apache旗下,所以本次整合使用apache发布的dubbo版本,下面将我使用springboot新版本整合dubbo的过程记录如下:

apacheDubbo的官网:https://github.com/apache/incubator-dubbo-spring-boot-project

1、要想富,先修路,要想整合zookeeper,首先我们需要安装zookeeper。可以参见:https://blog.csdn.net/weixin_42315600/article/details/88652654,在此不再啰嗦。

2、为了方便观察zookeeper中服务注册情况,我们可以下载一个zookeeper可视化界面工具,参见大牛的博客:

https://blog.csdn.net/u010889616/article/details/80792912

3、接下来就是重点了,springboot使用zookeeper方式整合dubbo

(1)关于springboot多模块项目的创建,我就不多说了,可以参见:springboot 2.1.3不使用zookeeper,使用直连方式整合dubbo 2.7.0的帖子:https://blog.csdn.net/weixin_42315600/article/details/88609622

(2)添加pom依赖,为了演示方便我这只在父项目中添加了依赖,provider和consumer子项目中不添加任何maven依赖,直接继承父项目,如下是我示例中父项目完成pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<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>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <packaging>pom</packaging> <!--修改父项目为POM-->

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <!--项目模块-->
    <modules>
        <module>demo-provider</module>
        <module>demo-iprovider</module>
        <module>demo-consumer</module>
    </modules>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--接口模块依赖-->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>demo-iprovider</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!--整合dubbo-->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.7.0</version>
        </dependency>
        <!-- Zookeeper -->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>4.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>4.2.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

(3)修改demo-provider项目application.properties文件

# demo-consumer配置文件

#端口配置
server.port=8080

## Dubbo 服务提供者配置
# provider应用名称
spring.application.name=demo-provider
# Dubbo组件扫描的基础包
dubbo.scan.base-packages=com.example.demoprovider
# Dubbo应用程序名称,的默认值是$ {spring.application.name}
## dubbo.application.name=${spring.application.name}
# Dubbo 协议与端口
dubbo.protocol.name=dubbo
dubbo.protocol.port=12345
## Dubbo 注册地址 N/A表示直连方式
#dubbo.registry.address=N/A
embedded.zookeeper.port = 2181
dubbo.registry.address=zookeeper://127.0.0.1:${embedded.zookeeper.port}

(4)在demo-provider启动程序所在包下,添加zookeeper工具类:EmbeddedZooKeeper,这个类是官方示例中提供。

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.demoprovider;

import org.apache.zookeeper.server.ServerConfig;
import org.apache.zookeeper.server.ZooKeeperServerMain;
import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.util.ErrorHandler;
import org.springframework.util.SocketUtils;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.UUID;

/**
 * from: https://github.com/spring-projects/spring-xd/blob/v1.3.1.RELEASE/spring-xd-dirt/src/main/java/org/springframework/xd/dirt/zookeeper/ZooKeeperUtils.java
 * <p>
 * Helper class to start an embedded instance of standalone (non clustered) ZooKeeper.
 * <p>
 * NOTE: at least an external standalone server (if not an ensemble) are recommended, even for
 * org.springframework.xd.dirt.server.singlenode.SingleNodeApplication
 *
 * @author Patrick Peralta
 * @author Mark Fisher
 * @author David Turanski
 */
public class EmbeddedZooKeeper implements SmartLifecycle {

    /**
     * Logger.
     */
    private static final Logger logger = LoggerFactory.getLogger(EmbeddedZooKeeper.class);

    /**
     * ZooKeeper client port. This will be determined dynamically upon startup.
     */
    private final int clientPort;

    /**
     * Whether to auto-start. Default is true.
     */
    private boolean autoStartup = true;

    /**
     * Lifecycle phase. Default is 0.
     */
    private int phase = 0;

    /**
     * Thread for running the ZooKeeper server.
     */
    private volatile Thread zkServerThread;

    /**
     * ZooKeeper server.
     */
    private volatile ZooKeeperServerMain zkServer;

    /**
     * {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread.
     */
    private ErrorHandler errorHandler;

    private boolean daemon = true;

    /**
     * Construct an EmbeddedZooKeeper with a random port.
     */
    public EmbeddedZooKeeper() {
        clientPort = SocketUtils.findAvailableTcpPort();
    }

    /**
     * Construct an EmbeddedZooKeeper with the provided port.
     *
     * @param clientPort port for ZooKeeper server to bind to
     */
    public EmbeddedZooKeeper(int clientPort, boolean daemon) {
        this.clientPort = clientPort;
        this.daemon = daemon;
    }

    /**
     * Returns the port that clients should use to connect to this embedded server.
     *
     * @return dynamically determined client port
     */
    public int getClientPort() {
        return this.clientPort;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isAutoStartup() {
        return this.autoStartup;
    }

    /**
     * Specify whether to start automatically. Default is true.
     *
     * @param autoStartup whether to start automatically
     */
    public void setAutoStartup(boolean autoStartup) {
        this.autoStartup = autoStartup;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getPhase() {
        return this.phase;
    }

    /**
     * Specify the lifecycle phase for the embedded server.
     *
     * @param phase the lifecycle phase
     */
    public void setPhase(int phase) {
        this.phase = phase;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isRunning() {
        return (zkServerThread != null);
    }

    /**
     * Start the ZooKeeper server in a background thread.
     * <p>
     * Register an error handler via {@link #setErrorHandler} in order to handle
     * any exceptions thrown during startup or execution.
     */
    @Override
    public synchronized void start() {
        if (zkServerThread == null) {
            zkServerThread = new Thread(new ServerRunnable(), "ZooKeeper Server Starter");
            zkServerThread.setDaemon(daemon);
            zkServerThread.start();
        }
    }

    /**
     * Shutdown the ZooKeeper server.
     */
    @Override
    public synchronized void stop() {
        if (zkServerThread != null) {
            // The shutdown method is protected...thus this hack to invoke it.
            // This will log an exception on shutdown; see
            // https://issues.apache.org/jira/browse/ZOOKEEPER-1873 for details.
            try {
                Method shutdown = ZooKeeperServerMain.class.getDeclaredMethod("shutdown");
                shutdown.setAccessible(true);
                shutdown.invoke(zkServer);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

            // It is expected that the thread will exit after
            // the server is shutdown; this will block until
            // the shutdown is complete.
            try {
                zkServerThread.join(5000);
                zkServerThread = null;
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                logger.warn("Interrupted while waiting for embedded ZooKeeper to exit");
                // abandoning zk thread
                zkServerThread = null;
            }
        }
    }

    /**
     * Stop the server if running and invoke the callback when complete.
     */
    @Override
    public void stop(Runnable callback) {
        stop();
        callback.run();
    }

    /**
     * Provide an {@link ErrorHandler} to be invoked if an Exception is thrown from the ZooKeeper server thread. If none
     * is provided, only error-level logging will occur.
     *
     * @param errorHandler the {@link ErrorHandler} to be invoked
     */
    public void setErrorHandler(ErrorHandler errorHandler) {
        this.errorHandler = errorHandler;
    }

    /**
     * Runnable implementation that starts the ZooKeeper server.
     */
    private class ServerRunnable implements Runnable {

        @Override
        public void run() {
            try {
                Properties properties = new Properties();
                File file = new File(System.getProperty("java.io.tmpdir")
                        + File.separator + UUID.randomUUID());
                file.deleteOnExit();
                properties.setProperty("dataDir", file.getAbsolutePath());
                properties.setProperty("clientPort", String.valueOf(clientPort));

                QuorumPeerConfig quorumPeerConfig = new QuorumPeerConfig();
                quorumPeerConfig.parseProperties(properties);

                zkServer = new ZooKeeperServerMain();
                ServerConfig configuration = new ServerConfig();
                configuration.readFrom(quorumPeerConfig);

                zkServer.runFromConfig(configuration);
            } catch (Exception e) {
                if (errorHandler != null) {
                    errorHandler.handleError(e);
                } else {
                    logger.error("Exception running embedded ZooKeeper", e);
                }
            }
        }
    }
}

(5)在修改demo-provider启动程序如下:

package com.example.demoprovider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.Environment;

@SpringBootApplication
public class DemoProviderApplication {

    public static void main(String[] args) {
//        SpringApplication.run(DemoProviderApplication.class, args);
        new SpringApplicationBuilder(DemoProviderApplication.class)
                .listeners((ApplicationListener<ApplicationEnvironmentPreparedEvent>) event -> {
                    Environment environment = event.getEnvironment();
                    int port = environment.getProperty("embedded.zookeeper.port", int.class);
                    new EmbeddedZooKeeper(port, false).start();
                }).run(args);
    }
}

(6)demo-provider服务提供者接口代码:

package com.example.demoprovider;

import com.example.demoiprovider.UserInfoISV;
import org.apache.dubbo.config.annotation.Service;

@Service(version = "1.0.0")
public class UserInfoSV implements UserInfoISV {
    @Override
    public String sayHello() {
        System.out.println("******demoprovider被访问******");
        return "Hello World!";
    }
}

(7)接下来开始配置demo-consumer项目:pom.xml中依赖直接继承父项目,application.properties配置文件修改如下:

# demo-provider配置文件

#端口配置,为防止端口冲突,该模块端口使用18080
server.port=18080

#dubbo 消费者配置
# 应用名称,配置模块项目名称即可
spring.application.name=demo-provider
## Dubbo 注册地址 N/A表示直连方式
#dubbo.registry.address=N/A
embedded.zookeeper.port = 2181
dubbo.registry.address=zookeeper://127.0.0.1:${embedded.zookeeper.port}

(8)demo-consumer服务消费者接口代码:

package com.example.democonsumer;

import com.example.demoiprovider.UserInfoISV;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserInfoController {
    private static final Logger logger = LoggerFactory.getLogger(UserInfoController.class);

    //但是version一定要指定 不然会找不到服务 直连需要加url="dubbo://localhost:12345",端口号和配置文件中保持一致
    @Reference(version = "1.0.0")
    private UserInfoISV userInfoISV;

    @GetMapping("/hello")
    public void sayHello (){
        System.out.println("******democonsumer被访问******");
        System.out.println(userInfoISV.sayHello());
    }
}

(9)至此我们就整合完成了,接下来我们运行一下项目看下日志情况(先运行demo-provider,再运行demo-consumer)。

(10)此时我们可通过zookeeper可视化工具,看下zookeeper服务的情况。此时你会发现demo项目的服务上已经显示了provider和consumer的使用情况。

猜你喜欢

转载自blog.csdn.net/weixin_42315600/article/details/88631796