dubbo&&zookeeper整合springboot

【一】介绍

Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。如果不想使用Spring配置,也可以通过使用API的方式进行调用(不推荐)。

【二】项目创建

在这里插入图片描述

  • model:数据模型

  • dubbo:需要暴露的接口
    dubbo依赖于model模型

  • provider:服务提供者
    依赖model模块,依赖dubbo模块

  • consumer:服务消费者
    依赖model模块,依赖dubbo模块

【三】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>

	<groupId>com.dubbo</groupId>
	<artifactId>module</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>


	<modules>
		<module>dubbo</module>
		<module>consumer</module>
		<module>provider</module>
		<module>model</module>
	</modules>

	<name>module</name>
	<description>Demo project for Spring Boot</description>

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

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
		</dependency>

		<!-- https://mvnrepository.com/artifact/com.alibaba.boot/dubbo-spring-boot-starter -->
		<dependency>
			<groupId>com.alibaba.boot</groupId>
			<artifactId>dubbo-spring-boot-starter</artifactId>
			<version>0.2.0</version>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.20</version>
			<scope>provided</scope>
		</dependency>

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


		<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-framework -->
		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-framework</artifactId>
			<version>4.0.1</version>
		</dependency>


		<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
		<dependency>
			<groupId>org.apache.zookeeper</groupId>
			<artifactId>zookeeper</artifactId>
			<version>3.4.13</version>
			<type>pom</type>
		</dependency>


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

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


</project>

  • model模块的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">
    <parent>
        <artifactId>module</artifactId>
        <groupId>com.dubbo</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>model</artifactId>


</project>
  • dubbo模块的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>

	<groupId>com.api</groupId>
	<artifactId>dubbo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>dubbo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>com.dubbo</groupId>
		<artifactId>module</artifactId>
		<version>0.0.1-SNAPSHOT</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<dependencies>
		<dependency>
			<groupId>com.dubbo</groupId>
			<artifactId>model</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
	</dependencies>

</project>

  • provider模块的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>

	<groupId>com.provider</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>com.dubbo</groupId>
		<artifactId>module</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>com.api</groupId>
			<artifactId>dubbo</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-framework</artifactId>
			<version>2.8.0</version>
		</dependency>

		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-recipes</artifactId>
			<version>2.8.0</version>
		</dependency>
		
	</dependencies>

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


</project>

  • consumer模块的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>

	<groupId>com.consumer</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>com.dubbo</groupId>
		<artifactId>module</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>com.api</groupId>
			<artifactId>dubbo</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
	</dependencies>

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


</project>

【四】代码实现

4.1 model:

  • User.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain=true)
public class User implements Serializable {
    private Integer id;
    private String username;
    private String password;
}

4.2 dubbo:

  • UserService.java
package com.api.dubbo.service;

import com.feng.model.User;

/**
 * 用户service
 *
 * @author fengwen
 */
public interface UserService {

    /**
     * 登录
     *
     * @param username
     * @param password
     * @return
     */
    User login(String username, String password);

    /**
     * 减少用户拥有数量
     *
     * @param count
     * @return
     */
    String reduce(int count);

    /**
     * 减少用户拥有数量
     *
     * @param count
     * @return
     */
    String reduce(String id, int count);
}

4.3 provider:

  • UserServiceImpl.java
package com.provider.demo.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.api.dubbo.service.UserService;
import com.feng.model.User;
import com.provider.demo.comment.DistributedLock;
import com.provider.demo.comment.RedisLock;
import org.springframework.beans.factory.annotation.Autowired;


/**
 * 用户service实现类
 * @author fengwen
 */
@org.springframework.stereotype.Service
@Service
public class UserServiceImpl implements UserService {

    /**
     * 用于测试分布式锁
     */
    public static int allCount=10;

    /**
     * 基于redis做的分布式锁
     */
    @Autowired
    private RedisLock redisLock;

    /**
     * 用户登录
     * @param username
     * @param password
     * @return
     */
    @Override
    public User login(String username, String password) {
        User user = new User();
        user.setPassword("12345");
        user.setUsername("fengwen");
        user.setId(10);
        return user;
    }

    /**
     * 减少用户拥有数量,这个地方采用的是curator做的分布式锁
     * @param count
     * @return
     */
    @Override
    public String reduce(int count) {
        DistributedLock lock = new DistributedLock("reduce");
        lock.acquireLock();
        if (allCount<count){
            lock.releaseLock();
            return "数量不足";
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        allCount = allCount -count;

        lock.releaseLock();
        return "减少成功";
    }


    /**
     * 减少用户拥有数量,这个地方采用的是redis做的分布式锁
     * @param count
     * @param id
     * @return
     */
    @Override
    public String reduce(String id,int count) {
        //加锁
        long time = System.currentTimeMillis() + 3000 ;
        if(!redisLock.lock(id,String.valueOf(time))){ //如果返回
            return  "并发量太多了,换个姿势再试试!";
        }

        if (allCount<count){
            redisLock.unlock(id,String.valueOf(time));
            return "数量不足";
        }

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        allCount = allCount -count;

        redisLock.unlock(id,String.valueOf(time));
        return "减少成功";
    }
}

  • UserController.java
package com.provider.demo.controller;

import com.api.dubbo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Description
 * @Author fengwen
 * @Date 2020/1/22 17:34
 * @Version V1.0
 */
@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserService userService;

    /**
     * 减少数量,测试分布式锁
     *
     * @param count
     * @return
     */
    @GetMapping("reduce")
    public String reduce(@RequestParam("count") int count) {
        String result = userService.reduce(count);
        return result;
    }

    /**
     * 减少数量,测试分布式锁
     *
     * @param count
     * @return
     */
    @GetMapping("reduce2")
    public String reduce2(@RequestParam("count") int count) {
        String result = userService.reduce(count);
        return result;
    }

    /**
     * 减少数量,测试分布式锁
     *
     * @param count
     * @return
     */
    @GetMapping("reduce3")
    public String reduce3(@RequestParam("id") String id, @RequestParam("count") int count) {
        String result = userService.reduce(id, count);
        return result;
    }

    /**
     * 减少数量,测试分布式锁
     *
     * @param count
     * @return
     */
    @GetMapping("reduce4")
    public String reduce4(@RequestParam("id") String id, @RequestParam("count") int count) {
        String result = userService.reduce(id, count);
        return result;
    }
}

  • DistributedLock.java
package com.provider.demo.comment;


import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author fengwen
 * @Date 2020/1/22 18:12
 * @Version V1.0
 */
public class DistributedLock {
    public static Logger log = LoggerFactory.getLogger(DistributedLock.class);

    //可重入排它锁
    private InterProcessMutex interProcessMutex;
    //竞争资源标志
    private String lockName;
    //根节点
    private String root = "/distributed/lock/";

    private static CuratorFramework curatorFramework;

    private static String ZK_URL = "127.0.0.1:2181";

    static{
        curatorFramework= CuratorFrameworkFactory.newClient(ZK_URL,new ExponentialBackoffRetry(1000,3));
        curatorFramework.start();
    }

    /**
     * 实例化
     * @param lockName
     */
    public DistributedLock(String lockName){
        try {
            this.lockName = lockName;
            interProcessMutex = new InterProcessMutex(curatorFramework, root + lockName);
        }catch (Exception e){
            log.error("initial InterProcessMutex exception="+e);
        }
    }

    /**
     * 获取锁
     */
    public void acquireLock(){
        try {
            //重试2次,每次最大等待2s,也就是最大等待4s
            while (true){
                boolean acquire = interProcessMutex.acquire(2, TimeUnit.SECONDS);
                if (acquire){
                    log.info("Thread:"+Thread.currentThread().getId()+" acquire distributed lock  success");
                    break;
                }
            }
        } catch (Exception e) {
            log.error("distributed lock acquire exception="+e);
        }
    }

    /**
     * 释放锁
     */
    public void releaseLock(){
        try {
            if(interProcessMutex != null && interProcessMutex.isAcquiredInThisProcess()){
                interProcessMutex.release();
                curatorFramework.delete().inBackground().forPath(root+lockName);
                log.info("Thread:"+Thread.currentThread().getId()+" release distributed lock  success");
            }
        }catch (Exception e){
            log.info("Thread:"+Thread.currentThread().getId()+" release distributed lock  exception="+e);
        }
    }
}

  • RedisLock.java
package com.provider.demo.comment;

/**
 * @Description
 * @Author fengwen
 * @Date 2020/1/23 11:37
 * @Version V1.0
 */

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

/**
 * Redis分布式锁
 * @author fengwen
 */
@Component
@Slf4j
public class RedisLock {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 加锁
     * @param key
     * @param value 当前时间+超时时间
     * @return
     */
    public boolean lock(String key, String value) {

        //相当于SETNX指令,setIfAbsent方法设置了返回true,没有设置返回false
        if(redisTemplate.opsForValue().setIfAbsent(key, value)) {
            return true;
        }
        //假设currentValue=A   接下来并发进来的两个线程的value都是B  其中一个线程拿到锁,除非从始至终所有都是在并发(实际上这中情况是不存在的),只要开始时有数据有先后顺序,则分布式锁就不会出现“多卖”的现象
        String currentValue = redisTemplate.opsForValue().get(key);
        //如果锁过期  解决死锁
        if (!StringUtils.isEmpty(currentValue)
                && Long.parseLong(currentValue) < System.currentTimeMillis()) {
            //获取上一个锁的时间,锁过期后,GETSET将原来的锁替换成新锁
            String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
            if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
                return true;
            }
        }
        //拿到锁的就有执行权力,拿不到的只有重新再来,重新再来只得是让用户手动继续抢单
        return false;
    }

    /**
     * 解锁
     * @param key
     * @param value
     */
    public void unlock(String key, String value) {
        try {
            String currentValue = redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e) {
            log.error("【redis分布式锁】解锁异常, {}", e);
        }
    }

}


  • application.yml
spring:
  application:
    name: dubbo-provider
  redis:
    host: 47.105.165.182
    password:
    port: 6379
    database: 0

server:
  port: 8081

dubbo:
  application:
    name: dubbo-provider
  protocol:
    name: dubbo
    port: 20880
  registry:
    address: zookeeper://127.0.0.1:2181
  provider:
    timeout: 5000



zookeeper:
  server: 127.0.0.1:2181
  lockPath: /springboot/



4.4 consumer

  • UserController.java
package com.consumer.demo.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.api.dubbo.service.UserService;
import com.feng.model.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 消费者
 * @author fengwen
 */
@RestController
@RequestMapping(value = "user")
public class UserController {

    @Reference
    private UserService userService;


    @RequestMapping("login")
    public User login(String username,String password) {
        User user = userService.login(username,password);
        return user;
    }
}

【五】链接

发布了130 篇原创文章 · 获赞 88 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/wenge1477/article/details/104076507