zoukankan      html  css  js  c++  java
  • Springboot整合dubbo搭建基本的消费、提供和负载均衡

     

    1.确定接口

    新建一个springboot项目,什么模块都不用选,然后里面新建entity实体类和service接口。
    如下图:

    User.java如下,这里需要注意的是要实现序列化接口。

    public class User implements Serializable{
        private Long id;
    
        private String email;
    
        private String nickName;
    
        private String password;
    
        private String regTime;
    
        private String userName;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email == null ? null : email.trim();
        }
    
        public String getNickName() {
            return nickName;
        }
    
        public void setNickName(String nickName) {
            this.nickName = nickName == null ? null : nickName.trim();
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password == null ? null : password.trim();
        }
    
        public String getRegTime() {
            return regTime;
        }
    
        public void setRegTime(String regTime) {
            this.regTime = regTime == null ? null : regTime.trim();
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName == null ? null : userName.trim();
        }
    }
    

    UserService.java如下:

    public interface UserService {
    
        int deleteByPrimaryKey(Long id);
    
        int insert(User record);
    
        User selectByPrimaryKey(Long id);
    
        List<User> selectAll();
    
        int updateByPrimaryKey(User record);
    
        Map<String, Object> addMethod();
    }
    

    2.创建提供者

    因为要实现负载均衡,这里就需要创建两个提供者。这里使用的是dubbo传统的配置方式:xml。现在dubbo已经支持注解方式,不过个人更偏向于xml配置。
    创建两个Springboot项目:Provider和ProviderB。Provider和ProviderB基本配置和代码都一样,除了一个协议端口不一样。这里就记录Provider的配置方式。

    2.1 pom配置

    因为是用xml方式,在springboot项目里就引入最干净的dubbo依赖库。如果你是用注解的方式,需要引入springboot-dubbo的依赖库,该库在dubbo基础上做了springboot适配。

    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>dubbo</artifactId>
    			<version>2.6.4</version>
    			<exclusions>
    				<exclusion>
    					<groupId>org.springframework</groupId>
    					<artifactId>spring</artifactId>
    				</exclusion>
    			</exclusions>
    		</dependency>
    
    		<dependency>
    			<groupId>org.apache.zookeeper</groupId>
    			<artifactId>zookeeper</artifactId>
    			<version>3.4.12</version>
    		</dependency>
    		<!--<dependency>-->
    			<!--<groupId>com.github.sgroschupf</groupId>-->
    			<!--<artifactId>zkclient</artifactId>-->
    			<!--<version>0.1</version>-->
    		<!--</dependency>-->
    		<dependency>
    			<groupId>org.apache.curator</groupId>
    			<artifactId>curator-recipes</artifactId>
    			<version>4.0.0</version>
    			<exclusions>
    				<exclusion>
    					<groupId>org.apache.zookeeper</groupId>
    					<artifactId>zookeeper</artifactId>
    				</exclusion>
    			</exclusions>
    		</dependency>
    
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    			<scope>runtime</scope>
    		</dependency>
    
    		<dependency>
    			<groupId>org.mybatis.spring.boot</groupId>
    			<artifactId>mybatis-spring-boot-starter</artifactId>
    			<version>1.3.2</version>
    		</dependency>
    
    		<dependency>
    			<groupId>com.alibaba</groupId>
    			<artifactId>druid-spring-boot-starter</artifactId>
    			<version>1.1.10</version>
    		</dependency>
    	</dependencies>
    

    这里不需要使用引入web依赖,因为只提供接口服务。然后需要引入mybatis、mysql模块(这两个在初始化springboot时勾选引入)。再加上dubbo,排除掉它自带的sping库,防止冲突。引入zookeeper库,zookeeper客户端依赖库curator-recipes(排除冲突,去除zookeeper库),再引入druid数据库连接池。

    2.2dubbo配置文件

    通过xml方式配置,在resources下新建一个dubbo文件夹,然后创建两个文件:dubbo.properties和dubbo-provider.xml,如下图:

    dubbo.properties写一些配置参数,

    dubbo.application.name=dubbo-provider
    dubbo.registry.protocol=zookeeper
    dubbo.registry.address1=172.16.30.100:2181
    dubbo.registry.address2=172.16.30.101:2181
    dubbo.registry.address3=172.16.30.101:2181
    dubbo.protocol.name=dubbo
    dubbo.protocol.port=20880
    

    dubbo-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://code.alibabatech.com/schema/dubbo"
           xsi:schemaLocation="http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://code.alibabatech.com/schema/dubbo  
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- 提供方应用信息,用于计算依赖关系 -->
        <dubbo:application name="${dubbo.application.name}"/>
    
        <!-- 注册中心暴露服务地址 -->
        <dubbo:registry protocol="${dubbo.registry.protocol}" address="${dubbo.registry.address1},${dubbo.registry.address2},${dubbo.registry.address3}"/>
    
        <!-- 暴露服务 -->
        <dubbo:protocol name="${dubbo.protocol.name}" port="${dubbo.protocol.port}"/>
    
        <dubbo:service interface="com.steven.xmldubbo.service.UserService"
                       ref="userServiceImpl" retries="0" timeout="6000" loadbalance="random"/>
    </beans>
    

    这里需要配置一个参数loadbalance="random",用来设定负载均衡策略。这里设置是Random,随机的。
    还有其他三种策略,参考官网:http://dubbo.apache.org/zh-cn/docs/user/demos/loadbalance.html

    2.3 application.properties

    这里只要配置数据库访问相关的参数就行。这里也贴一下吧

    spring.datasource.name=datasource
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    #监控统计拦截的filters
    spring.datasource.druid.filters=stat
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=true&useUnicode=true&characterEncoding=utf-8
    spring.datasource.username=root
    spring.datasource.password=root
    #配置初始化大小/最小/最大
    spring.datasource.druid.initial-size=1
    spring.datasource.druid.min-idle=1
    spring.datasource.druid.max-active=20
    #获取连接等待超时时间
    spring.datasource.druid.max-wait=60000
    #间隔多久进行一次检测,检测需要关闭的空闲连接
    spring.datasource.druid.time-between-eviction-runs-millis=60000
    #一个连接在池中最小生存的时间
    spring.datasource.druid.min-evictable-idle-time-millis=300000
    spring.datasource.druid.validation-query=SELECT 1
    spring.datasource.druid.test-while-idle=true
    spring.datasource.druid.test-on-borrow=false
    spring.datasource.druid.test-on-return=false
    #打开PSCache,并指定每个连接上PSCache的大小。oracle设为true,mysql设为false。分库分表较多推荐设置为false
    spring.datasource.druid.pool-prepared-statements=false
    spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
    
    #映射方式 配置下面这个就行了
    #pojo类所在包路径
    mybatis.type-aliases-package=com.steven.xmldubbo.entity
    
    #xml方式
    #xml文件所在路径
    mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
    mybatis.config-location=classpath:mybatis/mybatis-config.xml
    

    2.4 mybatis相关

    2.4.1 配置UserMapper.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.steven.xmldubbo.dao.UserMapper">
      <resultMap id="BaseResultMap" type="com.steven.xmldubbo.entity.User">
        <id column="id" jdbcType="BIGINT" property="id" />
        <result column="email" jdbcType="VARCHAR" property="email" />
        <result column="nick_name" jdbcType="VARCHAR" property="nickName" />
        <result column="password" jdbcType="VARCHAR" property="password" />
        <result column="reg_time" jdbcType="VARCHAR" property="regTime" />
        <result column="user_name" jdbcType="VARCHAR" property="userName" />
      </resultMap>
      <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
        delete from user
        where id = #{id,jdbcType=BIGINT}
      </delete>
      <insert id="insert" parameterType="com.steven.xmldubbo.entity.User">
        insert into user (id, email, nick_name, 
          password, reg_time, user_name
          )
        values (#{id,jdbcType=BIGINT}, #{email,jdbcType=VARCHAR}, #{nickName,jdbcType=VARCHAR}, 
          #{password,jdbcType=VARCHAR}, #{regTime,jdbcType=VARCHAR}, #{userName,jdbcType=VARCHAR}
          )
      </insert>
      <update id="updateByPrimaryKey" parameterType="com.steven.xmldubbo.entity.User">
        update user
        set email = #{email,jdbcType=VARCHAR},
          nick_name = #{nickName,jdbcType=VARCHAR},
          password = #{password,jdbcType=VARCHAR},
          reg_time = #{regTime,jdbcType=VARCHAR},
          user_name = #{userName,jdbcType=VARCHAR}
        where id = #{id,jdbcType=BIGINT}
      </update>
      <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
        select id, email, nick_name, password, reg_time, user_name
        from user
        where id = #{id,jdbcType=BIGINT}
      </select>
      <select id="selectAll" resultMap="BaseResultMap">
        select id, email, nick_name, password, reg_time, user_name
        from user
      </select>
    </mapper>
    
    2.4.2 配置UserMapper接口

    在项目包下创建dao文件夹,然后创建UserMapper.java

    @Repository
    public interface UserMapper {
        int deleteByPrimaryKey(Long id);
    
        int insert(User record);
    
        User selectByPrimaryKey(Long id);
    
        List<User> selectAll();
    
        int updateByPrimaryKey(User record);
    }
    
    2.4.3 实现UserService接口

    包下创建service文件夹,再创建impl文件夹,然后创建UserServiceImpl,实现UserService接口。
    这里需要配置项目Provider依赖Interface,然后就找得到Interface里的UserService了

    @Service
    public class UserServiceImpl implements UserService{
    
        private Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public int deleteByPrimaryKey(Long id) {
            return userMapper.deleteByPrimaryKey(id);
        }
    
        @Override
        public int insert(User record) {
            return userMapper.insert(record);
        }
    
        /**
         * 增加调用方基本信息
         * @param id
         * @return
         */
        @Override
        public User selectByPrimaryKey(Long id) {
            // 本端是否为提供端,这里会返回true
            boolean isProviderSide = RpcContext.getContext().isProviderSide();
            // 获取调用方IP地址
            String clientIp = RpcContext.getContext().getRemoteHost();
            // 获取当前服务配置信息,所有配置信息都将转换为URL的参数
            String url = RpcContext.getContext().getUrl().toFullString();
    
            logger.info("{} {} {}", isProviderSide, clientIp, url);
            return userMapper.selectByPrimaryKey(id);
        }
    
        @Override
        public List<User> selectAll() {
            return userMapper.selectAll();
        }
    
        @Override
        public int updateByPrimaryKey(User record) {
            return userMapper.updateByPrimaryKey(record);
        }
    
        /**
         * 接口新增一个方法测试
         * @return
         */
        @Override
        public Map<String, Object> addMethod() {
            Map<String,Object> result = Maps.newHashMap();
            result.put("attachment", true);
            String count = RpcContext.getContext().getAttachment("count");
            result.put("count", count);
            return result;
        }
    }
    

    2.5 让dubbo配置生效

    在项目包下新建一个config文件夹,创建DubboConfig.java

    /**
     * com.steven.xmldubbo.config
     * Created by ZhiLiSteven
     * Date 2018/10/30
     */
    @Configuration
    @PropertySource("classpath:dubbo/dubbo.properties")
    @ImportResource({"classpath:dubbo/*.xml"})
    public class DubboConfig {
    }
    

    2.6 实现Springboot application

    因为Provider不是web项目,所以启动方式要调整。并且为防止它启动main之后,因为不是以web方式启动,直接退出,需要增加一个阻塞:

    @SpringBootApplication
    @MapperScan("com.steven.xmldubbo.dao")
    public class XmldubboApplication implements CommandLineRunner{
    
    	private Logger logger = LoggerFactory.getLogger(XmldubboApplication.class);
    
    	@Bean
    	public CountDownLatch countDownLatch() {
    		return new CountDownLatch(1);
    	}
    
    	public static void main(String[] args) throws InterruptedException {
    		ApplicationContext ctx = new SpringApplicationBuilder(XmldubboApplication.class)
    				.web(WebApplicationType.NONE)//非web项目
    				.run(args);
    //		SpringApplication.run(XmldubboApplication.class, args);
    
    		CountDownLatch countDownLatch = ctx.getBean(CountDownLatch.class);
    		countDownLatch.await();
    	}
    
    	@Override
    	public void run(String... args) throws Exception {
    		logger.info("Dubbo Provider start now.................");
    	}
    }
    

    至此,提供方搭建完成。
    然后再新建一个ProviderB,其他都一样,唯一区别就是项目名不一样和dubbo.properties一个参数不一样。
    dubbo.protocol.port=20881
    这里ProviderB改成20881
    然后,在接口实现的一个方法里增加一个参数

        /**
         * 接口新增一个方法测试
         * @return
         */
        @Override
        public Map<String, Object> addMethod() {
            Map<String,Object> result = Maps.newHashMap();
            result.put("attachment", true);
            String count = RpcContext.getContext().getAttachment("count");
            result.put("count", count);
            //区别Provider和ProviderB,这里增加一个参数
            result.put("more", "providerB");
            return result;
        }
    

    3.创建消费者

    新建spingboot项目Consume,初始化时,勾选web就可以了。

    3.1 pom依赖

    然后项目依赖dubbo库,zookeeper库,curator-recipes这几个,和Provider一样。

    	<dependencies>
    		<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.alibaba</groupId>
    			<artifactId>dubbo</artifactId>
    			<version>2.6.4</version>
    			<exclusions>
    				<exclusion>
    					<groupId>org.springframework</groupId>
    					<artifactId>spring</artifactId>
    				</exclusion>
    			</exclusions>
    		</dependency>
    
    		<dependency>
    			<groupId>org.apache.zookeeper</groupId>
    			<artifactId>zookeeper</artifactId>
    			<version>3.4.12</version>
    		</dependency>
    		<!--<dependency>-->
    		<!--<groupId>com.github.sgroschupf</groupId>-->
    		<!--<artifactId>zkclient</artifactId>-->
    		<!--<version>0.1</version>-->
    		<!--</dependency>-->
    		<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-recipes -->
    		<dependency>
    			<groupId>org.apache.curator</groupId>
    			<artifactId>curator-recipes</artifactId>
    			<version>4.0.0</version>
    			<exclusions>
    				<exclusion>
    					<groupId>org.apache.zookeeper</groupId>
    					<artifactId>zookeeper</artifactId>
    				</exclusion>
    			</exclusions>
    		</dependency>
    	</dependencies>
    

    项目结构如下图:

    3.2 dubbo配置

    配置和Provider差不多,在resources下新建dubbo文件夹,然后新建dubbo.properties和dubbo-consumer.xml

    3.2.1 dubbo.properties
    dubbo.application.name=dubbo-consumer
    dubbo.registry.protocol=zookeeper
    dubbo.registry.address1=172.16.30.100:2181
    dubbo.registry.address2=172.16.30.101:2181
    dubbo.registry.address3=172.16.30.102:2181
    
    3.2.2 dubbo-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://code.alibabatech.com/schema/dubbo"
           xsi:schemaLocation="http://www.springframework.org/schema/beans  
        http://www.springframework.org/schema/beans/spring-beans.xsd  
        http://code.alibabatech.com/schema/dubbo  
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- 消费方应用信息,用于计算依赖关系 -->
        <dubbo:application name="${dubbo.application.name}"/>
    
        <!-- 注册中心暴露服务地址 -->
        <!-- <dubbo:registry address="multicast://224.5.6.7:1234" /> -->
    
        <dubbo:registry protocol="${dubbo.registry.protocol}" address="${dubbo.registry.address1},${dubbo.registry.address2},${dubbo.registry.address3}"/>
    
        <dubbo:reference interface="com.steven.xmldubbo.service.UserService"
                       id="userService" retries="0" timeout="6000"/>
    </beans>
    
    3.2.3 dubbo配置生效

    项目包下创建config文件夹,创建DubboConfig.java

    /**
     * com.steven.xmldubbo.config
     * Created by ZhiLiSteven
     * Date 2018/10/30
     */
    @Configuration
    @PropertySource("classpath:dubbo/dubbo.properties")
    @ImportResource({"classpath:dubbo/*.xml"})
    public class DubboConfig {
    }
    

    3.3 web创建

    创建一个UserController.java

    /**
     * com.steven.xmldubbo.web
     * Created by ZhiLiSteven
     * Date 2018/10/30
     */
    @RestController
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @GetMapping("user")
        public Map<String, Object> user(String id) {
            Map<String, Object> result = new HashMap<>();
            try {
                result.put("user", userService.selectByPrimaryKey(Long.parseLong(id)));
                result.put("type", "200");
                result.put("content", "success");
            } catch (Exception e) {
                e.printStackTrace();
                result.put("type", "500");
                result.put("content", e.getMessage());
            }
            return result;
        }
    
        @GetMapping("allUsers")
        public Map<String, Object> allUsers() {
            Map<String, Object> result = new HashMap<>();
            try {
                result.put("users", userService.selectAll());
                result.put("type", "200");
                result.put("content", "success");
            } catch (Exception e) {
                e.printStackTrace();
                result.put("type", "500");
                result.put("content", e.getMessage());
            }
            return result;
        }
    
        /**
         * 回声测试
         * @return
         */
        @GetMapping("echoTest")
        public Map<String, Object> echoTest() {
            // 所有服务自动实现 EchoService 接口
            EchoService echoService = (EchoService) userService;
            // 回声测试可用性
            String status = (String) echoService.$echo("OK");
            Map<String, Object> result = Maps.newHashMap();
            result.put("status", status);
            return result;
        }
    
        /**
         * 获取上下文信息
         */
        @GetMapping("rpcContext")
        public Map<String, Object> rpcContext() {
            // 要先请求一次
            userService.selectAll();
            // 本端是否为消费端
            boolean isConsumerSide = RpcContext.getContext().isConsumerSide();
            // 获取最后一次调用的提供方IP地址
            String serverIp = RpcContext.getContext().getRemoteHost();
            // 获取当前服务配置信息,所有配置信息都将转换为URL的参数
            String application = RpcContext.getContext().getUrl().getParameter("application");
    
            Map<String, Object> result = Maps.newHashMap();
            result.put("isConsumerSide", isConsumerSide);
            result.put("serverIp", serverIp);
            result.put("application", application);
    
            return result;
        }
    
        private int count = 0;
        /**
         * 隐式参数
         *
         */
        @GetMapping("attachment")
        public Map<String, Object> attachment() {
            if (++count%2 != 0) {
                // 隐式传参,后面的远程调用都会隐式将这些参数发送到服务器端,类似cookie,用于框架集成,不建议常规业务使用
                RpcContext.getContext().setAttachment("count", count+"");
            }
            return userService.addMethod();
        }
    }
    

    然后application.properties 设定一个端口
    server.port=8882

    至此,消费方也创建好了。

    4.启动测试

    启动两个提供者Provider,ProviderB项目,然后启动Consume项目

    调用http://localhost:8882/allUsers
    {“type”:“200”,“users”:[{“id”:9,“email”:“bb”,“nickName”:“bb123456”,“password”:“bb@126.com”,“regTime”:“2018年10月24日 下午02时03分53秒”,“userName”:“bb2”},{“id”:10,“email”:“cc”,“nickName”:“cc123456”,“password”:“cc@126.com”,“regTime”:“2018年10月24日 下午02时03分53秒”,“userName”:“cc3”},{“id”:11,“email”:“steven@126.com”,“nickName”:“steven”,“password”:“123456”,“regTime”:“2018年10月24日 下午02时06分57秒”,“userName”:“steven”},{“id”:12,“email”:“Liz@126.com”,“nickName”:“Liz”,“password”:“123321”,“regTime”:“2018年10月24日 下午02时06分57秒”,“userName”:“Liz”},{“id”:13,“email”:“HanHan@126.com”,“nickName”:“HanHan”,“password”:“654321”,“regTime”:“2018年10月24日 下午02时06分57秒”,“userName”:“HanHan”},{“id”:15,“email”:“YaoYao@126.com”,“nickName”:“YaoYao”,“password”:“654321”,“regTime”:“2018-01-01”,“userName”:“YaoYao”}],“content”:“success”}

    调用http://localhost:8882/attachment(该接口测试负载均衡)
    分别得到两种类型结果:
    {“attachment”:true,“count”:“1”}

    {“attachment”:true,“more”:“providerB”,“count”:null}

    这两个结果随机出现。

    至此,搭建测试完成!

  • 相关阅读:
    python高阶函数——返回函数(闭包)
    python高阶函数——sorted排序算法
    python高阶函数—filter
    python高阶函数——map/reduce
    Python——高阶函数概念(Higher-order function)
    Python高级特性——迭代器
    Python高级特性——生成器(generator)
    Python高级特性——列表生成式(list Comprehensions)
    Python高级特性——迭代(Iteration)
    Python高级特性——切片(Slice)
  • 原文地址:https://www.cnblogs.com/zyy1688/p/10870051.html
Copyright © 2011-2022 走看看