SpringCloud学习 系列三、 创建一个没有使用springCloud的服务提供者和消费者
系列导航
SpringCloud学习 系列一、 前言-为什么要学习微服务
SpringCloud学习 系列三、 创建一个没有使用springCloud的服务提供者和消费者
SpringCloud学习 系列四、微服务中心 Eureka介绍及创建一个Eureka中心服务
SpringCloud学习 系列五、创建生产者和消费者验证微服务中心 Eureka的作用
SpringCloud学习 系列七、EurekaServer集群创建
SpringCloud学习 系列十、服务熔断与降级(1-简介)
SpringCloud学习 系列十、服务熔断与降级(2-方法级别服务降级)
SpringCloud学习 系列十、服务熔断与降级(3-类级别的服务降级)
SpringCloud学习 系列十、服务熔断与降级(4-Dashboard监控仪表盘)
本系列教程期望达到的效果是,看完之后不仅仅对springCloud能干什么有所了解,更重要的是看完之后就能上手实现这些功能。好多教程写的非常好理论很全面,但是实验部分源码和测试用例不全,或者有跳跃导致读者无法独立完成实验内容,最终只是知道能干什么但是自己却不能实现出来。本系列教程将会逐步将我自己掌握的一些知识点以实验的方式展示给大家,希望大家有所收获,逐步更新中敬请期待。
创建一个没有使用springCloud的服务提供者和消费者
为了阐述为什么要用SpringCloud,本例先创建一个没有使用SpringCloud的消费者和供者的服务,然后分析一下这样的工程有什么不缺点。注:本系列中所有的实例都使用 MySQL 数据库,使用 mybatis-plus 作为持久层技术。
(1)数据库中创建表
CREATE TABLE `block_t` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; 插入实验数据: INSERT INTO `block_t` VALUES ('1', 'oracle'); INSERT INTO `block_t` VALUES ('2', 'mysql'); INSERT INTO `block_t` VALUES ('3', '达梦'); INSERT INTO `block_t` VALUES ('4', '金仓'); INSERT INTO `block_t` VALUES ('5', 'mongo'); INSERT INTO `block_t` VALUES ('6', 'redis');
(2)创建一个空的工程
上图:Jdk选择1.8版本
3)创建一个provider模块(服务提供者)
模块名称:01-provider-8081(该模块非常重要,后面好多工程都要在该基础上进行修改,一定要保证该工程的正确性)
主要提供对表block_t的单条查询和批量查询功能。
上图:创建一个module
上图:随便选一个版本,后面直接修改pom.xml文件改成需要的版本即可。
删除如下这些没有用的文件。
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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.springcloud</groupId> <artifactId>01-provider-8081</artifactId> <version>0.0.1-SNAPSHOT</version> <name>01-provider-8081</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.1.6.RELEASE</spring-boot.version> </properties> <dependencies> <!-- mysql 数据库连接驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.11</version> <scope>runtime</scope> </dependency> <!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1</version> </dependency> <!-- mybatis-plus-generator 代码自动生成--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.3.1</version> </dependency> <!-- 省略get/set等方法 日志打印 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency> <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> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.1.17.RELEASE</version> <configuration> <mainClass>com.springcloud.ApplicationProvider8081</mainClass> </configuration> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
配置文件
package com.springcloud.controller; import com.springcloud.domain.Block; import com.springcloud.service.IBlockService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import javax.validation.constraints.NotNull; import java.util.Map; /** * <p> * 前端控制器。 * </p> * * @author yc * @since 2022-07-15 */ @RestController @RequestMapping("/provider") public class BlockController { @Autowired private IBlockService iBlockService; /** * 单记录新增。 * * @param block 参数说明 * @return AjaxResult */ @PostMapping(value = "/block/add") @ResponseBody public int addSave(@Valid Block block) { return iBlockService.insert(block); } /** * 获取数据列表。 * * @return map */ @GetMapping(value = "/block/list") @ResponseBody public Map list( ) { Map map = iBlockService.selectList(null); return map; } /** * 根据id查询单条数据。 * * @param blockId 参数说明 * @return Block */ @GetMapping(value = "/block/get/{blockId}") @ResponseBody public Block get(@PathVariable("blockId") Integer blockId) { Block block = iBlockService.selectById(blockId); return block; } /** * 修改保存。 * @param block 参数说明 * @return int */ @PostMapping(value = "/block/update/{blockId}") @ResponseBody public int editSave(@PathVariable("blockId")Integer blockId,@Valid Block block){ block.setId(blockId); return iBlockService.edit(block) ; } /** * 根据id删除单条数据。 * * @param blockId 参数说明 * @return int */ @PostMapping(value = "/block/delete/{blockId}") @ResponseBody public int remove( @NotNull(message = "id不能为空!") @PathVariable("blockId") Integer blockId) { return iBlockService.delete(blockId); } }
package com.springcloud.domain; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; /** * <p> * 。 * </p> * * @author yc * @since 2022-07-15 */ @TableName(value = "BLOCK_T") public class Block { private static final long serialVersionUID = 1L; @TableId private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) .append("name", getName()) .toString(); } }
package com.springcloud.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.springcloud.domain.Block; /** * <p> * Mapper 接口。 * </p> * * @author yc * @since 2022-07-15 */ public interface BlockMapper extends BaseMapper<Block> { }
package com.springcloud.service; import com.springcloud.domain.Block; import java.util.Map; /** * <p> * 服务类。 * </p> * * @author yc * @since 2022-07-15 */ public interface IBlockService { /** * 获取数据列表。 * * @param block 参数说明 * @return List */ Map selectList(Block block); /** * 获取单条数据。 * * @param departId 参数说明 * @return Depart */ Block selectById(Integer departId); /** * 单记录新增。 * * @param block 参数说明 * @return status */ int insert(Block block); /** * 修改保存。 * * @param block 参数说明 * @return status */ int edit(Block block); /** * 根据id删除单条数据。 * * @param id 参数说明 * @return status */ int delete(Integer id); }
package com.springcloud.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.springcloud.domain.Block; import com.springcloud.mapper.BlockMapper; import com.springcloud.service.IBlockService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.Map; /** * <p> * 服务实现类。 * </p> * * @author yc * @since 2022-07-15 */ @Service public class BlockServiceImpl implements IBlockService { @Autowired BlockMapper blockMapper; /** * 获取数据列表。 * * @param block 参数说明 * @return List */ @Override public Map selectList(Block block) { Map<String, List> reusltMap = new HashMap<>(); reusltMap.put("dataList", blockMapper.selectList(new QueryWrapper<>(block))); return reusltMap; } /** * 根据id获取单条数据。 * * @param departId 参数说明 * @return Depart */ @Override public Block selectById(Integer departId) { return blockMapper.selectById(departId); } /** * 单记录新增。 * * @param block 参数说明 * @return status */ @Override public int insert(Block block) { return blockMapper.insert(block); } /** * 修改保存。 * * @param block 参数说明 * @return status */ @Override public int edit(Block block) { return blockMapper.updateById(block); } /** * 根据id删除单条数据。 * * @param id 参数说明 * @return status */ @Override public int delete(Integer id) { return blockMapper.deleteById(id); } }
package com.springcloud; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.springcloud.mapper") //这里要注意扫描mapper文件 public class ApplicationProvider8081 { public static void main(String[] args) { SpringApplication.run(ApplicationProvider8081.class, args); } }
(4)创建一个consumer模块(服务使用者)
模块名称:01-consumer-8080(该模块非常重要,后面好多工程都要在该基础上进行修改,一定要保证该工程的正确性)
主要提供调用provider模块中对表block_t的单条查询和批量查询功能的controller。
方法类似上面的步骤不在重复。
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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.springcloud</groupId> <artifactId>01-consumer-8080</artifactId> <version>0.0.1-SNAPSHOT</version> <name>01-consumer-8081</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.1.6.RELEASE</spring-boot.version> </properties> <dependencies> <!-- 省略get/set等方法 日志打印 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency> <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> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.1.17.RELEASE</version> <configuration> <mainClass>com.springcloud.ApplicationConsumer8080</mainClass> </configuration> <executions> <execution> <id>repackage</id> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
配置文件
package com.springcloud.configure; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Controller; import org.springframework.web.client.RestTemplate; @Controller public class BlockCodeConfigure { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
package com.springcloud.controller; import com.springcloud.domain.Block; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import java.util.Map; /** * <p> * 前端控制器。 * </p> * * @author yc * @since 2022-07-15 */ @RestController @RequestMapping("/consumer") public class BlockController { @Autowired private RestTemplate restTemplate; private static final String SERVICE_PROVIDER = "http://localhost:8081"; /** * 获取数据列表。 * * @param block 参数说明 * @return map */ @GetMapping(value = "/block/list") @ResponseBody public Map list(Block block) { String url = SERVICE_PROVIDER + "/provider/block/list"; return restTemplate.getForObject(url, Map.class); } /** * 根据id查询单条数据。 * * @param blockId 参数说明 * @return Block */ @GetMapping(value = "/block/get/{blockId}") @ResponseBody public Block get(@PathVariable("blockId") Integer blockId) { String url = SERVICE_PROVIDER + "/provider/block/get/"+blockId; return restTemplate.getForObject(url, Block.class); } }
package com.springcloud.domain; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; /** * <p> * 。 * </p> * * @author yc * @since 2022-07-15 */ public class Block { private static final long serialVersionUID = 1L; private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) .append("name", getName()) .toString(); } }
package com.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ApplicationConsumer8080 { public static void main(String[] args) { SpringApplication.run(ApplicationConsumer8080.class, args); } }
删除如下这些没用的文件
(5) 效果展示
<1>直接调用01-provider-8081工程中的接口(只看单条查询的接口)
<2>调用01-consumer-8080中的接口,01-consumer-8080中的接口在调用01-provider-8081工程中的接口(只看单条查询的接口)
6、这种服务存在的问题
(1)01-consumer-8080中直接调用服务者的服务,只能写一个服务者的地址,01-provider-8081挂了就没有服务了。
(2)调用服务提供者使用的是ip而不是服务名,如果服务提供者更换了主机,服务调用者也得修改代码。
(3)如果有很多consumer,服务提供者provider的压力无法分担容易出现性能瓶颈。
如何解决这个问题就要进入下一章“微服务中心 Eureka”