服务提供者与服务消费者

服务提供者和服务消费者,名词非常的高大上,但是其实很简单,我们看什么是服务提供者,什么是服务消费者,

服务的被调用方是服务的提供者,服务的调用方是消费者,以我们之前的电影系统为例,一个用户发起了购票的

请求,发现满足要求了,去查当前用户的信息,然后在这种场景下,电影微服务就是一个服务消费者,用户微服务

就是一个服务提供者,用户微服务提供的一个接口被他消费了,是这个意思

编写一个服务提供者,然后再编写一个简单的消费者,还是以电影销售系统为例,我们来模拟这种情况,

发起一个远程的调用,首先我们写一个服务提供者,我们先写服务提供者,microservice-simple-provider-user,

国内阿里云的镜像,这样下载会比较快,他的parent是spring-boot-starter-parent,首先我们写一些建表语句,

drop table user;
create table user(
	id bigint generated by default as identity,
	username varchar(40),
	name varchar(20),
	age int(3),
	balance decimal(10,2), 
	primary key(id)
);

balance是余额

插入一些数据

insert into user(id,username, name, age, balance) values(1,'user1', '张三', 20, 100.00);
insert into user(id,username, name, age, balance) values(2,'user2', '李四', 20, 100.00);
insert into user(id,username, name, age, balance) values(3,'user3', '王五', 20, 100.00);
insert into user(id,username, name, age, balance) values(4,'user4', '马六', 20, 100.00);

@GetMapping它是一个组合注解,它是在Spring4.3以后支持的,同样还有PostMapping,PutMapping,DeleteMapping,

GetMapping他其实相当于RequestMapping,RequestMethod的Get的混合注解,

/**
 * Annotation for mapping HTTP {@code GET} requests onto specific handler
 * methods.
 *
 * <p>Specifically, {@code @GetMapping} is a <em>composed annotation</em> that
 * acts as a shortcut for {@code @RequestMapping(method = RequestMethod.GET)}.
 *
 *
 * @author Sam Brannen
 * @since 4.3
 * @see PostMapping
 * @see PutMapping
 * @see DeleteMapping
 * @see PatchMapping
 * @see RequestMapping
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {

@RestController其实也是一个混合注解,相当于加了ResonseBody和Controller,

/**
 * A convenience annotation that is itself annotated with
 * {@link Controller @Controller} and {@link ResponseBody @ResponseBody}.
 * <p>
 * Types that carry this annotation are treated as controllers where
 * {@link RequestMapping @RequestMapping} methods assume
 * {@link ResponseBody @ResponseBody} semantics by default.
 *
 * <p><b>NOTE:</b> {@code @RestController} is processed if an appropriate
 * {@code HandlerMapping}-{@code HandlerAdapter} pair is configured such as the
 * {@code RequestMappingHandlerMapping}-{@code RequestMappingHandlerAdapter}
 * pair which are the default in the MVC Java config and the MVC namespace.
 * In particular {@code @RestController} is not supported with the
 * {@code DefaultAnnotationHandlerMapping}-{@code AnnotationMethodHandlerAdapter}
 * pair both of which are also deprecated.
 *
 * @author Rossen Stoyanchev
 * @author Sam Brannen
 * @since 4.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {
<?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.learn</groupId>
	<artifactId>microservice-simple-provider-user</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.12.RELEASE</version>
		<relativePath/> 
	</parent>
	
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
		<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
	</properties>
	
	<dependencies>
		<dependency>
			<!-- 引入web模块 -->
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- Spring Boot进行单元测试的模块 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>	
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!-- 引入druid数据源 -->
		<dependency>
		    <groupId>com.alibaba</groupId>
		    <artifactId>druid</artifactId>
		    <version>1.1.8</version>
		</dependency>
		<dependency>  
		    <groupId>org.mybatis.spring.boot</groupId>  
		    <artifactId>mybatis-spring-boot-starter</artifactId>  
		    <version>1.3.2</version>  
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
	</dependencies>
	
	<!-- 这个插件,可以将应用打包成一个可执行的jar包 -->
	<build>
	    <plugins>
	        <plugin>
	            <groupId>org.springframework.boot</groupId>
	            <artifactId>spring-boot-maven-plugin</artifactId>
	        </plugin>
	    </plugins>
	</build>
  
  
</project>
package com.learn.cloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.learn.cloud.entity.User;
import com.learn.cloud.mapper.UserMapper;

@RestController
public class UserController {

  @Autowired
  private UserMapper userMapper;

  @GetMapping("/simple/{id}")
  public User findById(@PathVariable Long id) {
    return this.userMapper.getUserById(id);
  }
  
}
package com.learn.cloud.mapper;

import org.apache.ibatis.annotations.Mapper;

import com.learn.cloud.entity.User;

//@Mapper或者@MapperScan将接口扫描装配到容器中
@Mapper
public interface UserMapper {

	public User getUserById(Long id);
}
<?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.learn.cloud.mapper.UserMapper">

  <select id="getUserById" resultType="com.learn.cloud.entity.User">
    select * from user where id = #{id}
  </select>
  
</mapper>
package com.learn.cloud.entity;

import java.math.BigDecimal;

public class User {
	
  private Long id;

  private String username;

  private String name;

  private Short age;

  private BigDecimal balance;

  public Long getId() {
    return this.id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getUsername() {
    return this.username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Short getAge() {
    return this.age;
  }

  public void setAge(Short age) {
    this.age = age;
  }

  public BigDecimal getBalance() {
    return this.balance;
  }

  public void setBalance(BigDecimal balance) {
    this.balance = balance;
  }
}
package com.learn.cloud;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan(value="com.learn.cloud.mapper")
@SpringBootApplication
public class MicroserviceSimpleProviderUserApplication {

	public static void main(String[] args) {
		SpringApplication.run(MicroserviceSimpleProviderUserApplication.class, args);
	}
}
#debug=true
server.port=7900

#server.context-path=/boot02

spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true

logging.level.com.learn=trace
#logging.file=D:/springboot.log
logging.file=springboot.log
#logging.path=/spring/log
logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
logging.pattern.file=%d{yyyy-MM-dd} ==== [%thread] %-5level ==== %logger{50} ==== %msg%n
#spring.resources.static-locations=classpath:/hello,classpath:/learn

spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://59.110.158.145:3306/SpringCloud?useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
spring.datasource.maxWait=60000

mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

http://localhost:7900/simple/1

{"id":1,"username":"user1","name":"张三","age":20,"balance":100.00}
我们发现是可以正常访问的,这样一个非常简单的用户微服务我们已经写完了

DROP DATABASE IF EXISTS SpringCloud;
create database SpringCloud;
use SpringCloud;

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL,
  `username` varchar(40) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL,
  `age` int(3) DEFAULT NULL,
  `balance` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into user(id,username,name,age,balance) values(1,'user1','张三',20,100);

insert into user(id,username,name,age,balance) values(2,'user2','李四',20,100);

现在我们写一下服务消费者,也就是这边的movie项目,我们让他比较简单的去调用这个user,这个微服务,

nohup java -jar microservice-simple-provider-user-0.0.1-SNAPSHOT.jar &

sudo apt-get install iptables

sudo aztech aztech

sudo iptables -I INPUT -p tcp --dport 7900 -j ACCEPT

sudo iptables-save

10.40.8.152:7900/simple/1

微服务服务之间是有自治的,所以我们启动movie也是OK的,即使User没有启动好,启动user也是OK的,

restTemplate有问题,因为我们没有new,我们在启动类上加一点小小的配置

@Bean
public RestTemplate restTemplate() {
	return new RestTemplate();
}

@Bean会把实例化的RestTemplate以方法名去命名,他的名称是restTemplate,启动7901,也就是movie这个微服务

localhost:7901/movie/1
<?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.learn</groupId>
	<artifactId>microservice-simple-consumer-movie</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>microservice-simple-consumer-movie</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.12.RELEASE</version>
		<relativePath/> 
	</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-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>
#debug=true
server.port=7901

user.userServicePath: http://10.40.8.152:7900/simple/

package com.learn.cloud.entity;

import java.math.BigDecimal;

public class User {
  private Long id;

  private String username;

  private String name;

  private Short age;

  private BigDecimal balance;

  public Long getId() {
    return this.id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getUsername() {
    return this.username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getName() {
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Short getAge() {
    return this.age;
  }

  public void setAge(Short age) {
    this.age = age;
  }

  public BigDecimal getBalance() {
    return this.balance;
  }

  public void setBalance(BigDecimal balance) {
    this.balance = balance;
  }

}
package com.learn.cloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.learn.cloud.entity.User;

@RestController
public class MovieController {
  @Autowired
  private RestTemplate restTemplate;

  @Value("${user.userServicePath}")
  private String userServicePath;

  @GetMapping("/movie/{id}")
  public User findById(@PathVariable Long id) {
    return this.restTemplate.getForObject(this.userServicePath + id, User.class);
  }
}
package com.learn.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class MicroserviceSimpleConsumerMovieApplication {

  @Bean
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }

  public static void main(String[] args) {
    SpringApplication.run(MicroserviceSimpleConsumerMovieApplication.class, args);
  }
}
是可以正常请求到user服务的,是可以用到user服务的接口的,同时写了一个服务消费者,我们总结一下需要注意点,

首先是服务提供者,第一个是@GetMapping,它是一个组合注解,是Spring4.3给我们提供的一个注解,yml是有严格的

缩进的,可以是两个空格缩进,也可以是四个空格缩进,然后回到movie这个项目,@Bean注解,我们用方法名称,作为

实例化后的Bean的名称

@Bean
public RestTemplate restTemplate() {
	return new RestTemplate();
}
  
相当于RestTemplate restTemplate = new RestTemplate();

目前这个架构其实是存在很多问题的,我现在是在消费的这一侧,把这个硬编码了,在传统的一些项目里面,大概没有太多

的问题了,因为这些环境都是比较固定的,IP端口都是比较固定的,但是在现在这种新式的环境下,就不一样了,比如说docker,

在一些云环境里面,IP和端口往往是动态的,当我把provider-user部署好了之后,他的IP和端口往往是动态的,那这个时候我们

怎么去进行一个配置呢,加上我provider重新的进行上限,他的IP进行了变更,那这边怎么样去玩呢,所以硬编码是行不通的,

但是即使这样也不行

@Value("${user.userServicePath}")
private String userServicePath;

user.userServicePath: http://10.40.8.152:7900/simple/

当然变得好维护了一些,当他的IP和端口发生了变化的时候,我这边也要重新的配置,重新的启动,当他又为其它的服务提供服务,

那别的服务是不是也得改配置,这种维护量是很大的,这是第一个问题,第二个问题,movie微服务调用user微服务,当然它是提供者,

现在这种情况是直接调,但是他有一定的问题,当我有多个提供的节点的时候,我怎么做到负载,中间加Nginx,由Nginx完成转发,

但是我们要知道,在一个复杂的项目里面,几百个微服务,甚至上万个,这都是有可能的,像亚马逊光首页,700个微服务,那是不是只要

有服务调用的时候,就加个nginx,那这个也是非常的难管理,那怎么去解决目前的这种问题呢

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值