服务提供者与服务消费者
生活随笔
收集整理的這篇文章主要介紹了
服务提供者与服务消费者
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
服務提供者和服務消費者,名詞非常的高大上,但是其實很簡單,我們看什么是服務提供者,什么是服務消費者,服務的被調用方是服務的提供者,服務的調用方是消費者,以我們之前的電影系統為例,一個用戶發起了購票的請求,發現滿足要求了,去查當前用戶的信息,然后在這種場景下,電影微服務就是一個服務消費者,用戶微服務就是一個服務提供者,用戶微服務提供的一個接口被他消費了,是這個意思
編寫一個服務提供者,然后再編寫一個簡單的消費者,還是以電影銷售系統為例,我們來模擬這種情況,發起一個遠程的調用,首先我們寫一個服務提供者,我們先寫服務提供者,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 {@Autowiredprivate 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 mapperPUBLIC "-//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=/boot02spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=truelogging.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:/learnspring.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=60000mybatis.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 iptablessudo aztech aztechsudo iptables -I INPUT -p tcp --dport 7900 -j ACCEPTsudo iptables-save10.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=7901user.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 {@Autowiredprivate 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 {@Beanpublic 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,那這個也是非常的難管理,那怎么去解決目前的這種問題呢
?
總結
以上是生活随笔為你收集整理的服务提供者与服务消费者的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开始使用Spring Cloud实战微服
- 下一篇: mysql日期/时间转换为字符串