大家好,欢迎来到IT知识分享网。
服务提供者和服务消费者,名词非常的高大上,但是其实很简单,我们看什么是服务提供者,什么是服务消费者, 服务的被调用方是服务的提供者,服务的调用方是消费者,以我们之前的电影系统为例,一个用户发起了购票的 请求,发现满足要求了,去查当前用户的信息,然后在这种场景下,电影微服务就是一个服务消费者,用户微服务 就是一个服务提供者,用户微服务提供的一个接口被他消费了,是这个意思
编写一个服务提供者,然后再编写一个简单的消费者,还是以电影销售系统为例,我们来模拟这种情况, 发起一个远程的调用,首先我们写一个服务提供者,我们先写服务提供者,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= 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,那这个也是非常的难管理,那怎么去解决目前的这种问题呢
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/127731.html